]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linville' of git://github.com/kvalo/ath6kl
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 13 Jun 2013 17:33:39 +0000 (13:33 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 13 Jun 2013 17:33:39 +0000 (13:33 -0400)
200 files changed:
Documentation/DocBook/80211.tmpl
drivers/bcma/Kconfig
drivers/bcma/scan.c
drivers/bluetooth/Kconfig
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btusb.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/htc.h
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/init.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/wow.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/ath/wil6210/Kconfig
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/main.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fweh.c
drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/cw1200/Kconfig
drivers/net/wireless/cw1200/Makefile
drivers/net/wireless/cw1200/bh.c
drivers/net/wireless/cw1200/cw1200.h
drivers/net/wireless/cw1200/cw1200_sagrad.c [deleted file]
drivers/net/wireless/cw1200/cw1200_sdio.c
drivers/net/wireless/cw1200/cw1200_spi.c
drivers/net/wireless/cw1200/debug.c
drivers/net/wireless/cw1200/debug.h
drivers/net/wireless/cw1200/fwio.c
drivers/net/wireless/cw1200/hwbus.h [new file with mode: 0644]
drivers/net/wireless/cw1200/hwio.c
drivers/net/wireless/cw1200/hwio.h
drivers/net/wireless/cw1200/itp.c [deleted file]
drivers/net/wireless/cw1200/itp.h [deleted file]
drivers/net/wireless/cw1200/main.c
drivers/net/wireless/cw1200/pm.c
drivers/net/wireless/cw1200/sbus.h [deleted file]
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/cw1200/txrx.c
drivers/net/wireless/cw1200/wsm.c
drivers/net/wireless/cw1200/wsm.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-phy-db.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.h
drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wl12xx/scan.c
drivers/net/wireless/ti/wl12xx/wl12xx.h
drivers/net/wireless/ti/wl18xx/scan.c
drivers/net/wireless/ti/wlcore/main.c
drivers/nfc/Kconfig
drivers/nfc/mei_phy.c
drivers/nfc/microread/mei.c
drivers/nfc/pn544/mei.c
include/linux/bcma/bcma.h
include/linux/cw1200_platform.h [deleted file]
include/linux/ieee80211.h
include/linux/platform_data/net-cw1200.h [new file with mode: 0644]
include/net/bluetooth/hci_core.h
include/net/bluetooth/mgmt.h
include/net/cfg80211.h
include/net/mac80211.h
include/uapi/linux/nl80211.h
net/bluetooth/hci_core.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/mac80211/cfg.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/nfc/Makefile
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/sme.c
net/wireless/trace.h
net/wireless/wext-sme.c

index ebe89694cf81d46c016ce663571a0b0dcd62bd88..49267ea975684391c1f1e7144fb0c88700557d66 100644 (file)
 !Finclude/net/cfg80211.h cfg80211_ibss_params
 !Finclude/net/cfg80211.h cfg80211_connect_params
 !Finclude/net/cfg80211.h cfg80211_pmksa
-!Finclude/net/cfg80211.h cfg80211_send_rx_auth
-!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
-!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
-!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
-!Finclude/net/cfg80211.h cfg80211_send_deauth
-!Finclude/net/cfg80211.h cfg80211_send_disassoc
+!Finclude/net/cfg80211.h cfg80211_rx_mlme_mgmt
+!Finclude/net/cfg80211.h cfg80211_auth_timeout
+!Finclude/net/cfg80211.h cfg80211_rx_assoc_resp
+!Finclude/net/cfg80211.h cfg80211_assoc_timeout
+!Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt
 !Finclude/net/cfg80211.h cfg80211_ibss_joined
 !Finclude/net/cfg80211.h cfg80211_connect_result
 !Finclude/net/cfg80211.h cfg80211_roamed
index 8b4221cfd118bdb390fea9fa5e6bbfdfe37060f7..380a2003231e4c56984207dd7f2658bd9bcc3166 100644 (file)
@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE
 config BCMA_HOST_PCI
        bool "Support for BCMA on PCI-host bus"
        depends on BCMA_HOST_PCI_POSSIBLE
+       default y
 
 config BCMA_DRIVER_PCI_HOSTMODE
        bool "Driver for PCI core working in hostmode"
index bca9c80056febb4f90215534ca67d6adbf0aee80..8bffa5c9818c8e598a7f1408bd56a511f5773f29 100644 (file)
@@ -84,6 +84,8 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
        { BCMA_CORE_I2S, "I2S" },
        { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
        { BCMA_CORE_SHIM, "SHIM" },
+       { BCMA_CORE_PCIE2, "PCIe Gen2" },
+       { BCMA_CORE_ARM_CR4, "ARM CR4" },
        { BCMA_CORE_DEFAULT, "Default" },
 };
 
index fdfd61a2d5237d0d3b977c858be1cfdeef37bcf0..11a6104a1e4fc1802fbdd57b5024f3de69c43222 100644 (file)
@@ -201,7 +201,7 @@ config BT_MRVL
          The core driver to support Marvell Bluetooth devices.
 
          This driver is required if you want to support
-         Marvell Bluetooth devices, such as 8688/8787/8797.
+         Marvell Bluetooth devices, such as 8688/8787/8797/8897.
 
          Say Y here to compile Marvell Bluetooth driver
          into the kernel or say M to compile it as module.
@@ -214,7 +214,7 @@ config BT_MRVL_SDIO
          The driver for Marvell Bluetooth chipsets with SDIO interface.
 
          This driver is required if you want to use Marvell Bluetooth
-         devices with SDIO interface. Currently SD8688/SD8787/SD8797
+         devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897
          chipsets are supported.
 
          Say Y here to compile support for Marvell BT-over-SDIO driver
index c63488c54f4aa5e465f774a16f2f44f360723dc1..75c262694632255e0932fa387c7e6b9d6e08aa25 100644 (file)
@@ -82,6 +82,23 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
        .io_port_2 = 0x7a,
 };
 
+static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
+       .cfg = 0x00,
+       .host_int_mask = 0x02,
+       .host_intstatus = 0x03,
+       .card_status = 0x50,
+       .sq_read_base_addr_a0 = 0x60,
+       .sq_read_base_addr_a1 = 0x61,
+       .card_revision = 0xbc,
+       .card_fw_status0 = 0xc0,
+       .card_fw_status1 = 0xc1,
+       .card_rx_len = 0xc2,
+       .card_rx_unit = 0xc3,
+       .io_port_0 = 0xd8,
+       .io_port_1 = 0xd9,
+       .io_port_2 = 0xda,
+};
+
 static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
        .helper         = "mrvl/sd8688_helper.bin",
        .firmware       = "mrvl/sd8688.bin",
@@ -103,6 +120,13 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
        .sd_blksz_fw_dl = 256,
 };
 
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
+       .helper         = NULL,
+       .firmware       = "mrvl/sd8897_uapsta.bin",
+       .reg            = &btmrvl_reg_88xx,
+       .sd_blksz_fw_dl = 256,
+};
+
 static const struct sdio_device_id btmrvl_sdio_ids[] = {
        /* Marvell SD8688 Bluetooth device */
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
@@ -116,6 +140,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
        /* Marvell SD8797 Bluetooth device */
        { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
                        .driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
+       /* Marvell SD8897 Bluetooth device */
+       { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
+                       .driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
 
        { }     /* Terminating entry */
 };
@@ -527,6 +554,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
        skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
        if (skb == NULL) {
                BT_ERR("No free skb");
+               ret = -ENOMEM;
                goto exit;
        }
 
@@ -1194,3 +1222,4 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
 MODULE_FIRMWARE("mrvl/sd8688.bin");
 MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
 MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
+MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
index 7a7e5f8ecadcffef990eaea6c2fafdcf94ff4c4b..81f12757a842a310398af8c2e4a3eb1a27ba19fd 100644 (file)
@@ -57,6 +57,9 @@ static struct usb_device_id btusb_table[] = {
        /* Apple-specific (Broadcom) devices */
        { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
 
+       /* MediaTek MT76x0E */
+       { USB_DEVICE(0x0e8d, 0x763f) },
+
        /* Broadcom SoftSailing reporting vendor specific */
        { USB_DEVICE(0x0a5c, 0x21e1) },
 
index 7f702fe3ecc2c68f5a3300cfa7182d00ad84fe38..ce67ab791eae9d008ed4c3d318b8c8949c30f428 100644 (file)
@@ -60,6 +60,7 @@
 
 #include <asm/unaligned.h>
 
+#include <net/mac80211.h>
 #include "base.h"
 #include "reg.h"
 #include "debug.h"
@@ -666,9 +667,46 @@ static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb)
        return htype;
 }
 
+static struct ieee80211_rate *
+ath5k_get_rate(const struct ieee80211_hw *hw,
+              const struct ieee80211_tx_info *info,
+              struct ath5k_buf *bf, int idx)
+{
+       /*
+       * convert a ieee80211_tx_rate RC-table entry to
+       * the respective ieee80211_rate struct
+       */
+       if (bf->rates[idx].idx < 0) {
+               return NULL;
+       }
+
+       return &hw->wiphy->bands[info->band]->bitrates[ bf->rates[idx].idx ];
+}
+
+static u16
+ath5k_get_rate_hw_value(const struct ieee80211_hw *hw,
+                       const struct ieee80211_tx_info *info,
+                       struct ath5k_buf *bf, int idx)
+{
+       struct ieee80211_rate *rate;
+       u16 hw_rate;
+       u8 rc_flags;
+
+       rate = ath5k_get_rate(hw, info, bf, idx);
+       if (!rate)
+               return 0;
+
+       rc_flags = bf->rates[idx].flags;
+       hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ?
+                  rate->hw_value_short : rate->hw_value;
+
+       return hw_rate;
+}
+
 static int
 ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
-                 struct ath5k_txq *txq, int padsize)
+                 struct ath5k_txq *txq, int padsize,
+                 struct ieee80211_tx_control *control)
 {
        struct ath5k_desc *ds = bf->desc;
        struct sk_buff *skb = bf->skb;
@@ -688,7 +726,11 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
        bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len,
                        DMA_TO_DEVICE);
 
-       rate = ieee80211_get_tx_rate(ah->hw, info);
+       ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates,
+                              ARRAY_SIZE(bf->rates));
+
+       rate = ath5k_get_rate(ah->hw, info, bf, 0);
+
        if (!rate) {
                ret = -EINVAL;
                goto err_unmap;
@@ -698,8 +740,8 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
                flags |= AR5K_TXDESC_NOACK;
 
        rc_flags = info->control.rates[0].flags;
-       hw_rate = (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ?
-               rate->hw_value_short : rate->hw_value;
+
+       hw_rate = ath5k_get_rate_hw_value(ah->hw, info, bf, 0);
 
        pktlen = skb->len;
 
@@ -722,12 +764,13 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
                duration = le16_to_cpu(ieee80211_ctstoself_duration(ah->hw,
                        info->control.vif, pktlen, info));
        }
+
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                ieee80211_get_hdrlen_from_skb(skb), padsize,
                get_hw_packet_type(skb),
                (ah->ah_txpower.txp_requested * 2),
                hw_rate,
-               info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
+               bf->rates[0].count, keyidx, ah->ah_tx_ant, flags,
                cts_rate, duration);
        if (ret)
                goto err_unmap;
@@ -736,13 +779,15 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
        if (ah->ah_capabilities.cap_has_mrr_support) {
                memset(mrr_rate, 0, sizeof(mrr_rate));
                memset(mrr_tries, 0, sizeof(mrr_tries));
+
                for (i = 0; i < 3; i++) {
-                       rate = ieee80211_get_alt_retry_rate(ah->hw, info, i);
+
+                       rate = ath5k_get_rate(ah->hw, info, bf, i);
                        if (!rate)
                                break;
 
-                       mrr_rate[i] = rate->hw_value;
-                       mrr_tries[i] = info->control.rates[i + 1].count;
+                       mrr_rate[i] = ath5k_get_rate_hw_value(ah->hw, info, bf, i);
+                       mrr_tries[i] = bf->rates[i].count;
                }
 
                ath5k_hw_setup_mrr_tx_desc(ah, ds,
@@ -1515,7 +1560,7 @@ unlock:
 
 void
 ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
-              struct ath5k_txq *txq)
+              struct ath5k_txq *txq, struct ieee80211_tx_control *control)
 {
        struct ath5k_hw *ah = hw->priv;
        struct ath5k_buf *bf;
@@ -1555,7 +1600,7 @@ ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        bf->skb = skb;
 
-       if (ath5k_txbuf_setup(ah, bf, txq, padsize)) {
+       if (ath5k_txbuf_setup(ah, bf, txq, padsize, control)) {
                bf->skb = NULL;
                spin_lock_irqsave(&ah->txbuflock, flags);
                list_add_tail(&bf->list, &ah->txbuf);
@@ -1571,11 +1616,13 @@ drop_packet:
 
 static void
 ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb,
-                        struct ath5k_txq *txq, struct ath5k_tx_status *ts)
+                        struct ath5k_txq *txq, struct ath5k_tx_status *ts,
+                        struct ath5k_buf *bf)
 {
        struct ieee80211_tx_info *info;
        u8 tries[3];
        int i;
+       int size = 0;
 
        ah->stats.tx_all_count++;
        ah->stats.tx_bytes_count += skb->len;
@@ -1587,6 +1634,9 @@ ath5k_tx_frame_completed(struct ath5k_hw *ah, struct sk_buff *skb,
 
        ieee80211_tx_info_clear_status(info);
 
+       size = min_t(int, sizeof(info->status.rates), sizeof(bf->rates));
+       memcpy(info->status.rates, bf->rates, size);
+
        for (i = 0; i < ts->ts_final_idx; i++) {
                struct ieee80211_tx_rate *r =
                        &info->status.rates[i];
@@ -1663,7 +1713,7 @@ ath5k_tx_processq(struct ath5k_hw *ah, struct ath5k_txq *txq)
 
                        dma_unmap_single(ah->dev, bf->skbaddr, skb->len,
                                        DMA_TO_DEVICE);
-                       ath5k_tx_frame_completed(ah, skb, txq, &ts);
+                       ath5k_tx_frame_completed(ah, skb, txq, &ts, bf);
                }
 
                /*
@@ -1917,7 +1967,7 @@ ath5k_beacon_send(struct ath5k_hw *ah)
 
        skb = ieee80211_get_buffered_bc(ah->hw, vif);
        while (skb) {
-               ath5k_tx_queue(ah->hw, skb, ah->cabq);
+               ath5k_tx_queue(ah->hw, skb, ah->cabq, NULL);
 
                if (ah->cabq->txq_len >= ah->cabq->txq_max)
                        break;
@@ -2442,7 +2492,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops)
                        IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                        IEEE80211_HW_SIGNAL_DBM |
                        IEEE80211_HW_MFP_CAPABLE |
-                       IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+                       IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+                       IEEE80211_HW_SUPPORTS_RC_TABLE;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
index 6c94c7ff23500abaf5aceed394e0ddb7c381468a..ca9a83ceeee1d430364a690c5b10703b14fc27d9 100644 (file)
@@ -47,6 +47,7 @@ struct ath5k_hw;
 struct ath5k_txq;
 struct ieee80211_channel;
 struct ath_bus_ops;
+struct ieee80211_tx_control;
 enum nl80211_iftype;
 
 enum ath5k_srev_type {
@@ -61,11 +62,12 @@ struct ath5k_srev_name {
 };
 
 struct ath5k_buf {
-       struct list_head        list;
-       struct ath5k_desc       *desc;  /* virtual addr of desc */
-       dma_addr_t              daddr;  /* physical addr of desc */
-       struct sk_buff          *skb;   /* skbuff for buf */
-       dma_addr_t              skbaddr;/* physical addr of skb data */
+       struct list_head                list;
+       struct ath5k_desc               *desc;          /* virtual addr of desc */
+       dma_addr_t                      daddr;          /* physical addr of desc */
+       struct sk_buff                  *skb;           /* skbuff for buf */
+       dma_addr_t                      skbaddr;        /* physical addr of skb data */
+       struct ieee80211_tx_rate        rates[4];       /* number of multi-rate stages */
 };
 
 struct ath5k_vif {
@@ -103,7 +105,7 @@ int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan);
 void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
 void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
 void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
-                   struct ath5k_txq *txq);
+                   struct ath5k_txq *txq, struct ieee80211_tx_control *control);
 
 const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
 
index 06f86f435711e805c958ee5f98354a60aafe5f41..81b686c6a3764111e8c8e969a90d36d6ced054ea 100644 (file)
@@ -66,7 +66,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
                return;
        }
 
-       ath5k_tx_queue(hw, skb, &ah->txqs[qnum]);
+       ath5k_tx_queue(hw, skb, &ah->txqs[qnum], control);
 }
 
 
index 5c9736a94e544d0c9008480ac994c593d1b4d269..2437ad26949d1c43617204fc7c887bf196a1e2f5 100644 (file)
@@ -3175,10 +3175,21 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 {
        struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
        struct ath6kl *ar = ath6kl_priv(vif->ndev);
-       u32 id;
+       u32 id, freq;
        const struct ieee80211_mgmt *mgmt;
        bool more_data, queued;
 
+       /* default to the current channel, but use the one specified as argument
+        * if any
+        */
+       freq = vif->ch_hint;
+       if (chan)
+               freq = chan->center_freq;
+
+       /* never send freq zero to the firmware */
+       if (WARN_ON(freq == 0))
+               return -EINVAL;
+
        mgmt = (const struct ieee80211_mgmt *) buf;
        if (vif->nw_type == AP_NETWORK && test_bit(CONNECTED, &vif->flags) &&
            ieee80211_is_probe_resp(mgmt->frame_control) &&
@@ -3188,8 +3199,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                 * command to allow the target to fill in the generic IEs.
                 */
                *cookie = 0; /* TX status not supported */
-               return ath6kl_send_go_probe_resp(vif, buf, len,
-                                                chan->center_freq);
+               return ath6kl_send_go_probe_resp(vif, buf, len, freq);
        }
 
        id = vif->send_action_id++;
@@ -3205,17 +3215,14 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 
        /* AP mode Power saving processing */
        if (vif->nw_type == AP_NETWORK) {
-               queued = ath6kl_mgmt_powersave_ap(vif,
-                                       id, chan->center_freq,
-                                       wait, buf,
-                                       len, &more_data, no_cck);
+               queued = ath6kl_mgmt_powersave_ap(vif, id, freq, wait, buf, len,
+                                                 &more_data, no_cck);
                if (queued)
                        return 0;
        }
 
-       return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id,
-                                       chan->center_freq, wait,
-                                       buf, len, no_cck);
+       return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, freq,
+                                       wait, buf, len, no_cck);
 }
 
 static void ath6kl_mgmt_frame_register(struct wiphy *wiphy,
@@ -3679,6 +3686,20 @@ err:
        return NULL;
 }
 
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support ath6kl_wowlan_support = {
+       .flags = WIPHY_WOWLAN_MAGIC_PKT |
+                WIPHY_WOWLAN_DISCONNECT |
+                WIPHY_WOWLAN_GTK_REKEY_FAILURE  |
+                WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                WIPHY_WOWLAN_EAP_IDENTITY_REQ   |
+                WIPHY_WOWLAN_4WAY_HANDSHAKE,
+       .n_patterns = WOW_MAX_FILTERS_PER_LIST,
+       .pattern_min_len = 1,
+       .pattern_max_len = WOW_PATTERN_SIZE,
+};
+#endif
+
 int ath6kl_cfg80211_init(struct ath6kl *ar)
 {
        struct wiphy *wiphy = ar->wiphy;
@@ -3772,15 +3793,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
        wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
 
 #ifdef CONFIG_PM
-       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                             WIPHY_WOWLAN_DISCONNECT |
-                             WIPHY_WOWLAN_GTK_REKEY_FAILURE  |
-                             WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                             WIPHY_WOWLAN_EAP_IDENTITY_REQ   |
-                             WIPHY_WOWLAN_4WAY_HANDSHAKE;
-       wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
-       wiphy->wowlan.pattern_min_len = 1;
-       wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
+       wiphy->wowlan = &ath6kl_wowlan_support;
 #endif
 
        wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
index ec33c8007b29a123e2d12d1cee1038d5b4c75409..760ab3fe09e2f753c360e1b1a149700ef5beca04 100644 (file)
@@ -17,7 +17,7 @@ config ATH9K_BTCOEX_SUPPORT
 
 config ATH9K
        tristate "Atheros 802.11n wireless cards support"
-       depends on MAC80211
+       depends on MAC80211 && HAS_DMA
        select ATH9K_HW
        select MAC80211_LEDS
        select LEDS_CLASS
@@ -84,13 +84,17 @@ config ATH9K_DFS_CERTIFIED
          developed. At this point enabling this option won't do anything
          except increase code size.
 
-config ATH9K_RATE_CONTROL
+config ATH9K_LEGACY_RATE_CONTROL
        bool "Atheros ath9k rate control"
        depends on ATH9K
-       default y
+       default n
        ---help---
          Say Y, if you want to use the ath9k specific rate control
-         module instead of minstrel_ht.
+         module instead of minstrel_ht. Be warned that there are various
+         issues with the ath9k RC and minstrel is a more robust algorithm.
+         Note that even if this option is selected, "ath9k_rate_control"
+         has to be passed to mac80211 using the module parameter,
+         ieee80211_default_rc_algo.
 
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
index 2ad8f9474ba1460c5733949d2232b5ade5d5fc42..75ee9e7704ce627eb52939c25d5ea0b6d1eb4f3d 100644 (file)
@@ -8,7 +8,7 @@ ath9k-y +=      beacon.o \
                antenna.o
 
 ath9k-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += mci.o
-ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
+ath9k-$(CONFIG_ATH9K_LEGACY_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
 ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
 ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
index 7ecd40f07a7442d4769c6e0e60331f9824f3d217..a68beb19ce4d6e65aaab31f475be2dff51d6d20d 100644 (file)
@@ -46,8 +46,8 @@ static const struct ani_ofdm_level_entry ofdm_level_table[] = {
        {  5,  4,  1  }, /* lvl 5 */
        {  6,  5,  1  }, /* lvl 6 */
        {  7,  6,  1  }, /* lvl 7 */
-       {  7,  6,  0  }, /* lvl 8 */
-       {  7,  7,  0  }  /* lvl 9 */
+       {  7,  7,  1  }, /* lvl 8 */
+       {  7,  8,  0  }  /* lvl 9 */
 };
 #define ATH9K_ANI_OFDM_NUM_LEVEL \
        ARRAY_SIZE(ofdm_level_table)
@@ -91,8 +91,8 @@ static const struct ani_cck_level_entry cck_level_table[] = {
        {  4,  0  }, /* lvl 4 */
        {  5,  0  }, /* lvl 5 */
        {  6,  0  }, /* lvl 6 */
-       {  6,  0  }, /* lvl 7 (only for high rssi) */
-       {  7,  0  }  /* lvl 8 (only for high rssi) */
+       {  7,  0  }, /* lvl 7 (only for high rssi) */
+       {  8,  0  }  /* lvl 8 (only for high rssi) */
 };
 
 #define ATH9K_ANI_CCK_NUM_LEVEL \
@@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
-       if (!DO_ANI(ah))
+       if (!ah->curchan)
                return;
 
-       aniState = &ah->curchan->ani;
+       aniState = &ah->ani;
        aniState->listenTime = 0;
 
        ENABLE_REGWRITE_BUFFER(ah);
@@ -143,7 +143,7 @@ static void ath9k_ani_restart(struct ath_hw *ah)
 static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
                                  bool scan)
 {
-       struct ar5416AniState *aniState = &ah->curchan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        const struct ani_ofdm_level_entry *entry_ofdm;
        const struct ani_cck_level_entry *entry_cck;
@@ -177,17 +177,14 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
            BEACON_RSSI(ah) <= ATH9K_ANI_RSSI_THR_HIGH)
                weak_sig = true;
 
-       if (aniState->ofdmWeakSigDetect != weak_sig)
-                       ath9k_hw_ani_control(ah,
-                               ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
-                               entry_ofdm->ofdm_weak_signal_on);
-
-       if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) {
-               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
-               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI;
-       } else {
-               ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI;
-               ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
+       /*
+        * OFDM Weak signal detection is always enabled for AP mode.
+        */
+       if (ah->opmode != NL80211_IFTYPE_AP &&
+           aniState->ofdmWeakSigDetect != weak_sig) {
+               ath9k_hw_ani_control(ah,
+                                    ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+                                    entry_ofdm->ofdm_weak_signal_on);
        }
 }
 
@@ -195,10 +192,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
-       if (!DO_ANI(ah))
+       if (!ah->curchan)
                return;
 
-       aniState = &ah->curchan->ani;
+       aniState = &ah->ani;
 
        if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
                ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
@@ -210,7 +207,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
                                 bool scan)
 {
-       struct ar5416AniState *aniState = &ah->curchan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        const struct ani_ofdm_level_entry *entry_ofdm;
        const struct ani_cck_level_entry *entry_cck;
@@ -251,10 +248,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
-       if (!DO_ANI(ah))
+       if (!ah->curchan)
                return;
 
-       aniState = &ah->curchan->ani;
+       aniState = &ah->ani;
 
        if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
                ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
@@ -269,7 +266,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
 
-       aniState = &ah->curchan->ani;
+       aniState = &ah->ani;
 
        /* lower OFDM noise immunity */
        if (aniState->ofdmNoiseImmunityLevel > 0 &&
@@ -292,12 +289,12 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
  */
 void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 {
-       struct ar5416AniState *aniState = &ah->curchan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
        struct ath9k_channel *chan = ah->curchan;
        struct ath_common *common = ath9k_hw_common(ah);
        int ofdm_nil, cck_nil;
 
-       if (!DO_ANI(ah))
+       if (!ah->curchan)
                return;
 
        BUG_ON(aniState == NULL);
@@ -363,24 +360,13 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
        ath9k_hw_set_ofdm_nil(ah, ofdm_nil, is_scanning);
        ath9k_hw_set_cck_nil(ah, cck_nil, is_scanning);
 
-       /*
-        * enable phy counters if hw supports or if not, enable phy
-        * interrupts (so we can count each one)
-        */
        ath9k_ani_restart(ah);
-
-       ENABLE_REGWRITE_BUFFER(ah);
-
-       REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
-       REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
-
-       REGWRITE_BUFFER_FLUSH(ah);
 }
 
 static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ar5416AniState *aniState = &ah->curchan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
        u32 phyCnt1, phyCnt2;
        int32_t listenTime;
 
@@ -415,10 +401,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
        struct ath_common *common = ath9k_hw_common(ah);
        u32 ofdmPhyErrRate, cckPhyErrRate;
 
-       if (!DO_ANI(ah))
+       if (!ah->curchan)
                return;
 
-       aniState = &ah->curchan->ani;
+       aniState = &ah->ani;
        if (!ath9k_hw_ani_read_counters(ah))
                return;
 
@@ -434,12 +420,25 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
                ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
                cckPhyErrRate, aniState->ofdmsTurn);
 
-       if (aniState->listenTime > ah->aniperiod) {
-               if (cckPhyErrRate < ah->config.cck_trig_low &&
-                   ofdmPhyErrRate < ah->config.ofdm_trig_low) {
+       if (aniState->listenTime > 5 * ah->aniperiod) {
+               /*
+                * Check if we need to lower immunity if
+                * 5 ani_periods have passed.
+                */
+               if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
+                   cckPhyErrRate <= ah->config.cck_trig_low) {
                        ath9k_hw_ani_lower_immunity(ah);
                        aniState->ofdmsTurn = !aniState->ofdmsTurn;
-               } else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) {
+               }
+               ath9k_ani_restart(ah);
+       } else if (aniState->listenTime > ah->aniperiod) {
+               /*
+                * Check if immunity has to be raised,
+                * (either OFDM or CCK).
+                */
+               if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
+                   (cckPhyErrRate <= ah->config.cck_trig_high ||
+                    aniState->ofdmsTurn)) {
                        ath9k_hw_ani_ofdm_err_trigger(ah);
                        aniState->ofdmsTurn = false;
                } else if (cckPhyErrRate > ah->config.cck_trig_high) {
@@ -490,32 +489,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 void ath9k_hw_ani_init(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       int i;
+       struct ar5416AniState *ani = &ah->ani;
 
        ath_dbg(common, ANI, "Initialize ANI\n");
 
        ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH;
        ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW;
-
        ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH;
        ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW;
 
-       for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
-               struct ath9k_channel *chan = &ah->channels[i];
-               struct ar5416AniState *ani = &chan->ani;
-
-               ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
-
-               ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-
-               ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
-
-               ani->ofdmsTurn = true;
-
-               ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
-               ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
-               ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
-       }
+       ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+       ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+       ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false;
+       ani->ofdmsTurn = true;
+       ani->ofdmWeakSigDetect = true;
+       ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+       ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
 
        /*
         * since we expect some ongoing maintenance on the tables, let's sanity
@@ -524,9 +513,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
        ah->aniperiod = ATH9K_ANI_PERIOD;
        ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL;
 
-       if (ah->config.enable_ani)
-               ah->proc_phyerr |= HAL_PROCESS_ANI;
-
        ath9k_ani_restart(ah);
        ath9k_enable_mib_counters(ah);
 }
index dddb1361039a71de9dbd205bba879e0dfcb8a14a..77a06fd40287aae33ff95de948cb7ce5b330bc0c 100644 (file)
 #ifndef ANI_H
 #define ANI_H
 
-#define HAL_PROCESS_ANI           0x00000001
-
-#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan)
-
 #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
 
 /* units are errors per second */
-#define ATH9K_ANI_OFDM_TRIG_HIGH          3500
-#define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000
-
-/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_HIGH          1000
 #define ATH9K_ANI_OFDM_TRIG_LOW           400
-#define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900
-
-/* units are errors per second */
 #define ATH9K_ANI_CCK_TRIG_HIGH           600
-
-/* units are errors per second */
 #define ATH9K_ANI_CCK_TRIG_LOW            300
 
-#define ATH9K_ANI_NOISE_IMMUNE_LVL        4
-#define ATH9K_ANI_USE_OFDM_WEAK_SIG       true
-#define ATH9K_ANI_CCK_WEAK_SIG_THR        false
-
 #define ATH9K_ANI_SPUR_IMMUNE_LVL         3
-
 #define ATH9K_ANI_FIRSTEP_LVL             2
 
 #define ATH9K_ANI_RSSI_THR_HIGH           40
 /* in ms */
 #define ATH9K_ANI_POLLINTERVAL            1000
 
-#define HAL_NOISE_IMMUNE_MAX              4
-#define HAL_SPUR_IMMUNE_MAX               7
-#define HAL_FIRST_STEP_MAX                2
-
 #define ATH9K_SIG_FIRSTEP_SETTING_MIN     0
 #define ATH9K_SIG_FIRSTEP_SETTING_MAX     20
 #define ATH9K_SIG_SPUR_IMM_SETTING_MIN    0
@@ -111,7 +90,7 @@ struct ar5416AniState {
        u8 mrcCCK;
        u8 spurImmunityLevel;
        u8 firstepLevel;
-       u8 ofdmWeakSigDetect;
+       bool ofdmWeakSigDetect;
        u32 listenTime;
        u32 ofdmPhyErrCount;
        u32 cckPhyErrCount;
@@ -119,8 +98,6 @@ struct ar5416AniState {
 };
 
 struct ar5416Stats {
-       u32 ast_ani_niup;
-       u32 ast_ani_nidown;
        u32 ast_ani_spurup;
        u32 ast_ani_spurdown;
        u32 ast_ani_ofdmon;
index 391da5ad6a99c54d8990790f26fc5c932def2193..d1acfe98918a2a50689c2760ed6455cf2c239b2a 100644 (file)
@@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah,
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
-       struct ar5416AniState *aniState = &chan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
        s32 value, value2;
 
        switch (cmd & ah->ani_function) {
@@ -1207,7 +1207,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
-       struct ar5416AniState *aniState = &chan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
        struct ath9k_ani_default *iniDef;
        u32 val;
 
@@ -1251,7 +1251,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
        /* these levels just got reset to defaults by the INI */
        aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
        aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-       aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+       aniState->ofdmWeakSigDetect = true;
        aniState->mrcCCK = false; /* not available on pre AR9003 */
 }
 
index 830daa12feb6d50bcd49783ca440446e304564f0..8dc2d089cdef642c7b92765a68f50f1a0b50292b 100644 (file)
@@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
        else
                INIT_INI_ARRAY(&ah->iniPcieSerdes,
                           ar9280PciePhy_clkreq_always_on_L1_9280);
-#ifdef CONFIG_PM_SLEEP
-               INIT_INI_ARRAY(&ah->iniPcieSerdesWow,
-                              ar9280PciePhy_awow);
-#endif
 
        if (AR_SREV_9287_11_OR_LATER(ah)) {
                INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1);
index beb6162cf97cbc36e39b3611c9d2cb063f04a3d3..4d18c66a6790362483be6a3ab4be86332826686a 100644 (file)
@@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
        {0x00004044, 0x00000000},
 };
 
-static const u32 ar9280PciePhy_awow[][2] = {
-       /* Addr      allmodes  */
-       {0x00004040, 0x9248fd00},
-       {0x00004040, 0x24924924},
-       {0x00004040, 0xa8000019},
-       {0x00004040, 0x13160820},
-       {0x00004040, 0xe5980560},
-       {0x00004040, 0xc01dcffd},
-       {0x00004040, 0x1aaabe41},
-       {0x00004040, 0xbe105554},
-       {0x00004040, 0x00043007},
-       {0x00004044, 0x00000000},
-};
-
 static const u32 ar9285Modes_9285_1_2[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
index db5ffada221718f76f6a1dfeabfbb5c6ed2929ef..7546b9a7dcbfa2252bf896e70fe48ad38b3b4646 100644 (file)
@@ -958,11 +958,11 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
        {0x0000a074, 0x00000000},
        {0x0000a078, 0x00000000},
        {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x1a1a1a1a},
-       {0x0000a084, 0x1a1a1a1a},
-       {0x0000a088, 0x1a1a1a1a},
-       {0x0000a08c, 0x1a1a1a1a},
-       {0x0000a090, 0x171a1a1a},
+       {0x0000a080, 0x22222229},
+       {0x0000a084, 0x1d1d1d1d},
+       {0x0000a088, 0x1d1d1d1d},
+       {0x0000a08c, 0x1d1d1d1d},
+       {0x0000a090, 0x171d1d1d},
        {0x0000a094, 0x11111717},
        {0x0000a098, 0x00030311},
        {0x0000a09c, 0x00000000},
index 639ba7d18ea41d14fd1ef55913c8bbc9ac7d8d42..6988e1d081f225c0c0a8efd0dc49fbacb4fc6a1a 100644 (file)
@@ -965,7 +965,7 @@ static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
 {
        int i;
 
-       if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah))
+       if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
                return;
 
        for (i = 0; i < AR9300_MAX_CHAINS; i++) {
index e6b92ff265fd6e878274a2d0b35660a5bfa9a1c5..25b8bbbe74fe347f6f0f17fcc129ebd100f88301 100644 (file)
@@ -3563,14 +3563,18 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
 {
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        int chain;
-       u32 regval;
+       u32 regval, value;
        static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
                        AR_PHY_SWITCH_CHAIN_0,
                        AR_PHY_SWITCH_CHAIN_1,
                        AR_PHY_SWITCH_CHAIN_2,
        };
 
-       u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
+       if (AR_SREV_9485(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0))
+               ath9k_hw_cfg_output(ah, AR9300_EXT_LNA_CTL_GPIO_AR9485,
+                                   AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED);
+
+       value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
 
        if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
                REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
index 54ba42f4108a4347c30900499b5c3e09c5dd4bbf..874f6570bd1cd7c266188dc7abe55295702f66d0 100644 (file)
 #define AR9300_BASE_ADDR 0x3ff
 #define AR9300_BASE_ADDR_512 0x1ff
 
-#define AR9300_OTP_BASE                        (AR_SREV_9340(ah) ? 0x30000 : 0x14000)
-#define AR9300_OTP_STATUS              (AR_SREV_9340(ah) ? 0x30018 : 0x15f18)
+#define AR9300_OTP_BASE \
+               ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
+#define AR9300_OTP_STATUS \
+               ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18)
 #define AR9300_OTP_STATUS_TYPE         0x7
 #define AR9300_OTP_STATUS_VALID                0x4
 #define AR9300_OTP_STATUS_ACCESS_BUSY  0x2
 #define AR9300_OTP_STATUS_SM_BUSY      0x1
-#define AR9300_OTP_READ_DATA           (AR_SREV_9340(ah) ? 0x3001c : 0x15f1c)
+#define AR9300_OTP_READ_DATA \
+               ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c)
 
 enum targetPowerHTRates {
        HT_TARGET_RATE_0_8_16,
index 2bf6548dd143c420f1a5d7372040b5638dd8ad38..bc483128efcd919af9af427a897335a82e6f183f 100644 (file)
@@ -334,7 +334,8 @@ static void ar9003_hw_spur_ofdm(struct ath_hw *ah,
        REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
                      AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1);
 
-       if (REG_READ_FIELD(ah, AR_PHY_MODE,
+       if (!AR_SREV_9340(ah) &&
+           REG_READ_FIELD(ah, AR_PHY_MODE,
                           AR_PHY_MODE_DYNAMIC) == 0x1)
                REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
                              AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1);
@@ -904,7 +905,12 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
 {
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_channel *chan = ah->curchan;
-       struct ar5416AniState *aniState = &chan->ani;
+       struct ar5416AniState *aniState = &ah->ani;
+       int m1ThreshLow, m2ThreshLow;
+       int m1Thresh, m2Thresh;
+       int m2CountThr, m2CountThrLow;
+       int m1ThreshLowExt, m2ThreshLowExt;
+       int m1ThreshExt, m2ThreshExt;
        s32 value, value2;
 
        switch (cmd & ah->ani_function) {
@@ -918,6 +924,61 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah,
                 */
                u32 on = param ? 1 : 0;
 
+               if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
+                       goto skip_ws_det;
+
+               m1ThreshLow = on ?
+                       aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+               m2ThreshLow = on ?
+                       aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+               m1Thresh = on ?
+                       aniState->iniDef.m1Thresh : m1Thresh_off;
+               m2Thresh = on ?
+                       aniState->iniDef.m2Thresh : m2Thresh_off;
+               m2CountThr = on ?
+                       aniState->iniDef.m2CountThr : m2CountThr_off;
+               m2CountThrLow = on ?
+                       aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+               m1ThreshLowExt = on ?
+                       aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+               m2ThreshLowExt = on ?
+                       aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+               m1ThreshExt = on ?
+                       aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+               m2ThreshExt = on ?
+                       aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+                             m1ThreshLow);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+                             m2ThreshLow);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M1_THRESH,
+                             m1Thresh);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2_THRESH,
+                             m2Thresh);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2COUNT_THR,
+                             m2CountThr);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+                             m2CountThrLow);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+                             m1ThreshLowExt);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+                             m2ThreshLowExt);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH,
+                             m1ThreshExt);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH,
+                             m2ThreshExt);
+skip_ws_det:
                if (on)
                        REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
                                    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
@@ -1172,7 +1233,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
        struct ath9k_ani_default *iniDef;
        u32 val;
 
-       aniState = &ah->curchan->ani;
+       aniState = &ah->ani;
        iniDef = &aniState->iniDef;
 
        ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
@@ -1213,7 +1274,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
        /* these levels just got reset to defaults by the INI */
        aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
        aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
-       aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG;
+       aniState->ofdmWeakSigDetect = true;
        aniState->mrcCCK = true;
 }
 
index e71774196c01bbf7fa6f3a33b1789556fc63ae9a..5013c731f9f6de2bb79a9a4d86f4fd0323ef7a88 100644 (file)
 
 #define AR_PHY_CCA_NOM_VAL_9330_2GHZ          -118
 
+#define AR9300_EXT_LNA_CTL_GPIO_AR9485 9
+
 /*
  * AGC Field Definitions
  */
index 712f415b8c0861165ab2a2ee74cbea853788295b..88ff1d7b53ab41c642333d553646e90065c3045b 100644 (file)
@@ -1020,7 +1020,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
        {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
        {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
        {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
        {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
index 579ed9c40b3f293cce9a38f7c22152e4721407ee..a6e666bcc0a747fedd0edbba4285dd7295c0865a 100644 (file)
@@ -251,9 +251,9 @@ struct ath_atx_tid {
        int tidno;
        int baw_head;   /* first un-acked tx buffer */
        int baw_tail;   /* next unused tx buffer slot */
-       int sched;
-       int paused;
-       u8 state;
+       bool sched;
+       bool paused;
+       bool active;
 };
 
 struct ath_node {
@@ -274,10 +274,6 @@ struct ath_node {
 #endif
 };
 
-#define AGGR_CLEANUP         BIT(1)
-#define AGGR_ADDBA_COMPLETE  BIT(2)
-#define AGGR_ADDBA_PROGRESS  BIT(3)
-
 struct ath_tx_control {
        struct ath_txq *txq;
        struct ath_node *an;
@@ -300,6 +296,7 @@ struct ath_tx {
        struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
        struct ath_descdma txdma;
        struct ath_txq *txq_map[IEEE80211_NUM_ACS];
+       struct ath_txq *uapsdq;
        u32 txq_max_pending[IEEE80211_NUM_ACS];
        u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
 };
@@ -347,6 +344,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
 void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop);
 int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl);
+void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                struct sk_buff *skb);
 void ath_tx_tasklet(struct ath_softc *sc);
 void ath_tx_edma_tasklet(struct ath_softc *sc);
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -357,6 +356,11 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
 void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
                       struct ath_node *an);
+void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta *sta,
+                                  u16 tids, int nframes,
+                                  enum ieee80211_frame_release_type reason,
+                                  bool more_data);
 
 /********/
 /* VIFs */
index fd1eebab8647e24a473233275256f859282963dc..1a17732bb089ca4b58e7d02880f4817b5f95a093 100644 (file)
@@ -108,23 +108,6 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
        ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
 }
 
-static void ath9k_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-       struct ath_softc *sc = hw->priv;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_tx_control txctl;
-
-       memset(&txctl, 0, sizeof(struct ath_tx_control));
-       txctl.txq = sc->beacon.cabq;
-
-       ath_dbg(common, XMIT, "transmitting CABQ packet, skb: %p\n", skb);
-
-       if (ath_tx_start(hw, skb, &txctl) != 0) {
-               ath_dbg(common, XMIT, "CABQ TX failed\n");
-               ieee80211_free_txskb(hw, skb);
-       }
-}
-
 static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
                                             struct ieee80211_vif *vif)
 {
@@ -206,10 +189,8 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
 
        ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx);
 
-       while (skb) {
-               ath9k_tx_cabq(hw, skb);
-               skb = ieee80211_get_buffered_bc(hw, vif);
-       }
+       if (skb)
+               ath_tx_cabq(hw, vif, skb);
 
        return bf;
 }
index 7304e7585009c03ec1faeaa7d013e5ded4eea5d3..5e8219a91e252b3d4a9ac2f5fda599caf4ae9ae8 100644 (file)
@@ -387,7 +387,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
 
        if (!caldata) {
                chan->noisefloor = nf;
-               ah->noise = ath9k_hw_getchan_noise(ah, chan);
                return false;
        }
 
index fc96ad3a135b7a1be0fdfc0c00f89987e7910d64..2721f52f0177ba7a4402521328a6029c80ed57c4 100644 (file)
@@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = {
        .llseek = default_llseek,
 };
 
-static ssize_t read_file_disable_ani(struct file *file, char __user *user_buf,
+static ssize_t read_file_ani(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       char buf[32];
-       unsigned int len;
+       struct ath_hw *ah = sc->sc_ah;
+       unsigned int len = 0, size = 1024;
+       ssize_t retval = 0;
+       char *buf;
 
-       len = sprintf(buf, "%d\n", common->disable_ani);
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       buf = kzalloc(size, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       if (common->disable_ani) {
+               len += snprintf(buf + len, size - len, "%s: %s\n",
+                               "ANI", "DISABLED");
+               goto exit;
+       }
+
+       len += snprintf(buf + len, size - len, "%15s: %s\n",
+                       "ANI", "ENABLED");
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "ANI RESET", ah->stats.ast_ani_reset);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "SPUR UP", ah->stats.ast_ani_spurup);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "SPUR DOWN", ah->stats.ast_ani_spurup);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "MRC-CCK ON", ah->stats.ast_ani_ccklow);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "FIR-STEP UP", ah->stats.ast_ani_stepup);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
+       len += snprintf(buf + len, size - len, "%15s: %u\n",
+                       "CCK ERRORS", ah->stats.ast_ani_cckerrs);
+exit:
+       if (len > size)
+               len = size;
+
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+
+       return retval;
 }
 
-static ssize_t write_file_disable_ani(struct file *file,
-                                     const char __user *user_buf,
-                                     size_t count, loff_t *ppos)
+static ssize_t write_file_ani(struct file *file,
+                             const char __user *user_buf,
+                             size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       unsigned long disable_ani;
+       unsigned long ani;
        char buf[32];
        ssize_t len;
 
@@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file,
                return -EFAULT;
 
        buf[len] = '\0';
-       if (strict_strtoul(buf, 0, &disable_ani))
+       if (strict_strtoul(buf, 0, &ani))
+               return -EINVAL;
+
+       if (ani < 0 || ani > 1)
                return -EINVAL;
 
-       common->disable_ani = !!disable_ani;
+       common->disable_ani = !ani;
 
-       if (disable_ani) {
+       if (common->disable_ani) {
                clear_bit(SC_OP_ANI_RUN, &sc->sc_flags);
                ath_stop_ani(sc);
        } else {
@@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file,
        return count;
 }
 
-static const struct file_operations fops_disable_ani = {
-       .read = read_file_disable_ani,
-       .write = write_file_disable_ani,
+static const struct file_operations fops_ani = {
+       .read = read_file_ani,
+       .write = write_file_ani,
        .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
@@ -1676,6 +1723,14 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
        WARN_ON(i != ATH9K_SSTATS_LEN);
 }
 
+void ath9k_deinit_debug(struct ath_softc *sc)
+{
+       if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
+               relay_close(sc->rfs_chan_spec_scan);
+               sc->rfs_chan_spec_scan = NULL;
+       }
+}
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1719,8 +1774,8 @@ int ath9k_init_debug(struct ath_hw *ah)
                            sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
        debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
                            sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
-       debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR,
-                           sc->debug.debugfs_phy, sc, &fops_disable_ani);
+       debugfs_create_file("ani", S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc, &fops_ani);
        debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
                            &sc->sc_ah->config.enable_paprd);
        debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
index 62da19c6f4e0e4d71f27d2e83329415b8405305f..fc679198a0f38049a385fb53ab25209b23945827 100644 (file)
@@ -251,45 +251,6 @@ struct ath_stats {
        u32 reset[__RESET_TYPE_MAX];
 };
 
-#define ATH_DBG_MAX_SAMPLES    10
-struct ath_dbg_bb_mac_samp {
-       u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS];
-       u32 pcu_obs, pcu_cr, noise;
-       struct {
-               u64 jiffies;
-               int8_t rssi_ctl0;
-               int8_t rssi_ctl1;
-               int8_t rssi_ctl2;
-               int8_t rssi_ext0;
-               int8_t rssi_ext1;
-               int8_t rssi_ext2;
-               int8_t rssi;
-               bool isok;
-               u8 rts_fail_cnt;
-               u8 data_fail_cnt;
-               u8 rateindex;
-               u8 qid;
-               u8 tid;
-               u32 ba_low;
-               u32 ba_high;
-       } ts[ATH_DBG_MAX_SAMPLES];
-       struct {
-               u64 jiffies;
-               int8_t rssi_ctl0;
-               int8_t rssi_ctl1;
-               int8_t rssi_ctl2;
-               int8_t rssi_ext0;
-               int8_t rssi_ext1;
-               int8_t rssi_ext2;
-               int8_t rssi;
-               bool is_mybeacon;
-               u8 antenna;
-               u8 rate;
-       } rs[ATH_DBG_MAX_SAMPLES];
-       struct ath_cycle_counters cc;
-       struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
-};
-
 struct ath9k_debug {
        struct dentry *debugfs_phy;
        u32 regidx;
@@ -297,6 +258,7 @@ struct ath9k_debug {
 };
 
 int ath9k_init_debug(struct ath_hw *ah);
+void ath9k_deinit_debug(struct ath_softc *sc);
 
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
@@ -332,6 +294,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
        return 0;
 }
 
+static inline void ath9k_deinit_debug(struct ath_softc *sc)
+{
+}
+
 static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
                                            enum ath9k_int status)
 {
index 0085e643132f4e794a62e57896cc032ca64a67ef..69581031f2cdfe159f26199c4189bfa4ee0f6546 100644 (file)
@@ -142,6 +142,7 @@ struct ath9k_htc_target_aggr {
 #define WLAN_RC_40_FLAG  0x02
 #define WLAN_RC_SGI_FLAG 0x04
 #define WLAN_RC_HT_FLAG  0x08
+#define ATH_RC_TX_STBC_FLAG 0x20
 
 struct ath9k_htc_rateset {
        u8 rs_nrates;
index 59f64367e8cac19f43bcbdc497b7a0c3b0d81bd9..bb0ba9e3e083730c2be54b44c6bbcf3a420285f3 100644 (file)
@@ -517,6 +517,9 @@ static void setup_ht_cap(struct ath9k_htc_priv *priv,
        ath_dbg(common, CONFIG, "TX streams %d, RX streams: %d\n",
                tx_streams, rx_streams);
 
+       if (tx_streams >= 2)
+               ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+
        if (tx_streams != rx_streams) {
                ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
                ht_info->mcs.tx_params |= ((tx_streams - 1) <<
index 2a67b57c3ecb680e95c0e985965b4cb1fbd075b2..eaa94feb4333b2d89f1cd224b930c6b1b93548ca 100644 (file)
@@ -627,6 +627,8 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
                trate->rates.ht_rates.rs_nrates = j;
 
                caps = WLAN_RC_HT_FLAG;
+               if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+                       caps |= ATH_RC_TX_STBC_FLAG;
                if (sta->ht_cap.mcs.rx_mask[1])
                        caps |= WLAN_RC_DS_FLAG;
                if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
@@ -814,8 +816,7 @@ void ath9k_htc_ani_work(struct work_struct *work)
        }
 
        /* Verify whether we must check ANI */
-       if (ah->config.enable_ani &&
-           (timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
+       if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
                aniflag = true;
                common->ani.checkani_timer = timestamp;
        }
@@ -845,8 +846,7 @@ set_timer:
        * short calibration and long calibration.
        */
        cal_interval = ATH_LONG_CALINTERVAL;
-       if (ah->config.enable_ani)
-               cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
+       cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
        if (!common->ani.caldone)
                cal_interval = min(cal_interval, (u32)short_cal_interval);
 
index a263ccc00a475438934e77bfd1531d3196a14e54..ca9d9cd14ddb966f5718c404f0aca0fc0cc7dca3 100644 (file)
@@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        ah->config.pcie_clock_req = 0;
        ah->config.pcie_waen = 0;
        ah->config.analog_shiftreg = 1;
-       ah->config.enable_ani = true;
 
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
                ah->config.spurchans[i][0] = AR_NO_SPUR;
@@ -549,8 +548,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
                ah->eep_ops->get_eeprom_ver(ah),
                ah->eep_ops->get_eeprom_rev(ah));
 
-       if (ah->config.enable_ani)
-               ath9k_hw_ani_init(ah);
+       ath9k_hw_ani_init(ah);
 
        return 0;
 }
@@ -1172,6 +1170,7 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)
 static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
+       int txbuf_size;
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -1225,13 +1224,17 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
                 * So set the usable tx buf size also to half to
                 * avoid data/delimiter underruns
                 */
-               REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
-                         AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
-       } else if (!AR_SREV_9271(ah)) {
-               REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
-                         AR_PCU_TXBUF_CTRL_USABLE_SIZE);
+               txbuf_size = AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE;
+       } else if (AR_SREV_9340_13_OR_LATER(ah)) {
+               /* Uses fewer entries for AR934x v1.3+ to prevent rx overruns */
+               txbuf_size = AR_9340_PCU_TXBUF_CTRL_USABLE_SIZE;
+       } else {
+               txbuf_size = AR_PCU_TXBUF_CTRL_USABLE_SIZE;
        }
 
+       if (!AR_SREV_9271(ah))
+               REG_WRITE(ah, AR_PCU_TXBUF_CTRL, txbuf_size);
+
        REGWRITE_BUFFER_FLUSH(ah);
 
        if (AR_SREV_9300_20_OR_LATER(ah))
@@ -1306,9 +1309,13 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                        AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
        } else {
                tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
-               if (tmpReg &
-                   (AR_INTR_SYNC_LOCAL_TIMEOUT |
-                    AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+               if (AR_SREV_9340(ah))
+                       tmpReg &= AR9340_INTR_SYNC_LOCAL_TIMEOUT;
+               else
+                       tmpReg &= AR_INTR_SYNC_LOCAL_TIMEOUT |
+                                 AR_INTR_SYNC_RADM_CPL_TIMEOUT;
+
+               if (tmpReg) {
                        u32 val;
                        REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
 
@@ -1863,7 +1870,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ah->caldata = caldata;
        if (caldata && (chan->channel != caldata->channel ||
-                       chan->channelFlags != caldata->channelFlags)) {
+                       chan->channelFlags != caldata->channelFlags ||
+                       chan->chanmode != caldata->chanmode)) {
                /* Operating channel changed, reset channel calibration data */
                memset(caldata, 0, sizeof(*caldata));
                ath9k_init_nfcal_hist_buffer(ah, chan);
@@ -2595,13 +2603,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        pCap->hw_caps |= ATH9K_HW_CAP_RTT;
        }
 
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE |
-                                ATH9K_HW_WOW_PATTERN_MATCH_EXACT;
-
-               if (AR_SREV_9280(ah))
-                       pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD;
-       }
+       if (AR_SREV_9462(ah))
+               pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE;
 
        if (AR_SREV_9300_20_OR_LATER(ah) &&
            ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
index ae3034374bc4ca1b064fe54d7a6ce6b5ed43b706..7d259b7dc2547062ab574373f967d8a7e18bd329 100644 (file)
@@ -246,9 +246,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_MCI                        = BIT(15),
        ATH9K_HW_CAP_DFS                        = BIT(16),
        ATH9K_HW_WOW_DEVICE_CAPABLE             = BIT(17),
-       ATH9K_HW_WOW_PATTERN_MATCH_EXACT        = BIT(18),
-       ATH9K_HW_WOW_PATTERN_MATCH_DWORD        = BIT(19),
-       ATH9K_HW_CAP_PAPRD                      = BIT(20),
+       ATH9K_HW_CAP_PAPRD                      = BIT(18),
 };
 
 /*
@@ -291,7 +289,6 @@ struct ath9k_ops_config {
        u32 ofdm_trig_high;
        u32 cck_trig_high;
        u32 cck_trig_low;
-       u32 enable_ani;
        u32 enable_paprd;
        int serialize_regmode;
        bool rx_intr_mitigation;
@@ -423,7 +420,6 @@ struct ath9k_hw_cal_data {
 
 struct ath9k_channel {
        struct ieee80211_channel *chan;
-       struct ar5416AniState ani;
        u16 channel;
        u32 channelFlags;
        u32 chanmode;
@@ -854,10 +850,10 @@ struct ath_hw {
        u32 globaltxtimeout;
 
        /* ANI */
-       u32 proc_phyerr;
        u32 aniperiod;
        enum ath9k_ani_cmd ani_function;
        u32 ani_skip_count;
+       struct ar5416AniState ani;
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex_hw btcoex_hw;
@@ -882,9 +878,6 @@ struct ath_hw {
        struct ar5416IniArray iniBank6;
        struct ar5416IniArray iniAddac;
        struct ar5416IniArray iniPcieSerdes;
-#ifdef CONFIG_PM_SLEEP
-       struct ar5416IniArray iniPcieSerdesWow;
-#endif
        struct ar5416IniArray iniPcieSerdesLowPower;
        struct ar5416IniArray iniModesFastClock;
        struct ar5416IniArray iniAdditional;
@@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
 }
 #endif
 
-
-
 #define ATH9K_CLOCK_RATE_CCK           22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM     44
index 0536d442b0682950d3b5aa2d7aeeda2e8c8b1cc4..818f22daa8ba88d2a2975f022e3c34f5a55ce76d 100644 (file)
@@ -432,6 +432,8 @@ static int ath9k_init_queues(struct ath_softc *sc)
        sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
        ath_cabq_update(sc);
 
+       sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0);
+
        for (i = 0; i < IEEE80211_NUM_ACS; i++) {
                sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
                sc->tx.txq_map[i]->mac80211_qnum = i;
@@ -753,6 +755,15 @@ static const struct ieee80211_iface_combination if_comb[] = {
        }
 };
 
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support ath9k_wowlan_support = {
+       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+       .n_patterns = MAX_NUM_USER_PATTERN,
+       .pattern_min_len = 1,
+       .pattern_max_len = MAX_PATTERN_SIZE,
+};
+#endif
+
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -778,6 +789,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
+       hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_P2P_GO) |
                BIT(NL80211_IFTYPE_P2P_CLIENT) |
@@ -790,29 +803,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        hw->wiphy->iface_combinations = if_comb;
        hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
 
-       if (AR_SREV_5416(sc->sc_ah))
-               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
        hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
        hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
 #ifdef CONFIG_PM_SLEEP
-
        if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
-           device_can_wakeup(sc->dev)) {
-
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT;
-               hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN;
-               hw->wiphy->wowlan.pattern_min_len = 1;
-               hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE;
-
-       }
+           device_can_wakeup(sc->dev))
+               hw->wiphy->wowlan = &ath9k_wowlan_support;
 
        atomic_set(&sc->wow_sleep_proc_intr, -1);
        atomic_set(&sc->wow_got_bmiss_intr, -1);
-
 #endif
 
        hw->queues = 4;
@@ -833,10 +836,6 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
        sc->ant_rx = hw->wiphy->available_antennas_rx;
        sc->ant_tx = hw->wiphy->available_antennas_tx;
 
-#ifdef CONFIG_ATH9K_RATE_CONTROL
-       hw->rate_control_algorithm = "ath9k_rate_control";
-#endif
-
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
                hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
                        &sc->sbands[IEEE80211_BAND_2GHZ];
@@ -909,7 +908,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
        if (!ath_is_world_regd(reg)) {
                error = regulatory_hint(hw->wiphy, reg->alpha2);
                if (error)
-                       goto unregister;
+                       goto debug_cleanup;
        }
 
        ath_init_leds(sc);
@@ -917,6 +916,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
 
        return 0;
 
+debug_cleanup:
+       ath9k_deinit_debug(sc);
 unregister:
        ieee80211_unregister_hw(hw);
 rx_cleanup:
@@ -945,11 +946,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
                sc->dfs_detector->exit(sc->dfs_detector);
 
        ath9k_eeprom_release(sc);
-
-       if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) {
-               relay_close(sc->rfs_chan_spec_scan);
-               sc->rfs_chan_spec_scan = NULL;
-       }
 }
 
 void ath9k_deinit_device(struct ath_softc *sc)
@@ -963,6 +959,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
 
        ath9k_ps_restore(sc);
 
+       ath9k_deinit_debug(sc);
        ieee80211_unregister_hw(hw);
        ath_rx_cleanup(sc);
        ath9k_deinit_softc(sc);
index cc422a4dfa171679d5c57cdb5593ba3a007f5e72..fff5d3ccc66325f351f32b6ab8c96b676592ed31 100644 (file)
@@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data)
        }
 
        /* Verify whether we must check ANI */
-       if (sc->sc_ah->config.enable_ani
-           && (timestamp - common->ani.checkani_timer) >=
-           ah->config.ani_poll_interval) {
+       if ((timestamp - common->ani.checkani_timer) >= ah->config.ani_poll_interval) {
                aniflag = true;
                common->ani.checkani_timer = timestamp;
        }
@@ -427,9 +425,7 @@ set_timer:
        * short calibration and long calibration.
        */
        cal_interval = ATH_LONG_CALINTERVAL;
-       if (sc->sc_ah->config.enable_ani)
-               cal_interval = min(cal_interval,
-                                  (u32)ah->config.ani_poll_interval);
+       cal_interval = min(cal_interval, (u32)ah->config.ani_poll_interval);
        if (!common->ani.caldone)
                cal_interval = min(cal_interval, (u32)short_cal_interval);
 
index d055e389abfc80d7a7b156a58ba0aa29ca9f1945..2ef05ebffbcf4d7c2167ed46c26aa192060427ed 100644 (file)
@@ -410,7 +410,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 
        REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
 
-       if (AR_SREV_9340(ah))
+       if (AR_SREV_9340(ah) && !AR_SREV_9340_13_OR_LATER(ah))
                REG_WRITE(ah, AR_DMISC(q),
                          AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
        else
index a1630d1ee3c98c3e4f62ecbcf225f0d4742dccde..1737a3e336859013e2b9aeb6d49d61da1b35a688 100644 (file)
@@ -1210,13 +1210,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                ath_update_survey_stats(sc);
                spin_unlock_irqrestore(&common->cc_lock, flags);
 
-               /*
-                * Preserve the current channel values, before updating
-                * the same channel
-                */
-               if (ah->curchan && (old_pos == pos))
-                       ath9k_hw_getnf(ah, ah->curchan);
-
                ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
                                          curchan, channel_type);
 
@@ -1686,6 +1679,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                              u16 tid, u16 *ssn, u8 buf_size)
 {
        struct ath_softc *sc = hw->priv;
+       bool flush = false;
        int ret = 0;
 
        mutex_lock(&sc->mutex);
@@ -1702,12 +1696,14 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                        ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                ath9k_ps_restore(sc);
                break;
-       case IEEE80211_AMPDU_TX_STOP_CONT:
        case IEEE80211_AMPDU_TX_STOP_FLUSH:
        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+               flush = true;
+       case IEEE80211_AMPDU_TX_STOP_CONT:
                ath9k_ps_wakeup(sc);
                ath_tx_aggr_stop(sc, sta, tid);
-               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               if (!flush)
+                       ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                ath9k_ps_restore(sc);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -2003,7 +1999,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_hw_capabilities *pcaps = &ah->caps;
        int pattern_count = 0;
        int i, byte_cnt;
        u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
@@ -2073,36 +2068,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
 
        /* Create Disassociate pattern mask */
 
-       if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) {
-
-               if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) {
-                       /*
-                        * for AR9280, because of hardware limitation, the
-                        * first 4 bytes have to be matched for all patterns.
-                        * the mask for disassociation and de-auth pattern
-                        * matching need to enable the first 4 bytes.
-                        * also the duration field needs to be filled.
-                        */
-                       dis_deauth_mask[0] = 0xf0;
-
-                       /*
-                        * fill in duration field
-                        FIXME: what is the exact value ?
-                        */
-                       dis_deauth_pattern[2] = 0xff;
-                       dis_deauth_pattern[3] = 0xff;
-               } else {
-                       dis_deauth_mask[0] = 0xfe;
-               }
-
-               dis_deauth_mask[1] = 0x03;
-               dis_deauth_mask[2] = 0xc0;
-       } else {
-               dis_deauth_mask[0] = 0xef;
-               dis_deauth_mask[1] = 0x3f;
-               dis_deauth_mask[2] = 0x00;
-               dis_deauth_mask[3] = 0xfc;
-       }
+       dis_deauth_mask[0] = 0xfe;
+       dis_deauth_mask[1] = 0x03;
+       dis_deauth_mask[2] = 0xc0;
 
        ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
 
@@ -2372,6 +2340,7 @@ struct ieee80211_ops ath9k_ops = {
        .flush              = ath9k_flush,
        .tx_frames_pending  = ath9k_tx_frames_pending,
        .tx_last_beacon     = ath9k_tx_last_beacon,
+       .release_buffered_frames = ath9k_release_buffered_frames,
        .get_stats          = ath9k_get_stats,
        .set_antenna        = ath9k_set_antenna,
        .get_antenna        = ath9k_get_antenna,
index aa4d368d8d3df53290a35fb7248c0e733d55deed..7eb1f4b458e4fb1f3c096fd297bb60b273d9c686 100644 (file)
@@ -1227,10 +1227,7 @@ static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta,
                return false;
 
        txtid = ATH_AN_2_TID(an, tidno);
-
-       if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
-                       return true;
-       return false;
+       return !txtid->active;
 }
 
 
index 267dbfcfaa96b8cb8b5311bd484d8e9908f838bc..b9a87383cb43214b17a845e6b7ae3ff2ecdf35d7 100644 (file)
@@ -231,7 +231,7 @@ static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
 }
 #endif
 
-#ifdef CONFIG_ATH9K_RATE_CONTROL
+#ifdef CONFIG_ATH9K_LEGACY_RATE_CONTROL
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
 #else
index b4b758deb30e2ef0fb827a665a0208570627da73..865e043e8aa6408c92e2b512ffcc7ba69c4ed39f 100644 (file)
@@ -955,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        if (rx_stats->rs_more)
                return 0;
 
-       ath9k_process_rssi(common, hw, hdr, rx_stats);
-
        if (ath9k_process_rate(common, hw, rx_stats, rx_status))
                return -EINVAL;
 
+       ath9k_process_rssi(common, hw, hdr, rx_stats);
+
        rx_status->band = hw->conf.chandef.chan->band;
        rx_status->freq = hw->conf.chandef.chan->center_freq;
        rx_status->signal = ah->noise + rx_stats->rs_rssi;
index 5c4ab5026dca598ad81b5a2522e3b03fc1a1cdff..f7c90cc58d563428d92940233222bcb9d05ea12c 100644 (file)
 #define AR_SREV_REVISION_9485_10       0
 #define AR_SREV_REVISION_9485_11        1
 #define AR_SREV_VERSION_9340           0x300
+#define AR_SREV_REVISION_9340_10       0
+#define AR_SREV_REVISION_9340_11       1
+#define AR_SREV_REVISION_9340_12       2
+#define AR_SREV_REVISION_9340_13       3
 #define AR_SREV_VERSION_9580           0x1C0
 #define AR_SREV_REVISION_9580_10       4 /* AR9580 1.0 */
 #define AR_SREV_VERSION_9462           0x280
 #define AR_SREV_9340(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
 
+#define AR_SREV_9340_13_OR_LATER(_ah) \
+       (AR_SREV_9340((_ah)) && \
+        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9340_13))
+
 #define AR_SREV_9285E_20(_ah) \
     (AR_SREV_9285_12_OR_LATER(_ah) && \
      ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
@@ -1007,6 +1015,8 @@ enum {
                                AR_INTR_SYNC_LOCAL_TIMEOUT |
                                AR_INTR_SYNC_MAC_SLEEP_ACCESS),
 
+       AR9340_INTR_SYNC_LOCAL_TIMEOUT = 0x00000010,
+
        AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF,
 
 };
@@ -1881,6 +1891,7 @@ enum {
 #define AR_PCU_TXBUF_CTRL_SIZE_MASK     0x7FF
 #define AR_PCU_TXBUF_CTRL_USABLE_SIZE   0x700
 #define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE   0x380
+#define AR_9340_PCU_TXBUF_CTRL_USABLE_SIZE   0x500
 
 #define AR_PCU_MISC_MODE2               0x8344
 #define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE           0x00000002
index 9f8563091bea436d5973331edac261de73292035..81c88dd606dcd960f43e740b9af8cffcdc25778a 100644 (file)
@@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event)
 }
 EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
 
-static void ath9k_hw_config_serdes_wow_sleep(struct ath_hw *ah)
-{
-       int i;
-
-       for (i = 0; i < ah->iniPcieSerdesWow.ia_rows; i++)
-               REG_WRITE(ah, INI_RA(&ah->iniPcieSerdesWow, i, 0),
-                         INI_RA(&ah->iniPcieSerdesWow, i, 1));
-
-       usleep_range(1000, 1500);
-}
-
 static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -58,15 +47,8 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
                ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
                        REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
                return;
-       } else {
-               if (!AR_SREV_9300_20_OR_LATER(ah))
-                       REG_WRITE(ah, AR_RXDP, 0x0);
        }
 
-       /* AR9280 WoW has sleep issue, do not set it to sleep */
-       if (AR_SREV_9280_20(ah))
-               return;
-
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
 }
 
@@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
 
        /* set the transmit buffer */
        ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
-
-       if (!(AR_SREV_9300_20_OR_LATER(ah)))
-               ctl[0] += (KAL_ANTENNA_MODE << 25);
-
        ctl[1] = 0;
        ctl[3] = 0xb;   /* OFDM_6M hardware value for this rate */
        ctl[4] = 0;
        ctl[7] = (ah->txchainmask) << 2;
-
-       if (AR_SREV_9300_20_OR_LATER(ah))
-               ctl[2] = 0xf << 16; /* tx_tries 0 */
-       else
-               ctl[2] = 0x7 << 16; /* tx_tries 0 */
-
+       ctl[2] = 0xf << 16; /* tx_tries 0 */
 
        for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
                REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
 
-       /* for AR9300 family 13 descriptor words */
-       if (AR_SREV_9300_20_OR_LATER(ah))
-               REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
+       REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
 
        data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |
                       (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);
@@ -183,9 +154,6 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
 
        ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
 
-       if (!AR_SREV_9285_12_OR_LATER(ah))
-               return;
-
        if (pattern_count < 4) {
                /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
                set = (pattern_len & AR_WOW_LENGTH_MAX) <<
@@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
 {
        u32 wow_status = 0;
        u32 val = 0, rval;
+
        /*
         * read the WoW status register to know
         * the wakeup reason
@@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
        val &= ah->wow_event_mask;
 
        if (val) {
-
                if (val & AR_WOW_MAGIC_PAT_FOUND)
                        wow_status |= AH_WOW_MAGIC_PATTERN_EN;
-
                if (AR_WOW_PATTERN_FOUND(val))
                        wow_status |= AH_WOW_USER_PATTERN_EN;
-
                if (val & AR_WOW_KEEP_ALIVE_FAIL)
                        wow_status |= AH_WOW_LINK_CHANGE;
-
                if (val & AR_WOW_BEACON_FAIL)
                        wow_status |= AH_WOW_BEACON_MISS;
-
        }
 
        /*
@@ -254,17 +218,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
        REG_WRITE(ah, AR_WOW_PATTERN,
                  AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));
 
-       /*
-        * tie reset register for AR9002 family of chipsets
-        * NB: not tieing it back might have some repurcussions.
-        */
-
-       if (!AR_SREV_9300_20_OR_LATER(ah)) {
-               REG_SET_BIT(ah, AR_WA, AR_WA_UNTIE_RESET_EN |
-                           AR_WA_POR_SHORT | AR_WA_RESET_EN);
-       }
-
-
        /*
         * restore the beacon threshold to init value
         */
@@ -277,8 +230,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
         * reset to our Chip's Power On Reset so that any PCI-E
         * reset from the bus will not reset our chip
         */
-
-       if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress)
+       if (ah->is_pciexpress)
                ath9k_hw_configpcipowersave(ah, false);
 
        ah->wow_event_mask = 0;
@@ -298,7 +250,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
         * are from the 'pattern_enable' in this function and
         * 'pattern_count' of ath9k_hw_wow_apply_pattern()
         */
-
        wow_event_mask = ah->wow_event_mask;
 
        /*
@@ -306,50 +257,15 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
         * WOW sleep, we do want the Reset from the PCI-E to disturb
         * our hw state
         */
-
        if (ah->is_pciexpress) {
-
                /*
                 * we need to untie the internal POR (power-on-reset)
                 * to the external PCI-E reset. We also need to tie
                 * the PCI-E Phy reset to the PCI-E reset.
                 */
-
-               if (AR_SREV_9300_20_OR_LATER(ah)) {
-                       set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
-                       clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
-                       REG_RMW(ah, AR_WA, set, clr);
-               } else {
-                       if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
-                               set = AR9285_WA_DEFAULT;
-                       else
-                               set = AR9280_WA_DEFAULT;
-
-                       /*
-                        * In AR9280 and AR9285, bit 14 in WA register
-                        * (disable L1) should only be set when device
-                        * enters D3 state and be cleared when device
-                        * comes back to D0
-                        */
-
-                       if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
-                               set |= AR_WA_D3_L1_DISABLE;
-
-                       clr = AR_WA_UNTIE_RESET_EN;
-                       set |= AR_WA_RESET_EN | AR_WA_POR_SHORT;
-                       REG_RMW(ah, AR_WA, set, clr);
-
-                       /*
-                        * for WoW sleep, we reprogram the SerDes so that the
-                        * PLL and CLK REQ are both enabled. This uses more
-                        * power but otherwise WoW sleep is unstable and the
-                        * chip may disappear.
-                        */
-
-                       if (AR_SREV_9285_12_OR_LATER(ah))
-                               ath9k_hw_config_serdes_wow_sleep(ah);
-
-               }
+               set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
+               clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
+               REG_RMW(ah, AR_WA, set, clr);
        }
 
        /*
@@ -378,7 +294,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
         * Program default values for pattern backoff, aifs/slot/KAL count,
         * beacon miss timeout, KAL timeout, etc.
         */
-
        set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
        REG_SET_BIT(ah, AR_WOW_PATTERN, set);
 
@@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
        /*
         * Keep alive timo in ms except AR9280
         */
-       if (!pattern_enable || AR_SREV_9280(ah))
+       if (!pattern_enable)
                set = AR_WOW_KEEP_ALIVE_NEVER;
        else
                set = KAL_TIMEOUT * 32;
@@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
        /*
         * Configure MAC WoW Registers
         */
-
        set = 0;
        /* Send keep alive timeouts anyway */
        clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
@@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
        else
                set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
 
-       /*
-        * FIXME: For now disable keep alive frame
-        * failure. This seems to sometimes trigger
-        * unnecessary wake up with AR9485 chipsets.
-        */
        set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
-
        REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
 
-
        /*
         * we are relying on a bmiss failure. ensure we have
         * enough threshold to prevent false positives
@@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
        set |= AR_WOW_MAC_INTR_EN;
        REG_RMW(ah, AR_WOW_PATTERN, set, clr);
 
-       /*
-        * For AR9285 and later version of chipsets
-        * enable WoW pattern match for packets less
-        * than 256 bytes for all patterns
-        */
-       if (AR_SREV_9285_12_OR_LATER(ah))
-               REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
-                         AR_WOW_PATTERN_SUPPORTED);
+       REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
+                 AR_WOW_PATTERN_SUPPORTED);
 
        /*
         * Set the power states appropriately and enable PME
@@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
        clr = 0;
        set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
              AR_PMCTRL_PWR_PM_CTRL_ENA;
-       /*
-        * This is needed for AR9300 chipsets to wake-up
-        * the host.
-        */
-       if (AR_SREV_9300_20_OR_LATER(ah))
-               clr = AR_PCIE_PM_CTRL_ENA;
 
+       clr = AR_PCIE_PM_CTRL_ENA;
        REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
 
-       if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
-               /*
-                * this is needed to prevent the chip waking up
-                * the host within 3-4 seconds with certain
-                * platform/BIOS. The fix is to enable
-                * D1 & D3 to match original definition and
-                * also match the OTP value. Anyway this
-                * is more related to SW WOW.
-                */
-               clr = AR_PMCTRL_PWR_STATE_D1D3;
-               REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
-
-               set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
-               REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
-       }
-
+       /*
+        * this is needed to prevent the chip waking up
+        * the host within 3-4 seconds with certain
+        * platform/BIOS. The fix is to enable
+        * D1 & D3 to match original definition and
+        * also match the OTP value. Anyway this
+        * is more related to SW WOW.
+        */
+       clr = AR_PMCTRL_PWR_STATE_D1D3;
+       REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
 
+       set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
+       REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
 
        REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
 
-       if (AR_SREV_9300_20_OR_LATER(ah)) {
-               /* to bring down WOW power low margin */
-               set = BIT(13);
-               REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
-               /* HW WoW */
-               clr = BIT(5);
-               REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
-       }
+       /* to bring down WOW power low margin */
+       set = BIT(13);
+       REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
+       /* HW WoW */
+       clr = BIT(5);
+       REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
 
        ath9k_hw_set_powermode_wow_sleep(ah);
        ah->wow_event_mask = wow_event_mask;
index eab0fcb7ded6452604fd36f645872282735b1170..7e19d9b5214eb7be1b75cf4cd1055fc8d0ee746f 100644 (file)
@@ -125,24 +125,6 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
        list_add_tail(&ac->list, &txq->axq_acq);
 }
 
-static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
-       struct ath_txq *txq = tid->ac->txq;
-
-       WARN_ON(!tid->paused);
-
-       ath_txq_lock(sc, txq);
-       tid->paused = false;
-
-       if (skb_queue_empty(&tid->buf_q))
-               goto unlock;
-
-       ath_tx_queue_tid(txq, tid);
-       ath_txq_schedule(sc, txq);
-unlock:
-       ath_txq_unlock_complete(sc, txq);
-}
-
 static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
 {
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -201,11 +183,6 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
                }
        }
 
-       if (tid->baw_head == tid->baw_tail) {
-               tid->state &= ~AGGR_ADDBA_COMPLETE;
-               tid->state &= ~AGGR_CLEANUP;
-       }
-
        if (sendbar) {
                ath_txq_unlock(sc, txq);
                ath_send_bar(tid, tid->seq_start);
@@ -277,9 +254,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 
                list_add_tail(&bf->list, &bf_head);
 
-               if (fi->retries)
-                       ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
-
+               ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
                ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
        }
 
@@ -491,19 +466,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                tx_info = IEEE80211_SKB_CB(skb);
                fi = get_frame_info(skb);
 
-               if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) {
+               if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+                       /*
+                        * Outside of the current BlockAck window,
+                        * maybe part of a previous session
+                        */
+                       txfail = 1;
+               } else if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) {
                        /* transmit completion, subframe is
                         * acked by block ack */
                        acked_cnt++;
                } else if (!isaggr && txok) {
                        /* transmit completion */
                        acked_cnt++;
-               } else if (tid->state & AGGR_CLEANUP) {
-                       /*
-                        * cleanup in progress, just fail
-                        * the un-acked sub-frames
-                        */
-                       txfail = 1;
                } else if (flush) {
                        txpending = 1;
                } else if (fi->retries < ATH_MAX_SW_RETRIES) {
@@ -527,7 +502,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                if (bf_next != NULL || !bf_last->bf_stale)
                        list_move_tail(&bf->list, &bf_head);
 
-               if (!txpending || (tid->state & AGGR_CLEANUP)) {
+               if (!txpending) {
                        /*
                         * complete the acked-ones/xretried ones; update
                         * block-ack window
@@ -543,6 +518,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
                                !txfail);
                } else {
+                       if (tx_info->flags & IEEE80211_TX_STATUS_EOSP) {
+                               tx_info->flags &= ~IEEE80211_TX_STATUS_EOSP;
+                               ieee80211_sta_eosp(sta);
+                       }
                        /* retry the un-acked ones */
                        if (bf->bf_next == NULL && bf_last->bf_stale) {
                                struct ath_buf *tbf;
@@ -601,9 +580,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                ath_txq_lock(sc, txq);
        }
 
-       if (tid->state & AGGR_CLEANUP)
-               ath_tx_flush_tid(sc, tid);
-
        rcu_read_unlock();
 
        if (needreset)
@@ -620,6 +596,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
                                  struct ath_tx_status *ts, struct ath_buf *bf,
                                  struct list_head *bf_head)
 {
+       struct ieee80211_tx_info *info;
        bool txok, flush;
 
        txok = !(ts->ts_status & ATH9K_TXERR_MASK);
@@ -631,8 +608,12 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
                txq->axq_ampdu_depth--;
 
        if (!bf_isampdu(bf)) {
-               if (!flush)
+               if (!flush) {
+                       info = IEEE80211_SKB_CB(bf->bf_mpdu);
+                       memcpy(info->control.rates, bf->rates,
+                              sizeof(info->control.rates));
                        ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
+               }
                ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
        } else
                ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok);
@@ -676,7 +657,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
 
        skb = bf->bf_mpdu;
        tx_info = IEEE80211_SKB_CB(skb);
-       rates = tx_info->control.rates;
+       rates = bf->rates;
 
        /*
         * Find the lowest frame length among the rate series that will have a
@@ -809,25 +790,20 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
        return ndelim;
 }
 
-static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
-                                            struct ath_txq *txq,
-                                            struct ath_atx_tid *tid,
-                                            struct list_head *bf_q,
-                                            int *aggr_len)
+static struct ath_buf *
+ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
+                       struct ath_atx_tid *tid)
 {
-#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
-       struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
-       int rl = 0, nframes = 0, ndelim, prev_al = 0;
-       u16 aggr_limit = 0, al = 0, bpad = 0,
-               al_delta, h_baw = tid->baw_size / 2;
-       enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
-       struct ieee80211_tx_info *tx_info;
        struct ath_frame_info *fi;
        struct sk_buff *skb;
+       struct ath_buf *bf;
        u16 seqno;
 
-       do {
+       while (1) {
                skb = skb_peek(&tid->buf_q);
+               if (!skb)
+                       break;
+
                fi = get_frame_info(skb);
                bf = fi->bf;
                if (!fi->bf)
@@ -843,10 +819,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                seqno = bf->bf_state.seqno;
 
                /* do not step over block-ack window */
-               if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
-                       status = ATH_AGGR_BAW_CLOSED;
+               if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
                        break;
-               }
 
                if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
                        struct ath_tx_status ts = {};
@@ -860,6 +834,40 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                        continue;
                }
 
+               bf->bf_next = NULL;
+               bf->bf_lastbf = bf;
+               return bf;
+       }
+
+       return NULL;
+}
+
+static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
+                                            struct ath_txq *txq,
+                                            struct ath_atx_tid *tid,
+                                            struct list_head *bf_q,
+                                            int *aggr_len)
+{
+#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
+       struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL;
+       int rl = 0, nframes = 0, ndelim, prev_al = 0;
+       u16 aggr_limit = 0, al = 0, bpad = 0,
+               al_delta, h_baw = tid->baw_size / 2;
+       enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
+       struct ieee80211_tx_info *tx_info;
+       struct ath_frame_info *fi;
+       struct sk_buff *skb;
+
+       do {
+               bf = ath_tx_get_tid_subframe(sc, txq, tid);
+               if (!bf) {
+                       status = ATH_AGGR_BAW_CLOSED;
+                       break;
+               }
+
+               skb = bf->bf_mpdu;
+               fi = get_frame_info(skb);
+
                if (!bf_first)
                        bf_first = bf;
 
@@ -905,7 +913,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
 
                /* link buffers of this frame to the aggregate */
                if (!fi->retries)
-                       ath_tx_addto_baw(sc, tid, seqno);
+                       ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
                bf->bf_state.ndelim = ndelim;
 
                __skb_unlink(skb, &tid->buf_q);
@@ -1113,10 +1121,8 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                             struct ath_txq *txq, int len)
 {
        struct ath_hw *ah = sc->sc_ah;
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
-       struct ath_buf *bf_first = bf;
+       struct ath_buf *bf_first = NULL;
        struct ath_tx_info info;
-       bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR);
 
        memset(&info, 0, sizeof(info));
        info.is_first = true;
@@ -1124,24 +1130,11 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
        info.txpower = MAX_RATE_POWER;
        info.qcu = txq->axq_qnum;
 
-       info.flags = ATH9K_TXDESC_INTREQ;
-       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
-               info.flags |= ATH9K_TXDESC_NOACK;
-       if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
-               info.flags |= ATH9K_TXDESC_LDPC;
-
-       ath_buf_set_rate(sc, bf, &info, len);
-
-       if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
-               info.flags |= ATH9K_TXDESC_CLRDMASK;
-
-       if (bf->bf_state.bfs_paprd)
-               info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S;
-
-
        while (bf) {
                struct sk_buff *skb = bf->bf_mpdu;
+               struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
                struct ath_frame_info *fi = get_frame_info(skb);
+               bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR);
 
                info.type = get_hw_packet_type(skb);
                if (bf->bf_next)
@@ -1149,6 +1142,26 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                else
                        info.link = 0;
 
+               if (!bf_first) {
+                       bf_first = bf;
+
+                       info.flags = ATH9K_TXDESC_INTREQ;
+                       if ((tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ||
+                           txq == sc->tx.uapsdq)
+                               info.flags |= ATH9K_TXDESC_CLRDMASK;
+
+                       if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+                               info.flags |= ATH9K_TXDESC_NOACK;
+                       if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
+                               info.flags |= ATH9K_TXDESC_LDPC;
+
+                       if (bf->bf_state.bfs_paprd)
+                               info.flags |= (u32) bf->bf_state.bfs_paprd <<
+                                             ATH9K_TXDESC_PAPRD_S;
+
+                       ath_buf_set_rate(sc, bf, &info, len);
+               }
+
                info.buf_addr[0] = bf->bf_buf_addr;
                info.buf_len[0] = skb->len;
                info.pkt_len = fi->framelen;
@@ -1158,7 +1171,7 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                if (aggr) {
                        if (bf == bf_first)
                                info.aggr = AGGR_BUF_FIRST;
-                       else if (!bf->bf_next)
+                       else if (bf == bf_first->bf_lastbf)
                                info.aggr = AGGR_BUF_LAST;
                        else
                                info.aggr = AGGR_BUF_MIDDLE;
@@ -1167,6 +1180,9 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                        info.aggr_len = len;
                }
 
+               if (bf == bf_first->bf_lastbf)
+                       bf_first = NULL;
+
                ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
                bf = bf->bf_next;
        }
@@ -1231,9 +1247,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
 
-       if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
-               return -EAGAIN;
-
        /* update ampdu factor/density, they may have changed. This may happen
         * in HT IBSS when a beacon with HT-info is received after the station
         * has already been added.
@@ -1245,7 +1258,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                an->mpdudensity = density;
        }
 
-       txtid->state |= AGGR_ADDBA_PROGRESS;
+       txtid->active = true;
        txtid->paused = true;
        *ssn = txtid->seq_start = txtid->seq_next;
        txtid->bar_index = -1;
@@ -1262,28 +1275,9 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
        struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
        struct ath_txq *txq = txtid->ac->txq;
 
-       if (txtid->state & AGGR_CLEANUP)
-               return;
-
-       if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
-               txtid->state &= ~AGGR_ADDBA_PROGRESS;
-               return;
-       }
-
        ath_txq_lock(sc, txq);
+       txtid->active = false;
        txtid->paused = true;
-
-       /*
-        * If frames are still being transmitted for this TID, they will be
-        * cleaned up during tx completion. To prevent race conditions, this
-        * TID can only be reused after all in-progress subframes have been
-        * completed.
-        */
-       if (txtid->baw_head != txtid->baw_tail)
-               txtid->state |= AGGR_CLEANUP;
-       else
-               txtid->state &= ~AGGR_ADDBA_COMPLETE;
-
        ath_tx_flush_tid(sc, txtid);
        ath_txq_unlock_complete(sc, txq);
 }
@@ -1349,18 +1343,92 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
        }
 }
 
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
+void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
+                       u16 tidno)
 {
-       struct ath_atx_tid *txtid;
+       struct ath_atx_tid *tid;
        struct ath_node *an;
+       struct ath_txq *txq;
 
        an = (struct ath_node *)sta->drv_priv;
+       tid = ATH_AN_2_TID(an, tidno);
+       txq = tid->ac->txq;
 
-       txtid = ATH_AN_2_TID(an, tid);
-       txtid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-       txtid->state |= AGGR_ADDBA_COMPLETE;
-       txtid->state &= ~AGGR_ADDBA_PROGRESS;
-       ath_tx_resume_tid(sc, txtid);
+       ath_txq_lock(sc, txq);
+
+       tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
+       tid->paused = false;
+
+       if (!skb_queue_empty(&tid->buf_q)) {
+               ath_tx_queue_tid(txq, tid);
+               ath_txq_schedule(sc, txq);
+       }
+
+       ath_txq_unlock_complete(sc, txq);
+}
+
+void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta *sta,
+                                  u16 tids, int nframes,
+                                  enum ieee80211_frame_release_type reason,
+                                  bool more_data)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_node *an = (struct ath_node *)sta->drv_priv;
+       struct ath_txq *txq = sc->tx.uapsdq;
+       struct ieee80211_tx_info *info;
+       struct list_head bf_q;
+       struct ath_buf *bf_tail = NULL, *bf;
+       int sent = 0;
+       int i;
+
+       INIT_LIST_HEAD(&bf_q);
+       for (i = 0; tids && nframes; i++, tids >>= 1) {
+               struct ath_atx_tid *tid;
+
+               if (!(tids & 1))
+                       continue;
+
+               tid = ATH_AN_2_TID(an, i);
+               if (tid->paused)
+                       continue;
+
+               ath_txq_lock(sc, tid->ac->txq);
+               while (!skb_queue_empty(&tid->buf_q) && nframes > 0) {
+                       bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
+                       if (!bf)
+                               break;
+
+                       __skb_unlink(bf->bf_mpdu, &tid->buf_q);
+                       list_add_tail(&bf->list, &bf_q);
+                       ath_set_rates(tid->an->vif, tid->an->sta, bf);
+                       ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
+                       bf->bf_state.bf_type &= ~BUF_AGGR;
+                       if (bf_tail)
+                               bf_tail->bf_next = bf;
+
+                       bf_tail = bf;
+                       nframes--;
+                       sent++;
+                       TX_STAT_INC(txq->axq_qnum, a_queued_hw);
+
+                       if (skb_queue_empty(&tid->buf_q))
+                               ieee80211_sta_set_buffered(an->sta, i, false);
+               }
+               ath_txq_unlock_complete(sc, tid->ac->txq);
+       }
+
+       if (list_empty(&bf_q))
+               return;
+
+       info = IEEE80211_SKB_CB(bf_tail->bf_mpdu);
+       info->flags |= IEEE80211_TX_STATUS_EOSP;
+
+       bf = list_first_entry(&bf_q, struct ath_buf, list);
+       ath_txq_lock(sc, txq);
+       ath_tx_fill_desc(sc, bf, txq, 0);
+       ath_tx_txqaddbuf(sc, txq, &bf_q, false);
+       ath_txq_unlock(sc, txq);
 }
 
 /********************/
@@ -1716,8 +1784,9 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
        }
 }
 
-static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
-                             struct sk_buff *skb, struct ath_tx_control *txctl)
+static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
+                             struct ath_atx_tid *tid, struct sk_buff *skb,
+                             struct ath_tx_control *txctl)
 {
        struct ath_frame_info *fi = get_frame_info(skb);
        struct list_head bf_head;
@@ -1730,21 +1799,22 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
         * - seqno is not within block-ack window
         * - h/w queue depth exceeds low water mark
         */
-       if (!skb_queue_empty(&tid->buf_q) || tid->paused ||
-           !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) ||
-           txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) {
+       if ((!skb_queue_empty(&tid->buf_q) || tid->paused ||
+            !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) ||
+            txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) &&
+           txq != sc->tx.uapsdq) {
                /*
                 * Add this frame to software queue for scheduling later
                 * for aggregation.
                 */
-               TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw);
+               TX_STAT_INC(txq->axq_qnum, a_queued_sw);
                __skb_queue_tail(&tid->buf_q, skb);
                if (!txctl->an || !txctl->an->sleeping)
-                       ath_tx_queue_tid(txctl->txq, tid);
+                       ath_tx_queue_tid(txq, tid);
                return;
        }
 
-       bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+       bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
                ieee80211_free_txskb(sc->hw, skb);
                return;
@@ -1759,10 +1829,10 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
        ath_tx_addto_baw(sc, tid, bf->bf_state.seqno);
 
        /* Queue to h/w without aggregation */
-       TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
+       TX_STAT_INC(txq->axq_qnum, a_queued_hw);
        bf->bf_lastbf = bf;
-       ath_tx_fill_desc(sc, bf, txctl->txq, fi->framelen);
-       ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
+       ath_tx_fill_desc(sc, bf, txq, fi->framelen);
+       ath_tx_txqaddbuf(sc, txq, &bf_head, false);
 }
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@@ -1900,22 +1970,16 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
        return bf;
 }
 
-/* Upon failure caller should free skb */
-int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
-                struct ath_tx_control *txctl)
+static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
+                         struct ath_tx_control *txctl)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_sta *sta = txctl->sta;
        struct ieee80211_vif *vif = info->control.vif;
        struct ath_softc *sc = hw->priv;
-       struct ath_txq *txq = txctl->txq;
-       struct ath_atx_tid *tid = NULL;
-       struct ath_buf *bf;
-       int padpos, padsize;
        int frmlen = skb->len + FCS_LEN;
-       u8 tidno;
-       int q;
+       int padpos, padsize;
 
        /* NOTE:  sta can be NULL according to net/mac80211.h */
        if (sta)
@@ -1936,6 +2000,11 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
        }
 
+       if ((vif && vif->type != NL80211_IFTYPE_AP &&
+                   vif->type != NL80211_IFTYPE_AP_VLAN) ||
+           !ieee80211_is_data(hdr->frame_control))
+               info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
        /* Add the padding after the header if this is not already done */
        padpos = ieee80211_hdrlen(hdr->frame_control);
        padsize = padpos & 3;
@@ -1945,16 +2014,34 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
                skb_push(skb, padsize);
                memmove(skb->data, skb->data + padsize, padpos);
-               hdr = (struct ieee80211_hdr *) skb->data;
        }
 
-       if ((vif && vif->type != NL80211_IFTYPE_AP &&
-                   vif->type != NL80211_IFTYPE_AP_VLAN) ||
-           !ieee80211_is_data(hdr->frame_control))
-               info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
-
        setup_frame_info(hw, sta, skb, frmlen);
+       return 0;
+}
 
+
+/* Upon failure caller should free skb */
+int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
+                struct ath_tx_control *txctl)
+{
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = txctl->sta;
+       struct ieee80211_vif *vif = info->control.vif;
+       struct ath_softc *sc = hw->priv;
+       struct ath_txq *txq = txctl->txq;
+       struct ath_atx_tid *tid = NULL;
+       struct ath_buf *bf;
+       u8 tidno;
+       int q;
+       int ret;
+
+       ret = ath_tx_prepare(hw, skb, txctl);
+       if (ret)
+           return ret;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
        /*
         * At this point, the vif, hw_key and sta pointers in the tx control
         * info are no longer valid (overwritten by the ath_frame_info data.
@@ -1970,6 +2057,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                txq->stopped = true;
        }
 
+       if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
+               ath_txq_unlock(sc, txq);
+               txq = sc->tx.uapsdq;
+               ath_txq_lock(sc, txq);
+       }
+
        if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
                tidno = ieee80211_get_qos_ctl(hdr)[0] &
                        IEEE80211_QOS_CTL_TID_MASK;
@@ -1983,11 +2076,11 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 * Try aggregation if it's a unicast data frame
                 * and the destination is HT capable.
                 */
-               ath_tx_send_ampdu(sc, tid, skb, txctl);
+               ath_tx_send_ampdu(sc, txq, tid, skb, txctl);
                goto out;
        }
 
-       bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+       bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
                if (txctl->paprd)
                        dev_kfree_skb_any(skb);
@@ -2002,7 +2095,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                bf->bf_state.bfs_paprd_timestamp = jiffies;
 
        ath_set_rates(vif, sta, bf);
-       ath_tx_send_normal(sc, txctl->txq, tid, skb);
+       ath_tx_send_normal(sc, txq, tid, skb);
 
 out:
        ath_txq_unlock(sc, txq);
@@ -2010,6 +2103,74 @@ out:
        return 0;
 }
 
+void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                struct sk_buff *skb)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_tx_control txctl = {
+               .txq = sc->beacon.cabq
+       };
+       struct ath_tx_info info = {};
+       struct ieee80211_hdr *hdr;
+       struct ath_buf *bf_tail = NULL;
+       struct ath_buf *bf;
+       LIST_HEAD(bf_q);
+       int duration = 0;
+       int max_duration;
+
+       max_duration =
+               sc->cur_beacon_conf.beacon_interval * 1000 *
+               sc->cur_beacon_conf.dtim_period / ATH_BCBUF;
+
+       do {
+               struct ath_frame_info *fi = get_frame_info(skb);
+
+               if (ath_tx_prepare(hw, skb, &txctl))
+                       break;
+
+               bf = ath_tx_setup_buffer(sc, txctl.txq, NULL, skb);
+               if (!bf)
+                       break;
+
+               bf->bf_lastbf = bf;
+               ath_set_rates(vif, NULL, bf);
+               ath_buf_set_rate(sc, bf, &info, fi->framelen);
+               duration += info.rates[0].PktDuration;
+               if (bf_tail)
+                       bf_tail->bf_next = bf;
+
+               list_add_tail(&bf->list, &bf_q);
+               bf_tail = bf;
+               skb = NULL;
+
+               if (duration > max_duration)
+                       break;
+
+               skb = ieee80211_get_buffered_bc(hw, vif);
+       } while(skb);
+
+       if (skb)
+               ieee80211_free_txskb(hw, skb);
+
+       if (list_empty(&bf_q))
+               return;
+
+       bf = list_first_entry(&bf_q, struct ath_buf, list);
+       hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
+
+       if (hdr->frame_control & IEEE80211_FCTL_MOREDATA) {
+               hdr->frame_control &= ~IEEE80211_FCTL_MOREDATA;
+               dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+                       sizeof(*hdr), DMA_TO_DEVICE);
+       }
+
+       ath_txq_lock(sc, txctl.txq);
+       ath_tx_fill_desc(sc, bf, txctl.txq, 0);
+       ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false);
+       TX_STAT_INC(txctl.txq->axq_qnum, queued);
+       ath_txq_unlock(sc, txctl.txq);
+}
+
 /*****************/
 /* TX Completion */
 /*****************/
@@ -2055,7 +2216,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        }
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
+       __skb_queue_tail(&txq->complete_q, skb);
+
        q = skb_get_queue_mapping(skb);
+       if (txq == sc->tx.uapsdq)
+               txq = sc->tx.txq_map[q];
+
        if (txq == sc->tx.txq_map[q]) {
                if (WARN_ON(--txq->pending_frames < 0))
                        txq->pending_frames = 0;
@@ -2066,8 +2232,6 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                        txq->stopped = false;
                }
        }
-
-       __skb_queue_tail(&txq->complete_q, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@ -2409,12 +2573,10 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
                tid->baw_head  = tid->baw_tail = 0;
                tid->sched     = false;
                tid->paused    = false;
-               tid->state &= ~AGGR_CLEANUP;
+               tid->active        = false;
                __skb_queue_head_init(&tid->buf_q);
                acno = TID_TO_WME_AC(tidno);
                tid->ac = &an->ac[acno];
-               tid->state &= ~AGGR_ADDBA_COMPLETE;
-               tid->state &= ~AGGR_ADDBA_PROGRESS;
        }
 
        for (acno = 0, ac = &an->ac[acno];
@@ -2451,8 +2613,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
                }
 
                ath_tid_drain(sc, txq, tid);
-               tid->state &= ~AGGR_ADDBA_COMPLETE;
-               tid->state &= ~AGGR_CLEANUP;
+               tid->active = false;
 
                ath_txq_unlock(sc, txq);
        }
index 9dce106cd6d4a1b963910a8310737be18929867a..8596aba34f96854dfe1700da64b44ef832e5fc9a 100644 (file)
@@ -133,6 +133,9 @@ struct carl9170_sta_tid {
 
        /* Preaggregation reorder queue */
        struct sk_buff_head queue;
+
+       struct ieee80211_sta *sta;
+       struct ieee80211_vif *vif;
 };
 
 #define CARL9170_QUEUE_TIMEOUT         256
index e9010a481dfdf475d61f567bb0f5f11f2e44dded..4a33c6e39ca28be1089aca1275c6e64edda6666d 100644 (file)
@@ -1448,6 +1448,8 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                tid_info->state = CARL9170_TID_STATE_PROGRESS;
                tid_info->tid = tid;
                tid_info->max = sta_info->ampdu_max_len;
+               tid_info->sta = sta;
+               tid_info->vif = vif;
 
                INIT_LIST_HEAD(&tid_info->list);
                INIT_LIST_HEAD(&tid_info->tmp_list);
@@ -1857,6 +1859,7 @@ void *carl9170_alloc(size_t priv_size)
                     IEEE80211_HW_SUPPORTS_PS |
                     IEEE80211_HW_PS_NULLFUNC_STACK |
                     IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
+                    IEEE80211_HW_SUPPORTS_RC_TABLE |
                     IEEE80211_HW_SIGNAL_DBM;
 
        if (!modparam_noht) {
index c61cafa2665b18c5215a953273919a024c5c4473..e3f696ee4d2393b00cbebd38d7f2840c51376149 100644 (file)
@@ -625,7 +625,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
                    msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)))
                        goto unlock;
 
-               sta = __carl9170_get_tx_sta(ar, skb);
+               sta = iter->sta;
                if (WARN_ON(!sta))
                        goto unlock;
 
@@ -866,6 +866,93 @@ static bool carl9170_tx_cts_check(struct ar9170 *ar,
        return false;
 }
 
+static void carl9170_tx_get_rates(struct ar9170 *ar,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_sta *sta,
+                                 struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *info;
+
+       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES);
+       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES > IEEE80211_TX_RATE_TABLE_SIZE);
+
+       info = IEEE80211_SKB_CB(skb);
+
+       ieee80211_get_tx_rates(vif, sta, skb,
+                              info->control.rates,
+                              IEEE80211_TX_MAX_RATES);
+}
+
+static void carl9170_tx_apply_rateset(struct ar9170 *ar,
+                                     struct ieee80211_tx_info *sinfo,
+                                     struct sk_buff *skb)
+{
+       struct ieee80211_tx_rate *txrate;
+       struct ieee80211_tx_info *info;
+       struct _carl9170_tx_superframe *txc = (void *) skb->data;
+       int i;
+       bool ampdu;
+       bool no_ack;
+
+       info = IEEE80211_SKB_CB(skb);
+       ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU);
+       no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
+
+       /* Set the rate control probe flag for all (sub-) frames.
+        * This is because the TX_STATS_AMPDU flag is only set on
+        * the last frame, so it has to be inherited.
+        */
+       info->flags |= (sinfo->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
+
+       /* NOTE: For the first rate, the ERP & AMPDU flags are directly
+        * taken from mac_control. For all fallback rate, the firmware
+        * updates the mac_control flags from the rate info field.
+        */
+       for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
+               __le32 phy_set;
+
+               txrate = &sinfo->control.rates[i];
+               if (txrate->idx < 0)
+                       break;
+
+               phy_set = carl9170_tx_physet(ar, info, txrate);
+               if (i == 0) {
+                       __le16 mac_tmp = cpu_to_le16(0);
+
+                       /* first rate - part of the hw's frame header */
+                       txc->f.phy_control = phy_set;
+
+                       if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS)
+                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+
+                       if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
+                       else if (carl9170_tx_cts_check(ar, txrate))
+                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
+
+                       txc->f.mac_control |= mac_tmp;
+               } else {
+                       /* fallback rates are stored in the firmware's
+                        * retry rate set array.
+                        */
+                       txc->s.rr[i - 1] = phy_set;
+               }
+
+               SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
+                       txrate->count);
+
+               if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+                       txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS <<
+                               CARL9170_TX_SUPER_RI_ERP_PROT_S);
+               else if (carl9170_tx_cts_check(ar, txrate))
+                       txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
+                               CARL9170_TX_SUPER_RI_ERP_PROT_S);
+
+               if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS))
+                       txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU;
+       }
+}
+
 static int carl9170_tx_prepare(struct ar9170 *ar,
                               struct ieee80211_sta *sta,
                               struct sk_buff *skb)
@@ -874,13 +961,10 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
        struct _carl9170_tx_superframe *txc;
        struct carl9170_vif_info *cvif;
        struct ieee80211_tx_info *info;
-       struct ieee80211_tx_rate *txrate;
        struct carl9170_tx_info *arinfo;
        unsigned int hw_queue;
-       int i;
        __le16 mac_tmp;
        u16 len;
-       bool ampdu, no_ack;
 
        BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
        BUILD_BUG_ON(sizeof(struct _carl9170_tx_superdesc) !=
@@ -889,8 +973,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
        BUILD_BUG_ON(sizeof(struct _ar9170_tx_hwdesc) !=
                     AR9170_TX_HWDESC_LEN);
 
-       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES < CARL9170_TX_MAX_RATES);
-
        BUILD_BUG_ON(AR9170_MAX_VIRTUAL_MAC >
                ((CARL9170_TX_SUPER_MISC_VIF_ID >>
                 CARL9170_TX_SUPER_MISC_VIF_ID_S) + 1));
@@ -932,8 +1014,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
        mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &
                               AR9170_TX_MAC_QOS);
 
-       no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
-       if (unlikely(no_ack))
+       if (unlikely(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mac_tmp |= cpu_to_le16(AR9170_TX_MAC_NO_ACK);
 
        if (info->control.hw_key) {
@@ -954,8 +1035,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
                }
        }
 
-       ampdu = !!(info->flags & IEEE80211_TX_CTL_AMPDU);
-       if (ampdu) {
+       if (info->flags & IEEE80211_TX_CTL_AMPDU) {
                unsigned int density, factor;
 
                if (unlikely(!sta || !cvif))
@@ -982,50 +1062,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
                        txc->s.ampdu_settings, factor);
        }
 
-       /*
-        * NOTE: For the first rate, the ERP & AMPDU flags are directly
-        * taken from mac_control. For all fallback rate, the firmware
-        * updates the mac_control flags from the rate info field.
-        */
-       for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
-               __le32 phy_set;
-               txrate = &info->control.rates[i];
-               if (txrate->idx < 0)
-                       break;
-
-               phy_set = carl9170_tx_physet(ar, info, txrate);
-               if (i == 0) {
-                       /* first rate - part of the hw's frame header */
-                       txc->f.phy_control = phy_set;
-
-                       if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS)
-                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-                       if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
-                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
-                       else if (carl9170_tx_cts_check(ar, txrate))
-                               mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
-
-               } else {
-                       /* fallback rates are stored in the firmware's
-                        * retry rate set array.
-                        */
-                       txc->s.rr[i - 1] = phy_set;
-               }
-
-               SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
-                       txrate->count);
-
-               if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
-                       txc->s.ri[i] |= (AR9170_TX_MAC_PROT_RTS <<
-                               CARL9170_TX_SUPER_RI_ERP_PROT_S);
-               else if (carl9170_tx_cts_check(ar, txrate))
-                       txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
-                               CARL9170_TX_SUPER_RI_ERP_PROT_S);
-
-               if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS))
-                       txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU;
-       }
-
        txc->s.len = cpu_to_le16(skb->len);
        txc->f.length = cpu_to_le16(len + FCS_LEN);
        txc->f.mac_control = mac_tmp;
@@ -1086,31 +1122,12 @@ static void carl9170_set_ampdu_params(struct ar9170 *ar, struct sk_buff *skb)
        }
 }
 
-static bool carl9170_tx_rate_check(struct ar9170 *ar, struct sk_buff *_dest,
-                                  struct sk_buff *_src)
-{
-       struct _carl9170_tx_superframe *dest, *src;
-
-       dest = (void *) _dest->data;
-       src = (void *) _src->data;
-
-       /*
-        * The mac80211 rate control algorithm expects that all MPDUs in
-        * an AMPDU share the same tx vectors.
-        * This is not really obvious right now, because the hardware
-        * does the AMPDU setup according to its own rulebook.
-        * Our nicely assembled, strictly monotonic increasing mpdu
-        * chains will be broken up, mashed back together...
-        */
-
-       return (dest->f.phy_control == src->f.phy_control);
-}
-
 static void carl9170_tx_ampdu(struct ar9170 *ar)
 {
        struct sk_buff_head agg;
        struct carl9170_sta_tid *tid_info;
        struct sk_buff *skb, *first;
+       struct ieee80211_tx_info *tx_info_first;
        unsigned int i = 0, done_ampdus = 0;
        u16 seq, queue, tmpssn;
 
@@ -1156,6 +1173,7 @@ retry:
                        goto processed;
                }
 
+               tx_info_first = NULL;
                while ((skb = skb_peek(&tid_info->queue))) {
                        /* strict 0, 1, ..., n - 1, n frame sequence order */
                        if (unlikely(carl9170_get_seq(skb) != seq))
@@ -1166,8 +1184,13 @@ retry:
                            (tid_info->max - 1)))
                                break;
 
-                       if (!carl9170_tx_rate_check(ar, skb, first))
-                               break;
+                       if (!tx_info_first) {
+                               carl9170_tx_get_rates(ar, tid_info->vif,
+                                                     tid_info->sta, first);
+                               tx_info_first = IEEE80211_SKB_CB(first);
+                       }
+
+                       carl9170_tx_apply_rateset(ar, tx_info_first, skb);
 
                        atomic_inc(&ar->tx_ampdu_upload);
                        tid_info->snx = seq = SEQ_NEXT(seq);
@@ -1182,8 +1205,7 @@ retry:
                if (skb_queue_empty(&tid_info->queue) ||
                    carl9170_get_seq(skb_peek(&tid_info->queue)) !=
                    tid_info->snx) {
-                       /*
-                        * stop TID, if A-MPDU frames are still missing,
+                       /* stop TID, if A-MPDU frames are still missing,
                         * or whenever the queue is empty.
                         */
 
@@ -1450,12 +1472,14 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
        struct ar9170 *ar = hw->priv;
        struct ieee80211_tx_info *info;
        struct ieee80211_sta *sta = control->sta;
+       struct ieee80211_vif *vif;
        bool run;
 
        if (unlikely(!IS_STARTED(ar)))
                goto err_free;
 
        info = IEEE80211_SKB_CB(skb);
+       vif = info->control.vif;
 
        if (unlikely(carl9170_tx_prepare(ar, sta, skb)))
                goto err_free;
@@ -1486,6 +1510,8 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
        } else {
                unsigned int queue = skb_get_queue_mapping(skb);
 
+               carl9170_tx_get_rates(ar, vif, sta, skb);
+               carl9170_tx_apply_rateset(ar, info, skb);
                skb_queue_tail(&ar->tx_pending[queue], skb);
        }
 
index ccc4c718f124c2a500410cc9ed16f48841e8ec29..7d077c752dd56ca9e3c3d9cb0aae0c951795cadb 100644 (file)
@@ -42,11 +42,11 @@ static int __ath_regd_init(struct ath_regulatory *reg);
                                NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
 
 /* We allow IBSS on these on a case by case basis by regulatory domain */
-#define ATH9K_5GHZ_5150_5350   REG_RULE(5150-10, 5350+10, 40, 0, 30,\
+#define ATH9K_5GHZ_5150_5350   REG_RULE(5150-10, 5350+10, 80, 0, 30,\
                                NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
-#define ATH9K_5GHZ_5470_5850   REG_RULE(5470-10, 5850+10, 40, 0, 30,\
+#define ATH9K_5GHZ_5470_5850   REG_RULE(5470-10, 5850+10, 80, 0, 30,\
                                NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
-#define ATH9K_5GHZ_5725_5850   REG_RULE(5725-10, 5850+10, 40, 0, 30,\
+#define ATH9K_5GHZ_5725_5850   REG_RULE(5725-10, 5850+10, 80, 0, 30,\
                                NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
 
 #define ATH9K_2GHZ_ALL         ATH9K_2GHZ_CH01_11, \
index 5644ac54facc4ef29e576d870b5d869d9fa8a0a8..ce8c0381825e674c2eca80510761ae186283073f 100644 (file)
@@ -28,7 +28,7 @@ config WIL6210_ISR_COR
          such monitoring impossible.
          Say y unless you debug interrupts
 
-config ATH6KL_TRACING
+config WIL6210_TRACING
        bool "wil6210 tracing support"
        depends on WIL6210
        depends on EVENT_TRACING
index 4eb05d0818c3633520cd85210912368f6754eedd..61c302a6bdeaa38ef1a1d20b3ac1e477db794745 100644 (file)
@@ -402,6 +402,30 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
        return 0;
 }
 
+static int wil_fix_bcon(struct wil6210_priv *wil,
+                       struct cfg80211_beacon_data *bcon)
+{
+       struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
+       size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+       int rc = 0;
+
+       if (bcon->probe_resp_len <= hlen)
+               return 0;
+
+       if (!bcon->proberesp_ies) {
+               bcon->proberesp_ies = f->u.probe_resp.variable;
+               bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
+               rc = 1;
+       }
+       if (!bcon->assocresp_ies) {
+               bcon->assocresp_ies = f->u.probe_resp.variable;
+               bcon->assocresp_ies_len = bcon->probe_resp_len - hlen;
+               rc = 1;
+       }
+
+       return rc;
+}
+
 static int wil_cfg80211_start_ap(struct wiphy *wiphy,
                                 struct net_device *ndev,
                                 struct cfg80211_ap_settings *info)
@@ -423,10 +447,18 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
                             info->ssid, info->ssid_len);
 
+       if (wil_fix_bcon(wil, bcon))
+               wil_dbg_misc(wil, "Fixed bcon\n");
+
        rc = wil_reset(wil);
        if (rc)
                return rc;
 
+       /* Rx VRING. */
+       rc = wil_rx_init(wil);
+       if (rc)
+               return rc;
+
        rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);
        if (rc)
                return rc;
@@ -455,8 +487,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        if (rc)
                return rc;
 
-       /* Rx VRING. After MAC and beacon */
-       rc = wil_rx_init(wil);
 
        netif_carrier_on(ndev);
 
index c97b864667c57db00226daa95e5e53ece033f1aa..0a2844c48a604a6fcf40c3f53e464f645f0d556d 100644 (file)
@@ -286,41 +286,36 @@ static int __wil_up(struct wil6210_priv *wil)
 {
        struct net_device *ndev = wil_to_ndev(wil);
        struct wireless_dev *wdev = wil->wdev;
-       struct ieee80211_channel *channel = wdev->preset_chandef.chan;
        int rc;
-       int bi;
-       u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
 
        rc = wil_reset(wil);
        if (rc)
                return rc;
 
-       /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */
-       wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC);
+       /* Rx VRING. After MAC and beacon */
+       rc = wil_rx_init(wil);
+       if (rc)
+               return rc;
+
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
                wil_dbg_misc(wil, "type: STATION\n");
-               bi = 0;
                ndev->type = ARPHRD_ETHER;
                break;
        case NL80211_IFTYPE_AP:
                wil_dbg_misc(wil, "type: AP\n");
-               bi = 100;
                ndev->type = ARPHRD_ETHER;
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
                wil_dbg_misc(wil, "type: P2P_CLIENT\n");
-               bi = 0;
                ndev->type = ARPHRD_ETHER;
                break;
        case NL80211_IFTYPE_P2P_GO:
                wil_dbg_misc(wil, "type: P2P_GO\n");
-               bi = 100;
                ndev->type = ARPHRD_ETHER;
                break;
        case NL80211_IFTYPE_MONITOR:
                wil_dbg_misc(wil, "type: Monitor\n");
-               bi = 0;
                ndev->type = ARPHRD_IEEE80211_RADIOTAP;
                /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
                break;
@@ -328,36 +323,9 @@ static int __wil_up(struct wil6210_priv *wil)
                return -EOPNOTSUPP;
        }
 
-       /* Apply profile in the following order: */
-       /* SSID and channel for the AP */
-       switch (wdev->iftype) {
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_P2P_GO:
-               if (wdev->ssid_len == 0) {
-                       wil_err(wil, "SSID not set\n");
-                       return -EINVAL;
-               }
-               rc = wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
-               if (rc)
-                       return rc;
-               break;
-       default:
-               break;
-       }
-
        /* MAC address - pre-requisite for other commands */
        wmi_set_mac_address(wil, ndev->dev_addr);
 
-       /* Set up beaconing if required. */
-       if (bi > 0) {
-               rc = wmi_pcp_start(wil, bi, wmi_nettype,
-                                  (channel ? channel->hw_value : 0));
-               if (rc)
-                       return rc;
-       }
-
-       /* Rx VRING. After MAC and beacon */
-       wil_rx_init(wil);
 
        napi_enable(&wil->napi_rx);
        napi_enable(&wil->napi_tx);
index 00dffeda983ec5a8d2c48bdfdc61076cecdae3d9..e1c492b9dfef6e4ec158b6a19e0787572d62fd1e 100644 (file)
@@ -768,18 +768,16 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                wil_err(wil, "Xmit in monitor mode not supported\n");
                goto drop;
        }
-       if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
-               rc = wmi_tx_eapol(wil, skb);
-       } else {
-               /* find vring */
-               vring = wil_find_tx_vring(wil, skb);
-               if (!vring) {
-                       wil_err(wil, "No Tx VRING available\n");
-                       goto drop;
-               }
-               /* set up vring entry */
-               rc = wil_tx_vring(wil, vring, skb);
+
+       /* find vring */
+       vring = wil_find_tx_vring(wil, skb);
+       if (!vring) {
+               wil_err(wil, "No Tx VRING available\n");
+               goto drop;
        }
+       /* set up vring entry */
+       rc = wil_tx_vring(wil, vring, skb);
+
        switch (rc) {
        case 0:
                /* statistics will be updated on the tx_complete */
index 373cf656f5b0a217c86c86dd8995cb63af184ccd..44fdab51de7e52b9c9565c318c2b6eac2df3527e 100644 (file)
@@ -329,7 +329,6 @@ int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
 int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
 int wmi_set_channel(struct wil6210_priv *wil, int channel);
 int wmi_get_channel(struct wil6210_priv *wil, int *channel);
-int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb);
 int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
                       const void *mac_addr);
 int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
index 527ffb5438215b2b1992ee5b570cd0438636ac51..dc8059ad4bab0d6d979d298d22d3bbf913211e85 100644 (file)
@@ -75,10 +75,11 @@ static const struct {
        {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
        {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
        {0x880000, 0x88a000, 0x880000}, /* various RGF */
-       {0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */
+       {0x8c0000, 0x949000, 0x8c0000}, /* trivial mapping for upper area */
        /*
         * 920000..930000 ucode code RAM
         * 930000..932000 ucode data RAM
+        * 932000..949000 back-door debug data
         */
 };
 
@@ -314,8 +315,8 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
 
        wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d\n",
                    data->info.channel, data->info.mcs, data->info.snr);
-       wil_dbg_wmi(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
-                   le16_to_cpu(data->info.stype));
+       wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
+                   le16_to_cpu(fc));
        wil_dbg_wmi(wil, "qid %d mid %d cid %d\n",
                    data->info.qid, data->info.mid, data->info.cid);
 
@@ -739,8 +740,12 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
        if (!wil->secure_pcp)
                cmd.disable_sec = 1;
 
+       /*
+        * Processing time may be huge, in case of secure AP it takes about
+        * 3500ms for FW to start AP
+        */
        rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
-                     WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 100);
+                     WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000);
        if (rc)
                return rc;
 
@@ -834,40 +839,6 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
        return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
 }
 
-int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
-{
-       struct wmi_eapol_tx_cmd *cmd;
-       struct ethhdr *eth;
-       u16 eapol_len = skb->len - ETH_HLEN;
-       void *eapol = skb->data + ETH_HLEN;
-       uint i;
-       int rc;
-
-       skb_set_mac_header(skb, 0);
-       eth = eth_hdr(skb);
-       wil_dbg_wmi(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
-       for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
-               if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0)
-                       goto found_dest;
-       }
-
-       return -EINVAL;
-
- found_dest:
-       /* find out eapol data & len */
-       cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL);
-       if (!cmd)
-               return -EINVAL;
-
-       memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN);
-       cmd->eapol_len = cpu_to_le16(eapol_len);
-       memcpy(cmd->eapol, eapol, eapol_len);
-       rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len);
-       kfree(cmd);
-
-       return rc;
-}
-
 int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
                       const void *mac_addr)
 {
index 830bb1d1f9574a12a3a02536b9485632ebf2dff9..b827d51c30a37b93f1747d7df9b2049aeb97e25f 100644 (file)
@@ -1624,7 +1624,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
 
        netif_carrier_off(dev);
 
-       if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv));
+       if (!proc_create_data("driver/atmel", 0, NULL, &atmel_proc_fops, priv))
                printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
 
        printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n",
index 078e6f3477a9dfb3aa9a1fd67c7cb0fd4c8fa8cb..3f21e0ba39badb430dee5db447d37d17dc332a11 100644 (file)
@@ -28,7 +28,7 @@ config B43
 
 config B43_BCMA
        bool "Support for BCMA bus"
-       depends on B43 && BCMA
+       depends on B43 && (BCMA = y || BCMA = B43)
        default y
 
 config B43_BCMA_EXTRA
@@ -39,7 +39,7 @@ config B43_BCMA_EXTRA
 
 config B43_SSB
        bool
-       depends on B43 && SSB
+       depends on B43 && (SSB = y || SSB = B43)
        default y
 
 # Auto-select SSB PCI-HOST support, if possible
@@ -111,6 +111,7 @@ config B43_PIO
 config B43_PHY_N
        bool "Support for 802.11n (N-PHY) devices"
        depends on B43
+       default y
        ---help---
          Support for the N-PHY.
 
@@ -132,6 +133,7 @@ config B43_PHY_LP
 config B43_PHY_HT
        bool "Support for HT-PHY (high throughput) devices"
        depends on B43 && B43_BCMA
+       default y
        ---help---
          Support for the HT-PHY.
 
index 6dd07e2ec595e851a13190fc43bc980c09a08617..a95b77ab360eaf7761bbb93e2eb92ad45ad13e14 100644 (file)
@@ -2458,7 +2458,7 @@ static void b43_request_firmware(struct work_struct *work)
        for (i = 0; i < B43_NR_FWTYPES; i++) {
                errmsg = ctx->errors[i];
                if (strlen(errmsg))
-                       b43err(dev->wl, errmsg);
+                       b43err(dev->wl, "%s", errmsg);
        }
        b43_print_fw_helptext(dev->wl, 1);
        goto out;
index 28db9cf3967261e71899c0e0952e66679c4d9c40..86cbfe2c7c6cbbf404827a6cfff726b12499cf3f 100644 (file)
@@ -583,6 +583,7 @@ enum brcmf_netif_stop_reason {
  * @bssidx: index of bss associated with this interface.
  * @mac_addr: assigned mac address.
  * @netif_stop: bitmap indicates reason why netif queues are stopped.
+ * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
  * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
  * @pend_8021x_wait: used for signalling change in count.
  */
@@ -598,6 +599,7 @@ struct brcmf_if {
        s32 bssidx;
        u8 mac_addr[ETH_ALEN];
        u8 netif_stop;
+       spinlock_t netif_stop_lock;
        atomic_t pend_8021x_cnt;
        wait_queue_head_t pend_8021x_wait;
 };
index 59c77aa3b9597894385a9b8c4c8d72aa5f6db84f..dd85401063cb1e484fe47f423b91d4bd3f9f39af 100644 (file)
@@ -30,6 +30,7 @@
 #include "dhd_bus.h"
 #include "fwsignal.h"
 #include "dhd_dbg.h"
+#include "tracepoint.h"
 
 struct brcmf_proto_cdc_dcmd {
        __le32 cmd;     /* dongle command value */
@@ -292,6 +293,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
        h->flags2 = 0;
        h->data_offset = offset;
        BDC_SET_IF_IDX(h, ifidx);
+       trace_brcmf_bdchdr(pktbuf->data);
 }
 
 int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
@@ -309,6 +311,7 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
                return -EBADE;
        }
 
+       trace_brcmf_bdchdr(pktbuf->data);
        h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
 
        *ifidx = BDC_GET_IF_IDX(h);
index be0787cab24f4ffc981d7831f1cafcaa15b3d33f..9431af2465f3135fc76d5df370853a3b85a77d67 100644 (file)
@@ -27,7 +27,6 @@
 #include "tracepoint.h"
 
 #define PKTFILTER_BUF_SIZE             128
-#define BRCMF_ARPOL_MODE               0xb     /* agent|snoop|peer_autoreply */
 #define BRCMF_DEFAULT_BCN_TIMEOUT      3
 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME        40
 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
@@ -338,23 +337,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
                goto done;
        }
 
-       /* Try to set and enable ARP offload feature, this may fail */
-       err = brcmf_fil_iovar_int_set(ifp, "arp_ol", BRCMF_ARPOL_MODE);
-       if (err) {
-               brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
-                         BRCMF_ARPOL_MODE, err);
-               err = 0;
-       } else {
-               err = brcmf_fil_iovar_int_set(ifp, "arpoe", 1);
-               if (err) {
-                       brcmf_dbg(TRACE, "failed to enable ARP offload err = %d\n",
-                                 err);
-                       err = 0;
-               } else
-                       brcmf_dbg(TRACE, "successfully enabled ARP offload to 0x%x\n",
-                                 BRCMF_ARPOL_MODE);
-       }
-
        /* Setup packet filter */
        brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
        brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
index 202869cd0932619a54c6f6914ead97b24b8907bf..c37b9d68e458880c36019851a704ee3cbef5d337 100644 (file)
@@ -156,8 +156,11 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
                        "txs_suppr_core:    %u\n"
                        "txs_suppr_ps:      %u\n"
                        "txs_tossed:        %u\n"
+                       "txs_host_tossed:   %u\n"
+                       "bus_flow_block:    %u\n"
+                       "fws_flow_block:    %u\n"
                        "send_pkts:         BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
-                       "fifo_credits_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
+                       "requested_sent:    BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
                        fwstats->header_pulls,
                        fwstats->header_only_pkt,
                        fwstats->tlv_parse_failed,
@@ -176,14 +179,17 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
                        fwstats->txs_supp_core,
                        fwstats->txs_supp_ps,
                        fwstats->txs_tossed,
+                       fwstats->txs_host_tossed,
+                       fwstats->bus_flow_block,
+                       fwstats->fws_flow_block,
                        fwstats->send_pkts[0], fwstats->send_pkts[1],
                        fwstats->send_pkts[2], fwstats->send_pkts[3],
                        fwstats->send_pkts[4],
-                       fwstats->fifo_credits_sent[0],
-                       fwstats->fifo_credits_sent[1],
-                       fwstats->fifo_credits_sent[2],
-                       fwstats->fifo_credits_sent[3],
-                       fwstats->fifo_credits_sent[4]);
+                       fwstats->requested_sent[0],
+                       fwstats->requested_sent[1],
+                       fwstats->requested_sent[2],
+                       fwstats->requested_sent[3],
+                       fwstats->requested_sent[4]);
 
        return simple_read_from_buffer(data, count, ppos, buf, res);
 }
index 009c87bfd9ae45e292af73082e6eccba3e1e3b1e..0af1f5dc583a8fd7dd9a550b6e3e5f585ab64925 100644 (file)
@@ -141,8 +141,7 @@ struct brcmf_fws_stats {
        u32 header_pulls;
        u32 pkt2bus;
        u32 send_pkts[5];
-       u32 fifo_credits_sent[5];
-       u32 fifo_credits_back[6];
+       u32 requested_sent[5];
        u32 generic_error;
        u32 mac_update_failed;
        u32 mac_ps_update_failed;
@@ -158,6 +157,9 @@ struct brcmf_fws_stats {
        u32 txs_supp_core;
        u32 txs_supp_ps;
        u32 txs_tossed;
+       u32 txs_host_tossed;
+       u32 bus_flow_block;
+       u32 fws_flow_block;
 };
 
 struct brcmf_pub;
index 59c25463e4285e620aab84d31cfb9c4ed9b7ced1..8c402e7b97eb8b861459e69ea8c2f287f46948c5 100644 (file)
@@ -179,7 +179,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
        struct brcmf_pub *drvr = ifp->drvr;
        struct ethhdr *eh;
 
-       brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
+       brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
 
        /* Can the device send data? */
        if (drvr->bus_if->state != BRCMF_BUS_DATA) {
@@ -240,11 +240,15 @@ done:
 void brcmf_txflowblock_if(struct brcmf_if *ifp,
                          enum brcmf_netif_stop_reason reason, bool state)
 {
+       unsigned long flags;
+
        if (!ifp)
                return;
 
        brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
                  ifp->bssidx, ifp->netif_stop, reason, state);
+
+       spin_lock_irqsave(&ifp->netif_stop_lock, flags);
        if (state) {
                if (!ifp->netif_stop)
                        netif_stop_queue(ifp->ndev);
@@ -254,6 +258,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
                if (!ifp->netif_stop)
                        netif_wake_queue(ifp->ndev);
        }
+       spin_unlock_irqrestore(&ifp->netif_stop_lock, flags);
 }
 
 void brcmf_txflowblock(struct device *dev, bool state)
@@ -264,9 +269,14 @@ void brcmf_txflowblock(struct device *dev, bool state)
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       for (i = 0; i < BRCMF_MAX_IFS; i++)
-               brcmf_txflowblock_if(drvr->iflist[i],
-                                    BRCMF_NETIF_STOP_REASON_BLOCK_BUS, state);
+       if (brcmf_fws_fc_active(drvr->fws)) {
+               brcmf_fws_bus_blocked(drvr, state);
+       } else {
+               for (i = 0; i < BRCMF_MAX_IFS; i++)
+                       brcmf_txflowblock_if(drvr->iflist[i],
+                                            BRCMF_NETIF_STOP_REASON_BLOCK_BUS,
+                                            state);
+       }
 }
 
 void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
@@ -280,7 +290,7 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
        u8 ifidx;
        int ret;
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(DATA, "Enter\n");
 
        skb_queue_walk_safe(skb_list, skb, pnext) {
                skb_unlink(skb, skb_list);
@@ -630,7 +640,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
        /* set appropriate operations */
        ndev->netdev_ops = &brcmf_netdev_ops_pri;
 
-       ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
+       ndev->hard_header_len += drvr->hdrlen;
        ndev->ethtool_ops = &brcmf_ethtool_ops;
 
        drvr->rxsz = ndev->mtu + ndev->hard_header_len +
@@ -653,10 +663,13 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 
        brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
 
+       ndev->destructor = free_netdev;
        return 0;
 
 fail:
+       drvr->iflist[ifp->bssidx] = NULL;
        ndev->netdev_ops = NULL;
+       free_netdev(ndev);
        return -EBADE;
 }
 
@@ -720,6 +733,9 @@ static int brcmf_net_p2p_attach(struct brcmf_if *ifp)
        return 0;
 
 fail:
+       ifp->drvr->iflist[ifp->bssidx] = NULL;
+       ndev->netdev_ops = NULL;
+       free_netdev(ndev);
        return -EBADE;
 }
 
@@ -773,6 +789,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
        ifp->bssidx = bssidx;
 
        init_waitqueue_head(&ifp->pend_8021x_wait);
+       spin_lock_init(&ifp->netif_stop_lock);
 
        if (mac_addr != NULL)
                memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
@@ -788,6 +805,7 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
        struct brcmf_if *ifp;
 
        ifp = drvr->iflist[bssidx];
+       drvr->iflist[bssidx] = NULL;
        if (!ifp) {
                brcmf_err("Null interface, idx=%d\n", bssidx);
                return;
@@ -808,15 +826,13 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
                        cancel_work_sync(&ifp->setmacaddr_work);
                        cancel_work_sync(&ifp->multicast_work);
                }
-
+               /* unregister will take care of freeing it */
                unregister_netdev(ifp->ndev);
                if (bssidx == 0)
                        brcmf_cfg80211_detach(drvr->config);
-               free_netdev(ifp->ndev);
        } else {
                kfree(ifp);
        }
-       drvr->iflist[bssidx] = NULL;
 }
 
 int brcmf_attach(uint bus_hdrlen, struct device *dev)
@@ -925,8 +941,10 @@ fail:
                        brcmf_fws_del_interface(ifp);
                        brcmf_fws_deinit(drvr);
                }
-               free_netdev(ifp->ndev);
-               drvr->iflist[0] = NULL;
+               if (drvr->iflist[0]) {
+                       free_netdev(ifp->ndev);
+                       drvr->iflist[0] = NULL;
+               }
                if (p2p_ifp) {
                        free_netdev(p2p_ifp->ndev);
                        drvr->iflist[1] = NULL;
@@ -934,7 +952,8 @@ fail:
                return ret;
        }
        if ((brcmf_p2p_enable) && (p2p_ifp))
-               brcmf_net_p2p_attach(p2p_ifp);
+               if (brcmf_net_p2p_attach(p2p_ifp) < 0)
+                       brcmf_p2p_enable = 0;
 
        return 0;
 }
index d2487518bd2a6a553a635f5c9d0a1e6996f66594..6f3d181659effaf4f29a259821c54ee4c4093293 100644 (file)
@@ -2369,12 +2369,12 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
        } else {
                ret = 0;
        }
-       spin_unlock_bh(&bus->txqlock);
 
        if (pktq_len(&bus->txq) >= TXHI) {
                bus->txoff = true;
                brcmf_txflowblock(bus->sdiodev->dev, true);
        }
+       spin_unlock_bh(&bus->txqlock);
 
 #ifdef DEBUG
        if (pktq_plen(&bus->txq, prec) > qcount[prec])
index 5a64280e64850867e2a4590050f024687e28749e..83ee53a7c76eae14073ef3e78850663879d71371 100644 (file)
@@ -202,7 +202,8 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
                        return;
                brcmf_fws_add_interface(ifp);
                if (!drvr->fweh.evt_handler[BRCMF_E_IF])
-                       err = brcmf_net_attach(ifp, false);
+                       if (brcmf_net_attach(ifp, false) < 0)
+                               return;
        }
 
        if (ifevent->action == BRCMF_E_IF_CHANGE)
index 0f2c83bc95dc5f7b769f9774d737638c72d39da3..665ef69e974b43c05ca802677fd6c36ce677baf9 100644 (file)
 
 #define BRCMF_FIL_ACTION_FRAME_SIZE    1800
 
+/* ARP Offload feature flags for arp_ol iovar */
+#define BRCMF_ARP_OL_AGENT             0x00000001
+#define BRCMF_ARP_OL_SNOOP             0x00000002
+#define BRCMF_ARP_OL_HOST_AUTO_REPLY   0x00000004
+#define BRCMF_ARP_OL_PEER_AUTO_REPLY   0x00000008
+
 
 enum brcmf_fil_p2p_if_types {
        BRCMF_FIL_P2P_IF_CLIENT,
index 5352dc1fdf3ca6c03b48e4c27952d32da25eaa2f..70f70cea7f7d2fbf07561b2733d2ec8319832aab 100644 (file)
@@ -157,11 +157,13 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
  * @BRCMF_FWS_SKBSTATE_NEW: sk_buff is newly arrived in the driver.
  * @BRCMF_FWS_SKBSTATE_DELAYED: sk_buff had to wait on queue.
  * @BRCMF_FWS_SKBSTATE_SUPPRESSED: sk_buff has been suppressed by firmware.
+ * @BRCMF_FWS_SKBSTATE_TIM: allocated for TIM update info.
  */
 enum brcmf_fws_skb_state {
        BRCMF_FWS_SKBSTATE_NEW,
        BRCMF_FWS_SKBSTATE_DELAYED,
-       BRCMF_FWS_SKBSTATE_SUPPRESSED
+       BRCMF_FWS_SKBSTATE_SUPPRESSED,
+       BRCMF_FWS_SKBSTATE_TIM
 };
 
 /**
@@ -193,9 +195,8 @@ struct brcmf_skbuff_cb {
  *     b[11]  - packet sent upon firmware request.
  *     b[10]  - packet only contains signalling data.
  *     b[9]   - packet is a tx packet.
- *     b[8]   - packet uses FIFO credit (non-pspoll).
+ *     b[8]   - packet used requested credit
  *     b[7]   - interface in AP mode.
- *     b[6:4] - AC FIFO number.
  *     b[3:0] - interface index.
  */
 #define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK      0x0800
@@ -204,12 +205,10 @@ struct brcmf_skbuff_cb {
 #define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT   10
 #define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK        0x0200
 #define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT      9
-#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK    0x0100
-#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_SHIFT   8
+#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_MASK     0x0100
+#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_SHIFT    8
 #define BRCMF_SKB_IF_FLAGS_IF_AP_MASK          0x0080
 #define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT         7
-#define BRCMF_SKB_IF_FLAGS_FIFO_MASK           0x0070
-#define BRCMF_SKB_IF_FLAGS_FIFO_SHIFT          4
 #define BRCMF_SKB_IF_FLAGS_INDEX_MASK          0x000f
 #define BRCMF_SKB_IF_FLAGS_INDEX_SHIFT         0
 
@@ -246,7 +245,7 @@ struct brcmf_skbuff_cb {
 #define BRCMF_SKB_HTOD_TAG_HSLOT_MASK                  0x00ffff00
 #define BRCMF_SKB_HTOD_TAG_HSLOT_SHIFT                 8
 #define BRCMF_SKB_HTOD_TAG_FREERUN_MASK                        0x000000ff
-#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT                       0
+#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT               0
 
 #define brcmf_skb_htod_tag_set_field(skb, field, value) \
        brcmu_maskset32(&(brcmf_skbcb(skb)->htod), \
@@ -278,6 +277,7 @@ struct brcmf_skbuff_cb {
 /**
  * enum brcmf_fws_fifo - fifo indices used by dongle firmware.
  *
+ * @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background.
  * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
  * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
  * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
@@ -287,7 +287,8 @@ struct brcmf_skbuff_cb {
  * @BRCMF_FWS_FIFO_COUNT: number of fifos.
  */
 enum brcmf_fws_fifo {
-       BRCMF_FWS_FIFO_AC_BK,
+       BRCMF_FWS_FIFO_FIRST,
+       BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
        BRCMF_FWS_FIFO_AC_BE,
        BRCMF_FWS_FIFO_AC_VI,
        BRCMF_FWS_FIFO_AC_VO,
@@ -307,12 +308,15 @@ enum brcmf_fws_fifo {
  *     firmware suppress the packet as device is already in PS mode.
  * @BRCMF_FWS_TXSTATUS_FW_TOSSED:
  *     firmware tossed the packet.
+ * @BRCMF_FWS_TXSTATUS_HOST_TOSSED:
+ *     host tossed the packet.
  */
 enum brcmf_fws_txstatus {
        BRCMF_FWS_TXSTATUS_DISCARD,
        BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
        BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
-       BRCMF_FWS_TXSTATUS_FW_TOSSED
+       BRCMF_FWS_TXSTATUS_FW_TOSSED,
+       BRCMF_FWS_TXSTATUS_HOST_TOSSED
 };
 
 enum brcmf_fws_fcmode {
@@ -343,6 +347,7 @@ enum brcmf_fws_mac_desc_state {
  * @transit_count: packet in transit to firmware.
  */
 struct brcmf_fws_mac_descriptor {
+       char name[16];
        u8 occupied;
        u8 mac_handle;
        u8 interface_id;
@@ -356,7 +361,6 @@ struct brcmf_fws_mac_descriptor {
        u8 seq[BRCMF_FWS_FIFO_COUNT];
        struct pktq psq;
        int transit_count;
-       int suppress_count;
        int suppr_transit_count;
        bool send_tim_signal;
        u8 traffic_pending_bmp;
@@ -383,12 +387,10 @@ enum brcmf_fws_hanger_item_state {
  * struct brcmf_fws_hanger_item - single entry for tx pending packet.
  *
  * @state: entry is either free or occupied.
- * @gen: generation.
  * @pkt: packet itself.
  */
 struct brcmf_fws_hanger_item {
        enum brcmf_fws_hanger_item_state state;
-       u8 gen;
        struct sk_buff *pkt;
 };
 
@@ -434,6 +436,8 @@ struct brcmf_fws_info {
        u32 fifo_credit_map;
        u32 fifo_delay_map;
        unsigned long borrow_defer_timestamp;
+       bool bus_flow_blocked;
+       bool creditmap_received;
 };
 
 /*
@@ -507,7 +511,6 @@ static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
 {
        int i;
 
-       brcmf_dbg(TRACE, "enter\n");
        memset(hanger, 0, sizeof(*hanger));
        for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
                hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
@@ -517,7 +520,6 @@ static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
 {
        u32 i;
 
-       brcmf_dbg(TRACE, "enter\n");
        i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
 
        while (i != h->slot_pos) {
@@ -533,14 +535,12 @@ static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
        h->failed_slotfind++;
        i = BRCMF_FWS_HANGER_MAXITEMS;
 done:
-       brcmf_dbg(TRACE, "exit: %d\n", i);
        return i;
 }
 
 static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
-                                          struct sk_buff *pkt, u32 slot_id)
+                                   struct sk_buff *pkt, u32 slot_id)
 {
-       brcmf_dbg(TRACE, "enter\n");
        if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
                return -ENOENT;
 
@@ -560,7 +560,6 @@ static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
                                          u32 slot_id, struct sk_buff **pktout,
                                          bool remove_item)
 {
-       brcmf_dbg(TRACE, "enter\n");
        if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
                return -ENOENT;
 
@@ -574,23 +573,18 @@ static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
        if (remove_item) {
                h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
                h->items[slot_id].pkt = NULL;
-               h->items[slot_id].gen = 0xff;
                h->popped++;
        }
        return 0;
 }
 
 static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
-                                                  u32 slot_id, u8 gen)
+                                           u32 slot_id)
 {
-       brcmf_dbg(TRACE, "enter\n");
-
        if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
                return -ENOENT;
 
-       h->items[slot_id].gen = gen;
-
-       if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_INUSE) {
+       if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
                brcmf_err("entry not in use\n");
                return -EINVAL;
        }
@@ -599,25 +593,6 @@ static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
        return 0;
 }
 
-static int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
-                                             struct sk_buff *pkt, u32 slot_id,
-                                             int *gen)
-{
-       brcmf_dbg(TRACE, "enter\n");
-       *gen = 0xff;
-
-       if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
-               return -ENOENT;
-
-       if (hanger->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
-               brcmf_err("slot not in use\n");
-               return -EINVAL;
-       }
-
-       *gen = hanger->items[slot_id].gen;
-       return 0;
-}
-
 static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
                                     bool (*fn)(struct sk_buff *, void *),
                                     int ifidx)
@@ -627,7 +602,6 @@ static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
        int i;
        enum brcmf_fws_hanger_item_state s;
 
-       brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
        for (i = 0; i < ARRAY_SIZE(h->items); i++) {
                s = h->items[i].state;
                if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
@@ -644,6 +618,19 @@ static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
        }
 }
 
+static void brcmf_fws_macdesc_set_name(struct brcmf_fws_info *fws,
+                                      struct brcmf_fws_mac_descriptor *desc)
+{
+       if (desc == &fws->desc.other)
+               strlcpy(desc->name, "MAC-OTHER", sizeof(desc->name));
+       else if (desc->mac_handle)
+               scnprintf(desc->name, sizeof(desc->name), "MAC-%d:%d",
+                         desc->mac_handle, desc->interface_id);
+       else
+               scnprintf(desc->name, sizeof(desc->name), "MACIF:%d",
+                         desc->interface_id);
+}
+
 static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
                                          u8 *addr, u8 ifidx)
 {
@@ -652,6 +639,7 @@ static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
        desc->occupied = 1;
        desc->state = BRCMF_FWS_STATE_OPEN;
        desc->requested_credit = 0;
+       desc->requested_packet = 0;
        /* depending on use may need ifp->bssidx instead */
        desc->interface_id = ifidx;
        desc->ac_bitmap = 0xff; /* update this when handling APSD */
@@ -667,6 +655,7 @@ void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc)
        desc->occupied = 0;
        desc->state = BRCMF_FWS_STATE_CLOSE;
        desc->requested_credit = 0;
+       desc->requested_packet = 0;
 }
 
 static struct brcmf_fws_mac_descriptor *
@@ -675,7 +664,6 @@ brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
        struct brcmf_fws_mac_descriptor *entry;
        int i;
 
-       brcmf_dbg(TRACE, "enter: ea=%pM\n", ea);
        if (ea == NULL)
                return ERR_PTR(-EINVAL);
 
@@ -695,31 +683,23 @@ brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, struct brcmf_if *ifp,
 {
        struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
        bool multicast;
-       enum nl80211_iftype iftype;
-
-       brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
 
        multicast = is_multicast_ether_addr(da);
-       iftype = brcmf_cfg80211_get_iftype(ifp);
 
-       /* Multicast destination and P2P clients get the interface entry.
-        * STA gets the interface entry if there is no exact match. For
-        * example, TDLS destinations have their own entry.
+       /* Multicast destination, STA and P2P clients get the interface entry.
+        * STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations
+        * have their own entry.
         */
-       entry = NULL;
-       if ((multicast || iftype == NL80211_IFTYPE_STATION ||
-            iftype == NL80211_IFTYPE_P2P_CLIENT) && ifp->fws_desc)
+       if (multicast && ifp->fws_desc) {
                entry = ifp->fws_desc;
-
-       if (entry != NULL && iftype != NL80211_IFTYPE_STATION)
                goto done;
+       }
 
        entry = brcmf_fws_mac_descriptor_lookup(fws, da);
        if (IS_ERR(entry))
-               entry = &fws->desc.other;
+               entry = ifp->fws_desc;
 
 done:
-       brcmf_dbg(TRACE, "exit: entry=%p\n", entry);
        return entry;
 }
 
@@ -752,11 +732,7 @@ static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_info *fws,
                                       struct brcmf_fws_mac_descriptor *entry,
                                       int ifidx)
 {
-       brcmf_dbg(TRACE, "enter: entry=(ea=%pM, ifid=%d), ifidx=%d\n",
-                 entry->ea, entry->interface_id, ifidx);
        if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
-               brcmf_dbg(TRACE, "flush psq: ifidx=%d, qlen=%d\n",
-                         ifidx, entry->psq.len);
                brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
                entry->occupied = !!(entry->psq.len);
        }
@@ -772,7 +748,6 @@ static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
        int prec;
        u32 hslot;
 
-       brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
        txq = brcmf_bus_gettxq(fws->drvr->bus_if);
        if (IS_ERR(txq)) {
                brcmf_dbg(TRACE, "no txq to clean up\n");
@@ -798,7 +773,6 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
        struct brcmf_fws_mac_descriptor *table;
        bool (*matchfn)(struct sk_buff *, void *) = NULL;
 
-       brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
        if (fws == NULL)
                return;
 
@@ -815,44 +789,115 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
        brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
 }
 
-static void brcmf_fws_tim_update(struct brcmf_fws_info *ctx,
-                                struct brcmf_fws_mac_descriptor *entry,
-                                int prec)
+static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
 {
-       brcmf_dbg(TRACE, "enter: ea=%pM\n", entry->ea);
-       if (entry->state == BRCMF_FWS_STATE_CLOSE) {
-               /* check delayedQ and suppressQ in one call using bitmap */
-               if (brcmu_pktq_mlen(&entry->psq, 3 << (prec * 2)) == 0)
-                       entry->traffic_pending_bmp =
-                               entry->traffic_pending_bmp & ~NBITVAL(prec);
-               else
-                       entry->traffic_pending_bmp =
-                               entry->traffic_pending_bmp | NBITVAL(prec);
+       struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+       u8 *wlh;
+       u16 data_offset = 0;
+       u8 fillers;
+       __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
+
+       brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u (%u), pkttag=0x%08X, hslot=%d\n",
+                 entry->ea, entry->interface_id,
+                 brcmf_skb_if_flags_get_field(skb, INDEX),
+                 le32_to_cpu(pkttag), (le32_to_cpu(pkttag) >> 8) & 0xffff);
+       if (entry->send_tim_signal)
+               data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+
+       /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
+       data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
+       fillers = round_up(data_offset, 4) - data_offset;
+       data_offset += fillers;
+
+       skb_push(skb, data_offset);
+       wlh = skb->data;
+
+       wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
+       wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
+       memcpy(&wlh[2], &pkttag, sizeof(pkttag));
+       wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
+
+       if (entry->send_tim_signal) {
+               entry->send_tim_signal = 0;
+               wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
+               wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+               wlh[2] = entry->mac_handle;
+               wlh[3] = entry->traffic_pending_bmp;
+               brcmf_dbg(TRACE, "adding TIM info: %02X:%02X:%02X:%02X\n",
+                         wlh[0], wlh[1], wlh[2], wlh[3]);
+               wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
+               entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
        }
-       /* request a TIM update to firmware at the next piggyback opportunity */
+       if (fillers)
+               memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
+
+       brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
+                           data_offset >> 2, skb);
+       return 0;
+}
+
+static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
+                                struct brcmf_fws_mac_descriptor *entry,
+                                int prec, bool send_immediately)
+{
+       struct sk_buff *skb;
+       struct brcmf_bus *bus;
+       struct brcmf_skbuff_cb *skcb;
+       s32 err;
+       u32 len;
+
+       /* check delayedQ and suppressQ in one call using bitmap */
+       if (brcmu_pktq_mlen(&entry->psq, 3 << (prec * 2)) == 0)
+               entry->traffic_pending_bmp &= ~NBITVAL(prec);
+       else
+               entry->traffic_pending_bmp |= NBITVAL(prec);
+
+       entry->send_tim_signal = false;
        if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
                entry->send_tim_signal = true;
+       if (send_immediately && entry->send_tim_signal &&
+           entry->state == BRCMF_FWS_STATE_CLOSE) {
+               /* create a dummy packet and sent that. The traffic          */
+               /* bitmap info will automatically be attached to that packet */
+               len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
+                     BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
+                     4 + fws->drvr->hdrlen;
+               skb = brcmu_pkt_buf_get_skb(len);
+               if (skb == NULL)
+                       return false;
+               skb_pull(skb, len);
+               skcb = brcmf_skbcb(skb);
+               skcb->mac = entry;
+               skcb->state = BRCMF_FWS_SKBSTATE_TIM;
+               bus = fws->drvr->bus_if;
+               err = brcmf_fws_hdrpush(fws, skb);
+               if (err == 0)
+                       err = brcmf_bus_txdata(bus, skb);
+               if (err)
+                       brcmu_pkt_buf_free_skb(skb);
+               return true;
+       }
+       return false;
 }
 
 static void
 brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
                             u8 if_id)
 {
-       struct brcmf_if *ifp = fws->drvr->iflist[if_id];
+       struct brcmf_if *ifp = fws->drvr->iflist[!if_id ? 0 : if_id + 1];
 
        if (WARN_ON(!ifp))
                return;
 
-       brcmf_dbg(TRACE,
-                 "enter: bssidx=%d, ifidx=%d\n", ifp->bssidx, ifp->ifidx);
-
        if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
            pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
                brcmf_txflowblock_if(ifp,
                                     BRCMF_NETIF_STOP_REASON_FWS_FC, false);
        if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
-           pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER)
+           pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER) {
+               fws->stats.fws_flow_block++;
                brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
+       }
        return;
 }
 
@@ -876,8 +921,9 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
 
        entry = &fws->desc.nodes[mac_handle & 0x1F];
        if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
-               brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx);
                if (entry->occupied) {
+                       brcmf_dbg(TRACE, "deleting %s mac %pM\n",
+                                 entry->name, addr);
                        brcmf_fws_mac_desc_cleanup(fws, entry, -1);
                        brcmf_fws_clear_mac_descriptor(entry);
                } else
@@ -885,25 +931,28 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
                return 0;
        }
 
-       brcmf_dbg(TRACE,
-                 "add mac %pM handle %u idx %d\n", addr, mac_handle, ifidx);
        existing = brcmf_fws_mac_descriptor_lookup(fws, addr);
        if (IS_ERR(existing)) {
                if (!entry->occupied) {
                        entry->mac_handle = mac_handle;
                        brcmf_fws_init_mac_descriptor(entry, addr, ifidx);
+                       brcmf_fws_macdesc_set_name(fws, entry);
                        brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
                                        BRCMF_FWS_PSQ_LEN);
+                       brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
                } else {
                        fws->stats.mac_update_failed++;
                }
        } else {
                if (entry != existing) {
-                       brcmf_dbg(TRACE, "relocate mac\n");
+                       brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
                        memcpy(entry, existing,
                               offsetof(struct brcmf_fws_mac_descriptor, psq));
                        entry->mac_handle = mac_handle;
                        brcmf_fws_clear_mac_descriptor(existing);
+                       brcmf_fws_macdesc_set_name(fws, entry);
+                       brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
+                                 addr);
                } else {
                        brcmf_dbg(TRACE, "use existing\n");
                        WARN_ON(entry->mac_handle != mac_handle);
@@ -918,7 +967,6 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
 {
        struct brcmf_fws_mac_descriptor *entry;
        u8 mac_handle;
-       int i;
 
        mac_handle = data[0];
        entry = &fws->desc.nodes[mac_handle & 0x1F];
@@ -926,16 +974,18 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
                fws->stats.mac_ps_update_failed++;
                return -ESRCH;
        }
-
-       /* a state update should wipe old credits? */
+       /* a state update should wipe old credits */
        entry->requested_credit = 0;
+       entry->requested_packet = 0;
        if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
                entry->state = BRCMF_FWS_STATE_OPEN;
                return BRCMF_FWS_RET_OK_SCHEDULE;
        } else {
                entry->state = BRCMF_FWS_STATE_CLOSE;
-               for (i = BRCMF_FWS_FIFO_AC_BE; i < NL80211_NUM_ACS; i++)
-                       brcmf_fws_tim_update(fws, entry, i);
+               brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
+               brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
+               brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
+               brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
        }
        return BRCMF_FWS_RET_OK_NOSCHEDULE;
 }
@@ -949,7 +999,6 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
 
        ifidx = data[0];
 
-       brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
        if (ifidx >= BRCMF_MAX_IFS) {
                ret = -ERANGE;
                goto fail;
@@ -961,6 +1010,8 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
                goto fail;
        }
 
+       brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
+                 entry->name);
        switch (type) {
        case BRCMF_FWS_TYPE_INTERFACE_OPEN:
                entry->state = BRCMF_FWS_STATE_OPEN;
@@ -991,6 +1042,9 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
                return -ESRCH;
        }
 
+       brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
+                 brcmf_fws_get_tlv_name(type), type, entry->name,
+                 data[0], data[2]);
        if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
                entry->requested_credit = data[0];
        else
@@ -1000,6 +1054,37 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
        return BRCMF_FWS_RET_OK_SCHEDULE;
 }
 
+static void
+brcmf_fws_macdesc_use_req_credit(struct brcmf_fws_mac_descriptor *entry,
+                                struct sk_buff *skb)
+{
+       if (entry->requested_credit > 0) {
+               entry->requested_credit--;
+               brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
+               brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
+               if (entry->state != BRCMF_FWS_STATE_CLOSE)
+                       brcmf_err("requested credit set while mac not closed!\n");
+       } else if (entry->requested_packet > 0) {
+               entry->requested_packet--;
+               brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
+               brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
+               if (entry->state != BRCMF_FWS_STATE_CLOSE)
+                       brcmf_err("requested packet set while mac not closed!\n");
+       } else {
+               brcmf_skb_if_flags_set_field(skb, REQUESTED, 0);
+               brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
+       }
+}
+
+static void brcmf_fws_macdesc_return_req_credit(struct sk_buff *skb)
+{
+       struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+
+       if ((brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) &&
+           (entry->state == BRCMF_FWS_STATE_CLOSE))
+               entry->requested_credit++;
+}
+
 static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
                                     u8 fifo, u8 credits)
 {
@@ -1010,6 +1095,8 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
        if (!credits)
                return;
 
+       fws->fifo_credit_map |= 1 << fifo;
+
        if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
            (fws->credits_borrowed[0])) {
                for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
@@ -1031,7 +1118,6 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
                }
        }
 
-       fws->fifo_credit_map |= 1 << fifo;
        fws->fifo_credit[fifo] += credits;
 }
 
@@ -1042,27 +1128,6 @@ static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
                queue_work(fws->fws_wq, &fws->fws_dequeue_work);
 }
 
-static void brcmf_skb_pick_up_credit(struct brcmf_fws_info *fws, int fifo,
-                                    struct sk_buff *p)
-{
-       struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(p)->mac;
-
-       if (brcmf_skbcb(p)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
-               if (fws->fcmode != BRCMF_FWS_FCMODE_IMPLIED_CREDIT)
-                       return;
-               brcmf_fws_return_credits(fws, fifo, 1);
-       } else {
-               /*
-                * if this packet did not count against FIFO credit, it
-                * must have taken a requested_credit from the destination
-                * entry (for pspoll etc.)
-                */
-               if (!brcmf_skb_if_flags_get_field(p, REQUESTED))
-                       entry->requested_credit++;
-       }
-       brcmf_fws_schedule_deq(fws);
-}
-
 static int brcmf_fws_enq(struct brcmf_fws_info *fws,
                         enum brcmf_fws_skb_state state, int fifo,
                         struct sk_buff *p)
@@ -1078,7 +1143,7 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,
                return -ENOENT;
        }
 
-       brcmf_dbg(TRACE, "enter: ea=%pM, qlen=%d\n", entry->ea, entry->psq.len);
+       brcmf_dbg(DATA, "enter: fifo %d skb %p\n", fifo, p);
        if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
                prec += 1;
                qfull_stat = &fws->stats.supprq_full_error;
@@ -1095,14 +1160,12 @@ static int brcmf_fws_enq(struct brcmf_fws_info *fws,
 
        /* update the sk_buff state */
        brcmf_skbcb(p)->state = state;
-       if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
-               entry->suppress_count++;
 
        /*
         * A packet has been pushed so update traffic
         * availability bitmap, if applicable
         */
-       brcmf_fws_tim_update(fws, entry, fifo);
+       brcmf_fws_tim_update(fws, entry, fifo, true);
        brcmf_fws_flow_control_check(fws, &entry->psq,
                                     brcmf_skb_if_flags_get_field(p, INDEX));
        return 0;
@@ -1113,7 +1176,6 @@ static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
        struct brcmf_fws_mac_descriptor *table;
        struct brcmf_fws_mac_descriptor *entry;
        struct sk_buff *p;
-       int use_credit = 1;
        int num_nodes;
        int node_pos;
        int prec_out;
@@ -1137,9 +1199,8 @@ static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
                p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
                if (p == NULL) {
                        if (entry->suppressed) {
-                               if (entry->suppr_transit_count >
-                                   entry->suppress_count)
-                                       return NULL;
+                               if (entry->suppr_transit_count)
+                                       continue;
                                entry->suppressed = false;
                                p = brcmu_pktq_mdeq(&entry->psq,
                                                    1 << (fifo * 2), &prec_out);
@@ -1148,26 +1209,7 @@ static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
                if  (p == NULL)
                        continue;
 
-               /* did the packet come from suppress sub-queue? */
-               if (entry->requested_credit > 0) {
-                       entry->requested_credit--;
-                       /*
-                        * if the packet was pulled out while destination is in
-                        * closed state but had a non-zero packets requested,
-                        * then this should not count against the FIFO credit.
-                        * That is due to the fact that the firmware will
-                        * most likely hold onto this packet until a suitable
-                        * time later to push it to the appropriate AC FIFO.
-                        */
-                       if (entry->state == BRCMF_FWS_STATE_CLOSE)
-                               use_credit = 0;
-               } else if (entry->requested_packet > 0) {
-                       entry->requested_packet--;
-                       brcmf_skb_if_flags_set_field(p, REQUESTED, 1);
-                       if (entry->state == BRCMF_FWS_STATE_CLOSE)
-                               use_credit = 0;
-               }
-               brcmf_skb_if_flags_set_field(p, CREDITCHECK, use_credit);
+               brcmf_fws_macdesc_use_req_credit(entry, p);
 
                /* move dequeue position to ensure fair round-robin */
                fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
@@ -1179,7 +1221,7 @@ static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
                 * A packet has been picked up, update traffic
                 * availability bitmap, if applicable
                 */
-               brcmf_fws_tim_update(fws, entry, fifo);
+               brcmf_fws_tim_update(fws, entry, fifo, false);
 
                /*
                 * decrement total enqueued fifo packets and
@@ -1192,7 +1234,7 @@ static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
        }
        p = NULL;
 done:
-       brcmf_dbg(TRACE, "exit: fifo %d skb %p\n", fifo, p);
+       brcmf_dbg(DATA, "exit: fifo %d skb %p\n", fifo, p);
        return p;
 }
 
@@ -1202,22 +1244,26 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
        u32 hslot;
        int ret;
+       u8 ifidx;
 
        hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
 
        /* this packet was suppressed */
-       if (!entry->suppressed || entry->generation != genbit) {
+       if (!entry->suppressed) {
                entry->suppressed = true;
-               entry->suppress_count = brcmu_pktq_mlen(&entry->psq,
-                                                       1 << (fifo * 2 + 1));
                entry->suppr_transit_count = entry->transit_count;
+               brcmf_dbg(DATA, "suppress %s: transit %d\n",
+                         entry->name, entry->transit_count);
        }
 
        entry->generation = genbit;
 
-       ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
+       ret = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
+       if (ret == 0)
+               ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo,
+                                   skb);
        if (ret != 0) {
-               /* suppress q is full, drop this packet */
+               /* suppress q is full or hdrpull failed, drop this packet */
                brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
                                        true);
        } else {
@@ -1225,26 +1271,24 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
                 * Mark suppressed to avoid a double free during
                 * wlfc cleanup
                 */
-               brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot,
-                                                genbit);
-               entry->suppress_count++;
+               brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
        }
 
        return ret;
 }
 
 static int
-brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
+brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
                           u32 genbit)
 {
        u32 fifo;
        int ret;
        bool remove_from_hanger = true;
        struct sk_buff *skb;
+       struct brcmf_skbuff_cb *skcb;
        struct brcmf_fws_mac_descriptor *entry = NULL;
 
-       brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
-                 flags, hslot);
+       brcmf_dbg(DATA, "flags %d\n", flags);
 
        if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
                fws->stats.txs_discard++;
@@ -1256,6 +1300,8 @@ brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
                remove_from_hanger = false;
        } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
                fws->stats.txs_tossed++;
+       else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
+               fws->stats.txs_host_tossed++;
        else
                brcmf_err("unexpected txstatus\n");
 
@@ -1266,26 +1312,35 @@ brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
                return ret;
        }
 
-       entry = brcmf_skbcb(skb)->mac;
+       skcb = brcmf_skbcb(skb);
+       entry = skcb->mac;
        if (WARN_ON(!entry)) {
                brcmu_pkt_buf_free_skb(skb);
                return -EINVAL;
        }
+       entry->transit_count--;
+       if (entry->suppressed && entry->suppr_transit_count)
+               entry->suppr_transit_count--;
+
+       brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags,
+                 skcb->htod);
 
        /* pick up the implicit credit from this packet */
        fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
-       brcmf_skb_pick_up_credit(fws, fifo, skb);
+       if ((fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT) ||
+           (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
+           (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)) {
+               brcmf_fws_return_credits(fws, fifo, 1);
+               brcmf_fws_schedule_deq(fws);
+       }
+       brcmf_fws_macdesc_return_req_credit(skb);
 
        if (!remove_from_hanger)
                ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
 
-       if (remove_from_hanger || ret) {
-               entry->transit_count--;
-               if (entry->suppressed)
-                       entry->suppr_transit_count--;
-
+       if (remove_from_hanger || ret)
                brcmf_txfinalize(fws->drvr, skb, true);
-       }
+
        return 0;
 }
 
@@ -1299,11 +1354,11 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
                return BRCMF_FWS_RET_OK_NOSCHEDULE;
        }
 
-       brcmf_dbg(TRACE, "enter: data %pM\n", data);
+       brcmf_dbg(DATA, "enter: data %pM\n", data);
        for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
                brcmf_fws_return_credits(fws, i, data[i]);
 
-       brcmf_dbg(INFO, "map: credit %x delay %x\n", fws->fifo_credit_map,
+       brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
                  fws->fifo_delay_map);
        return BRCMF_FWS_RET_OK_SCHEDULE;
 }
@@ -1323,7 +1378,7 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
        hslot = brcmf_txstatus_get_field(status, HSLOT);
        genbit = brcmf_txstatus_get_field(status, GENERATION);
 
-       return brcmf_fws_txstatus_process(fws, flags, hslot, genbit);
+       return brcmf_fws_txs_process(fws, flags, hslot, genbit);
 }
 
 static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
@@ -1331,7 +1386,7 @@ static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
        __le32 timestamp;
 
        memcpy(&timestamp, &data[2], sizeof(timestamp));
-       brcmf_dbg(INFO, "received: seq %d, timestamp %d\n", data[1],
+       brcmf_dbg(CTL, "received: seq %d, timestamp %d\n", data[1],
                  le32_to_cpu(timestamp));
        return 0;
 }
@@ -1364,6 +1419,10 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
                brcmf_err("event payload too small (%d)\n", e->datalen);
                return -EINVAL;
        }
+       if (fws->creditmap_received)
+               return 0;
+
+       fws->creditmap_received = true;
 
        brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
        brcmf_fws_lock(ifp->drvr, flags);
@@ -1392,7 +1451,7 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
        s32 status;
        s32 err;
 
-       brcmf_dbg(TRACE, "enter: ifidx %d, skblen %u, sig %d\n",
+       brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
                  ifidx, skb->len, signal_len);
 
        WARN_ON(signal_len > skb->len);
@@ -1426,14 +1485,15 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
                len = signal_data[1];
                data = signal_data + 2;
 
-               brcmf_dbg(INFO, "tlv type=%d (%s), len=%d, data[0]=%d\n", type,
-                         brcmf_fws_get_tlv_name(type), len, *data);
+               brcmf_dbg(HDRS, "tlv type=%s (%d), len=%d (%d)\n",
+                         brcmf_fws_get_tlv_name(type), type, len,
+                         brcmf_fws_get_tlv_len(fws, type));
 
                /* abort parsing when length invalid */
                if (data_len < len + 2)
                        break;
 
-               if (len != brcmf_fws_get_tlv_len(fws, type))
+               if (len < brcmf_fws_get_tlv_len(fws, type))
                        break;
 
                err = BRCMF_FWS_RET_OK_NOSCHEDULE;
@@ -1502,64 +1562,32 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
        return 0;
 }
 
-static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
-{
-       struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
-       u8 *wlh;
-       u16 data_offset = 0;
-       u8 fillers;
-       __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
-
-       brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u, pkttag=0x%08X\n",
-                 entry->ea, entry->interface_id, le32_to_cpu(pkttag));
-       if (entry->send_tim_signal)
-               data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
-
-       /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
-       data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
-       fillers = round_up(data_offset, 4) - data_offset;
-       data_offset += fillers;
-
-       skb_push(skb, data_offset);
-       wlh = skb->data;
-
-       wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
-       wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
-       memcpy(&wlh[2], &pkttag, sizeof(pkttag));
-       wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
-
-       if (entry->send_tim_signal) {
-               entry->send_tim_signal = 0;
-               wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
-               wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
-               wlh[2] = entry->mac_handle;
-               wlh[3] = entry->traffic_pending_bmp;
-               wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
-               entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
-       }
-       if (fillers)
-               memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
-
-       brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
-                           data_offset >> 2, skb);
-       return 0;
-}
-
 static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
                                   struct sk_buff *p)
 {
        struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
        struct brcmf_fws_mac_descriptor *entry = skcb->mac;
        int rc = 0;
-       bool header_needed;
+       bool first_time;
        int hslot = BRCMF_FWS_HANGER_MAXITEMS;
        u8 free_ctr;
-       u8 ifidx;
        u8 flags;
 
-       header_needed = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
+       first_time = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
 
-       if (header_needed) {
+       brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
+       brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
+       brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
+       flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
+       if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
+               /*
+                * Indicate that this packet is being sent in response to an
+                * explicit request from the firmware side.
+                */
+               flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
+       }
+       brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
+       if (first_time) {
                /* obtaining free slot may fail, but that will be caught
                 * by the hanger push. This assures the packet has a BDC
                 * header upon return.
@@ -1568,47 +1596,20 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
                free_ctr = entry->seq[fifo];
                brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
                brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr);
-               brcmf_skb_htod_tag_set_field(p, GENERATION, 1);
-               entry->transit_count++;
-       }
-       brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
-       brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
-
-       flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
-       if (!(skcb->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)) {
-               /*
-               Indicate that this packet is being sent in response to an
-               explicit request from the firmware side.
-               */
-               flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
-       }
-       brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
-       if (header_needed) {
-               brcmf_fws_hdrpush(fws, p);
                rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
                if (rc)
                        brcmf_err("hanger push failed: rc=%d\n", rc);
-       } else {
-               int gen;
-
-               /* remove old header */
-               rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, p);
-               if (rc == 0) {
-                       hslot = brcmf_skb_htod_tag_get_field(p, HSLOT);
-                       brcmf_fws_hanger_get_genbit(&fws->hanger, p,
-                                                   hslot, &gen);
-                       brcmf_skb_htod_tag_set_field(p, GENERATION, gen);
-
-                       /* push new header */
-                       brcmf_fws_hdrpush(fws, p);
-               }
        }
 
+       if (rc == 0)
+               brcmf_fws_hdrpush(fws, p);
+
        return rc;
 }
 
 static void
-brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
+brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
+                      struct sk_buff *skb, int fifo)
 {
        /*
        put the packet back to the head of queue
@@ -1622,13 +1623,11 @@ brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
        enum brcmf_fws_skb_state state;
        struct sk_buff *pktout;
        int rc = 0;
-       int fifo;
        int hslot;
-       u8 ifidx;
 
-       fifo = brcmf_skb_if_flags_get_field(skb, FIFO);
        state = brcmf_skbcb(skb)->state;
        entry = brcmf_skbcb(skb)->mac;
+       hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
 
        if (entry != NULL) {
                if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
@@ -1640,19 +1639,6 @@ brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
                                rc = -ENOSPC;
                        }
                } else {
-                       hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
-
-                       /* remove header first */
-                       rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
-                       if (rc) {
-                               brcmf_err("header removal failed\n");
-                               /* free the hanger slot */
-                               brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
-                                                       &pktout, true);
-                               rc = -EINVAL;
-                               goto fail;
-                       }
-
                        /* delay-q packets are going to delay-q */
                        pktout = brcmu_pktq_penq_head(&entry->psq,
                                                      2 * fifo, skb);
@@ -1668,33 +1654,30 @@ brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
                        /* decrement sequence count */
                        entry->seq[fifo]--;
                }
-               /*
-               if this packet did not count against FIFO credit, it must have
-               taken a requested_credit from the firmware (for pspoll etc.)
-               */
-               if (!(brcmf_skbcb(skb)->if_flags &
-                     BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK))
-                       entry->requested_credit++;
        } else {
                brcmf_err("no mac entry linked\n");
                rc = -ENOENT;
        }
 
-
-fail:
        if (rc) {
-               brcmf_txfinalize(fws->drvr, skb, false);
                fws->stats.rollback_failed++;
-       } else
+               brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
+                                     hslot, 0);
+       } else {
                fws->stats.rollback_success++;
+               brcmf_fws_return_credits(fws, fifo, 1);
+               brcmf_fws_macdesc_return_req_credit(skb);
+       }
 }
 
 static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
 {
        int lender_ac;
 
-       if (time_after(fws->borrow_defer_timestamp, jiffies))
+       if (time_after(fws->borrow_defer_timestamp, jiffies)) {
+               fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
                return -ENAVAIL;
+       }
 
        for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
                if (fws->fifo_credit[lender_ac]) {
@@ -1702,10 +1685,12 @@ static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
                        fws->fifo_credit[lender_ac]--;
                        if (fws->fifo_credit[lender_ac] == 0)
                                fws->fifo_credit_map &= ~(1 << lender_ac);
-                       brcmf_dbg(TRACE, "borrow credit from: %d\n", lender_ac);
+                       fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE);
+                       brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac);
                        return 0;
                }
        }
+       fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
        return -ENAVAIL;
 }
 
@@ -1714,33 +1699,6 @@ static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
 {
        struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
        int *credit = &fws->fifo_credit[fifo];
-       int use_credit = 1;
-
-       brcmf_dbg(TRACE, "enter: ac=%d, credits=%d\n", fifo, *credit);
-
-       if (entry->requested_credit > 0) {
-               /*
-                * if the packet was pulled out while destination is in
-                * closed state but had a non-zero packets requested,
-                * then this should not count against the FIFO credit.
-                * That is due to the fact that the firmware will
-                * most likely hold onto this packet until a suitable
-                * time later to push it to the appropriate AC FIFO.
-                */
-               entry->requested_credit--;
-               if (entry->state == BRCMF_FWS_STATE_CLOSE)
-                       use_credit = 0;
-       } else if (entry->requested_packet > 0) {
-               entry->requested_packet--;
-               brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
-               if (entry->state == BRCMF_FWS_STATE_CLOSE)
-                       use_credit = 0;
-       }
-       brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
-       if (!use_credit) {
-               brcmf_dbg(TRACE, "exit: no creditcheck set\n");
-               return 0;
-       }
 
        if (fifo != BRCMF_FWS_FIFO_AC_BE)
                fws->borrow_defer_timestamp = jiffies +
@@ -1748,17 +1706,22 @@ static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
 
        if (!(*credit)) {
                /* Try to borrow a credit from other queue */
-               if (fifo == BRCMF_FWS_FIFO_AC_BE &&
-                   brcmf_fws_borrow_credit(fws) == 0)
-                       return 0;
-
-               brcmf_dbg(TRACE, "exit: ac=%d, credits depleted\n", fifo);
-               return -ENAVAIL;
+               if (fifo != BRCMF_FWS_FIFO_AC_BE ||
+                   (brcmf_fws_borrow_credit(fws) != 0)) {
+                       brcmf_dbg(DATA, "ac=%d, credits depleted\n", fifo);
+                       return -ENAVAIL;
+               }
+       } else {
+               (*credit)--;
+               if (!(*credit))
+                       fws->fifo_credit_map &= ~(1 << fifo);
        }
-       (*credit)--;
-       if (!(*credit))
-               fws->fifo_credit_map &= ~(1 << fifo);
-       brcmf_dbg(TRACE, "exit: ac=%d, credits=%d\n", fifo, *credit);
+
+       brcmf_fws_macdesc_use_req_credit(entry, skb);
+
+       brcmf_dbg(DATA, "ac=%d, credits=%02d:%02d:%02d:%02d\n", fifo,
+                 fws->fifo_credit[0], fws->fifo_credit[1],
+                 fws->fifo_credit[2], fws->fifo_credit[3]);
        return 0;
 }
 
@@ -1769,6 +1732,7 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
        struct brcmf_fws_mac_descriptor *entry;
        struct brcmf_bus *bus = fws->drvr->bus_if;
        int rc;
+       u8 ifidx;
 
        entry = skcb->mac;
        if (IS_ERR(entry))
@@ -1780,21 +1744,27 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
                goto rollback;
        }
 
+       brcmf_dbg(DATA, "%s flags %X htod %X\n", entry->name, skcb->if_flags,
+                 skcb->htod);
        rc = brcmf_bus_txdata(bus, skb);
-       if (rc < 0)
+       if (rc < 0) {
+               brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
                goto rollback;
+       }
 
+       entry->transit_count++;
+       if (entry->suppressed)
+               entry->suppr_transit_count++;
        entry->seq[fifo]++;
        fws->stats.pkt2bus++;
-       if (brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
-               fws->stats.send_pkts[fifo]++;
-               fws->stats.fifo_credits_sent[fifo]++;
-       }
+       fws->stats.send_pkts[fifo]++;
+       if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
+               fws->stats.requested_sent[fifo]++;
 
        return rc;
 
 rollback:
-       brcmf_fws_rollback_toq(fws, skb);
+       brcmf_fws_rollback_toq(fws, skb, fifo);
        return rc;
 }
 
@@ -1831,13 +1801,13 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
        if (!multicast)
                fifo = brcmf_fws_prio2fifo[skb->priority];
-       brcmf_skb_if_flags_set_field(skb, FIFO, fifo);
 
-       brcmf_dbg(TRACE, "ea=%pM, multi=%d, fifo=%d\n", eh->h_dest,
-                 multicast, fifo);
+       brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
+                 eh->h_dest, multicast, fifo);
 
        brcmf_fws_lock(drvr, flags);
        if (skcb->mac->suppressed ||
+           fws->bus_flow_blocked ||
            brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) ||
            brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) ||
            (!multicast &&
@@ -1846,9 +1816,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
                drvr->fws->fifo_delay_map |= 1 << fifo;
                brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
        } else {
-               if (brcmf_fws_commit_skb(fws, fifo, skb))
-                       if (!multicast)
-                               brcmf_skb_pick_up_credit(fws, fifo, skb);
+               brcmf_fws_commit_skb(fws, fifo, skb);
        }
        brcmf_fws_unlock(drvr, flags);
        return 0;
@@ -1870,16 +1838,16 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
        struct brcmf_fws_info *fws = ifp->drvr->fws;
        struct brcmf_fws_mac_descriptor *entry;
 
-       brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n",
-                 ifp->bssidx, ifp->mac_addr);
        if (!ifp->ndev || !ifp->drvr->fw_signals)
                return;
 
        entry = &fws->desc.iface[ifp->ifidx];
        ifp->fws_desc = entry;
        brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
+       brcmf_fws_macdesc_set_name(fws, entry);
        brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
                        BRCMF_FWS_PSQ_LEN);
+       brcmf_dbg(TRACE, "added %s\n", entry->name);
 }
 
 void brcmf_fws_del_interface(struct brcmf_if *ifp)
@@ -1887,12 +1855,12 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp)
        struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
        ulong flags;
 
-       brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
        if (!entry)
                return;
 
        brcmf_fws_lock(ifp->drvr, flags);
        ifp->fws_desc = NULL;
+       brcmf_dbg(TRACE, "deleting %s\n", entry->name);
        brcmf_fws_clear_mac_descriptor(entry);
        brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
        brcmf_fws_unlock(ifp->drvr, flags);
@@ -1904,39 +1872,36 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker)
        struct sk_buff *skb;
        ulong flags;
        int fifo;
-       int credit;
 
        fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
 
-       brcmf_dbg(TRACE, "enter: fws=%p\n", fws);
        brcmf_fws_lock(fws->drvr, flags);
-       for (fifo = NL80211_NUM_ACS; fifo >= 0; fifo--) {
-               brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
-                         fws->fifo_credit[fifo]);
-               for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
+       for (fifo = NL80211_NUM_ACS; fifo >= 0 && !fws->bus_flow_blocked;
+            fifo--) {
+               while (fws->fifo_credit[fifo]) {
                        skb = brcmf_fws_deq(fws, fifo);
-                       if (!skb || brcmf_fws_commit_skb(fws, fifo, skb))
+                       if (!skb)
+                               break;
+                       fws->fifo_credit[fifo]--;
+                       if (brcmf_fws_commit_skb(fws, fifo, skb))
+                               break;
+                       if (fws->bus_flow_blocked)
                                break;
-                       if (brcmf_skbcb(skb)->if_flags &
-                           BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
-                               credit++;
                }
                if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
-                   (credit == fws->fifo_credit[fifo])) {
-                       fws->fifo_credit[fifo] -= credit;
+                   (fws->fifo_credit[fifo] == 0) &&
+                   (!fws->bus_flow_blocked)) {
                        while (brcmf_fws_borrow_credit(fws) == 0) {
                                skb = brcmf_fws_deq(fws, fifo);
                                if (!skb) {
                                        brcmf_fws_return_credits(fws, fifo, 1);
                                        break;
                                }
-                               if (brcmf_fws_commit_skb(fws, fifo, skb)) {
-                                       brcmf_fws_return_credits(fws, fifo, 1);
+                               if (brcmf_fws_commit_skb(fws, fifo, skb))
+                                       break;
+                               if (fws->bus_flow_blocked)
                                        break;
-                               }
                        }
-               } else {
-                       fws->fifo_credit[fifo] -= credit;
                }
        }
        brcmf_fws_unlock(fws->drvr, flags);
@@ -1994,14 +1959,14 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
 
        brcmf_fws_hanger_init(&drvr->fws->hanger);
        brcmf_fws_init_mac_descriptor(&drvr->fws->desc.other, NULL, 0);
+       brcmf_fws_macdesc_set_name(drvr->fws, &drvr->fws->desc.other);
        brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
                        BRCMF_FWS_PSQ_LEN);
 
        /* create debugfs file for statistics */
        brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
 
-       /* TODO: remove upon feature delivery */
-       brcmf_err("%s bdcv2 tlv signaling [%x]\n",
+       brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
                  drvr->fw_signals ? "enabled" : "disabled", tlv);
        return 0;
 
@@ -2043,25 +2008,31 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
        if (!fws)
                return false;
 
-       brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode);
        return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
 }
 
 void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
 {
        ulong flags;
+       u32 hslot;
 
-       brcmf_fws_lock(fws->drvr, flags);
-       brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED,
-                                  brcmf_skb_htod_tag_get_field(skb, HSLOT), 0);
-       /* the packet never reached firmware so reclaim credit */
-       if (fws->fcmode == BRCMF_FWS_FCMODE_EXPLICIT_CREDIT &&
-           brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
-               brcmf_fws_return_credits(fws,
-                                        brcmf_skb_htod_tag_get_field(skb,
-                                                                     FIFO),
-                                        1);
-               brcmf_fws_schedule_deq(fws);
+       if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
+               brcmu_pkt_buf_free_skb(skb);
+               return;
        }
+       brcmf_fws_lock(fws->drvr, flags);
+       hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+       brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0);
        brcmf_fws_unlock(fws->drvr, flags);
 }
+
+void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
+{
+       struct brcmf_fws_info *fws = drvr->fws;
+
+       fws->bus_flow_blocked = flow_blocked;
+       if (!flow_blocked)
+               brcmf_fws_schedule_deq(fws);
+       else
+               fws->stats.bus_flow_block++;
+}
index fbe483d23752ca2e2a0ae3b0ab1f6169b613809f..9fc860910bd8571abd9f42040b6918f9f7fb57e5 100644 (file)
@@ -29,5 +29,6 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp);
 void brcmf_fws_add_interface(struct brcmf_if *ifp);
 void brcmf_fws_del_interface(struct brcmf_if *ifp);
 void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
+void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
 
 #endif /* FWSIGNAL_H_ */
index e7a1a47709966972891f96202996c77db40f3eec..79555f006d53d170e6186a76f3111b6d16b299ee 100644 (file)
@@ -47,6 +47,7 @@
 #define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
                                         (channel == SOCIAL_CHAN_2) || \
                                         (channel == SOCIAL_CHAN_3))
+#define BRCMF_P2P_TEMP_CHAN    SOCIAL_CHAN_3
 #define SOCIAL_CHAN_CNT                3
 #define AF_PEER_SEARCH_CNT     2
 
@@ -1954,21 +1955,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
                err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
                if (err < 0) {
                        brcmf_err("set p2p_disc error\n");
-                       brcmf_free_vif(p2p_vif);
+                       brcmf_free_vif(cfg, p2p_vif);
                        goto exit;
                }
                /* obtain bsscfg index for P2P discovery */
                err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
                if (err < 0) {
                        brcmf_err("retrieving discover bsscfg index failed\n");
-                       brcmf_free_vif(p2p_vif);
+                       brcmf_free_vif(cfg, p2p_vif);
                        goto exit;
                }
                /* Verify that firmware uses same bssidx as driver !! */
                if (p2p_ifp->bssidx != bssidx) {
                        brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
                                  bssidx, p2p_ifp->bssidx);
-                       brcmf_free_vif(p2p_vif);
+                       brcmf_free_vif(cfg, p2p_vif);
                        goto exit;
                }
 
@@ -1996,7 +1997,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
                brcmf_p2p_cancel_remain_on_channel(vif->ifp);
                brcmf_p2p_deinit_discovery(p2p);
                /* remove discovery interface */
-               brcmf_free_vif(vif);
+               brcmf_free_vif(p2p->cfg, vif);
                p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
        }
        /* just set it all to zero */
@@ -2013,17 +2014,30 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
                                           u16 *chanspec)
 {
        struct brcmf_if *ifp;
-       struct brcmf_fil_chan_info_le ci;
+       u8 mac_addr[ETH_ALEN];
        struct brcmu_chan ch;
-       s32 err;
+       struct brcmf_bss_info_le *bi;
+       u8 *buf;
 
        ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
 
-       ch.chnum = 11;
-
-       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
-       if (!err)
-               ch.chnum = le32_to_cpu(ci.hw_channel);
+       if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mac_addr,
+                                  ETH_ALEN) == 0) {
+               buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+               if (buf != NULL) {
+                       *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+                       if (brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSS_INFO,
+                                                  buf, WL_BSS_INFO_MAX) == 0) {
+                               bi = (struct brcmf_bss_info_le *)(buf + 4);
+                               *chanspec = le16_to_cpu(bi->chanspec);
+                               kfree(buf);
+                               return;
+                       }
+                       kfree(buf);
+               }
+       }
+       /* Use default channel for P2P */
+       ch.chnum = BRCMF_P2P_TEMP_CHAN;
        ch.bw = BRCMU_CHAN_BW_20;
        p2p->cfg->d11inf.encchspec(&ch);
        *chanspec = ch.chspec;
@@ -2208,7 +2222,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
        return &p2p_vif->wdev;
 
 fail:
-       brcmf_free_vif(p2p_vif);
+       brcmf_free_vif(p2p->cfg, p2p_vif);
        return ERR_PTR(err);
 }
 
@@ -2217,13 +2231,31 @@ fail:
  *
  * @vif: virtual interface object to delete.
  */
-static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_vif *vif)
+static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg,
+                                   struct brcmf_cfg80211_vif *vif)
 {
-       struct brcmf_p2p_info *p2p = &vif->ifp->drvr->config->p2p;
-
        cfg80211_unregister_wdev(&vif->wdev);
-       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
-       brcmf_free_vif(vif);
+       cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+       brcmf_free_vif(cfg, vif);
+}
+
+/**
+ * brcmf_p2p_free_p2p_if() - free up net device related data.
+ *
+ * @ndev: net device that needs to be freed.
+ */
+static void brcmf_p2p_free_p2p_if(struct net_device *ndev)
+{
+       struct brcmf_cfg80211_info *cfg;
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_if *ifp;
+
+       ifp = netdev_priv(ndev);
+       cfg = ifp->drvr->config;
+       vif = ifp->vif;
+
+       brcmf_free_vif(cfg, vif);
+       free_netdev(ifp->ndev);
 }
 
 /**
@@ -2303,6 +2335,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
                brcmf_err("Registering netdevice failed\n");
                goto fail;
        }
+       /* override destructor */
+       ifp->ndev->destructor = brcmf_p2p_free_p2p_if;
+
        cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
        /* Disable firmware roaming for P2P interface  */
        brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
@@ -2314,7 +2349,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
        return &ifp->vif->wdev;
 
 fail:
-       brcmf_free_vif(vif);
+       brcmf_free_vif(cfg, vif);
        return ERR_PTR(err);
 }
 
@@ -2350,7 +2385,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                break;
 
        case NL80211_IFTYPE_P2P_DEVICE:
-               brcmf_p2p_delete_p2pdev(vif);
+               brcmf_p2p_delete_p2pdev(cfg, vif);
                return 0;
        default:
                return -ENOTSUPP;
@@ -2378,7 +2413,6 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                        err = 0;
        }
        brcmf_cfg80211_arm_vif_event(cfg, NULL);
-       brcmf_free_vif(vif);
        p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL;
 
        return err;
index 9df1f7a681e07e9ee32b15672e7ba9de3a795fef..bc29171128991a9836d8237c556be00482f66d00 100644 (file)
@@ -87,6 +87,27 @@ TRACE_EVENT(brcmf_hexdump,
        TP_printk("hexdump [length=%lu]", __entry->len)
 );
 
+TRACE_EVENT(brcmf_bdchdr,
+       TP_PROTO(void *data),
+       TP_ARGS(data),
+       TP_STRUCT__entry(
+               __field(u8, flags)
+               __field(u8, prio)
+               __field(u8, flags2)
+               __field(u32, siglen)
+               __dynamic_array(u8, signal, *((u8 *)data + 3) * 4)
+       ),
+       TP_fast_assign(
+               __entry->flags = *(u8 *)data;
+               __entry->prio = *((u8 *)data + 1);
+               __entry->flags2 = *((u8 *)data + 2);
+               __entry->siglen = *((u8 *)data + 3) * 4;
+               memcpy(__get_dynamic_array(signal),
+                      (u8 *)data + 4, __entry->siglen);
+       ),
+       TP_printk("bdc: prio=%d siglen=%d", __entry->prio, __entry->siglen)
+);
+
 #ifdef CONFIG_BRCM_TRACING
 
 #undef TRACE_INCLUDE_PATH
index 01aed7ad6bec17ec4f2dc453518f3a72079f5c76..322cadc51deddcbfe8d7c560dbc93669b167b574 100644 (file)
@@ -82,6 +82,7 @@ struct brcmf_usbdev_info {
        int tx_high_watermark;
        int tx_freecount;
        bool tx_flowblock;
+       spinlock_t tx_flowblock_lock;
 
        struct brcmf_usbreq *tx_reqs;
        struct brcmf_usbreq *rx_reqs;
@@ -411,6 +412,7 @@ static void brcmf_usb_tx_complete(struct urb *urb)
 {
        struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
        struct brcmf_usbdev_info *devinfo = req->devinfo;
+       unsigned long flags;
 
        brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
                  req->skb);
@@ -419,11 +421,13 @@ static void brcmf_usb_tx_complete(struct urb *urb)
        brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
        req->skb = NULL;
        brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
+       spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
        if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
                devinfo->tx_flowblock) {
                brcmf_txflowblock(devinfo->dev, false);
                devinfo->tx_flowblock = false;
        }
+       spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
 }
 
 static void brcmf_usb_rx_complete(struct urb *urb)
@@ -568,6 +572,7 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
        struct brcmf_usbreq  *req;
        int ret;
+       unsigned long flags;
 
        brcmf_dbg(USB, "Enter, skb=%p\n", skb);
        if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
@@ -599,11 +604,13 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
                goto fail;
        }
 
+       spin_lock_irqsave(&devinfo->tx_flowblock_lock, flags);
        if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
            !devinfo->tx_flowblock) {
                brcmf_txflowblock(dev, true);
                devinfo->tx_flowblock = true;
        }
+       spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
        return 0;
 
 fail:
@@ -1164,6 +1171,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
 
        /* Initialize the spinlocks */
        spin_lock_init(&devinfo->qlock);
+       spin_lock_init(&devinfo->tx_flowblock_lock);
 
        INIT_LIST_HEAD(&devinfo->rx_freeq);
        INIT_LIST_HEAD(&devinfo->rx_postq);
index 6d758f2853522fc1c2112186e21f6595867a99f1..71f4db5fde9954df33187a3681d0d00bf28f6112 100644 (file)
@@ -459,6 +459,38 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
        return err;
 }
 
+static s32
+brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
+{
+       s32 err;
+       u32 mode;
+
+       if (enable)
+               mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY;
+       else
+               mode = 0;
+
+       /* Try to set and enable ARP offload feature, this may fail, then it  */
+       /* is simply not supported and err 0 will be returned                 */
+       err = brcmf_fil_iovar_int_set(ifp, "arp_ol", mode);
+       if (err) {
+               brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, err = %d\n",
+                         mode, err);
+               err = 0;
+       } else {
+               err = brcmf_fil_iovar_int_set(ifp, "arpoe", enable);
+               if (err) {
+                       brcmf_dbg(TRACE, "failed to configure (%d) ARP offload err = %d\n",
+                                 enable, err);
+                       err = 0;
+               } else
+                       brcmf_dbg(TRACE, "successfully configured (%d) ARP offload to 0x%x\n",
+                                 enable, mode);
+       }
+
+       return err;
+}
+
 static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
                                                     const char *name,
                                                     enum nl80211_iftype type,
@@ -2216,6 +2248,11 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        pm = enabled ? PM_FAST : PM_OFF;
+       /* Do not enable the power save after assoc if it is a p2p interface */
+       if (ifp->vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) {
+               brcmf_dbg(INFO, "Do not enable power save for P2P clients\n");
+               pm = PM_OFF;
+       }
        brcmf_dbg(INFO, "power save %s\n", (pm ? "enabled" : "disabled"));
 
        err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, pm);
@@ -3639,11 +3676,29 @@ brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif,
        return err;
 }
 
+static s32
+brcmf_cfg80211_set_channel(struct brcmf_cfg80211_info *cfg,
+                          struct brcmf_if *ifp,
+                          struct ieee80211_channel *channel)
+{
+       u16 chanspec;
+       s32 err;
+
+       brcmf_dbg(TRACE, "band=%d, center_freq=%d\n", channel->band,
+                 channel->center_freq);
+
+       chanspec = channel_to_chanspec(&cfg->d11inf, channel);
+       err = brcmf_fil_iovar_int_set(ifp, "chanspec", chanspec);
+
+       return err;
+}
+
 static s32
 brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
                        struct cfg80211_ap_settings *settings)
 {
        s32 ie_offset;
+       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_tlv *ssid_ie;
        struct brcmf_ssid_le ssid_le;
@@ -3683,6 +3738,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        brcmf_set_mpc(ifp, 0);
+       brcmf_configure_arp_offload(ifp, false);
 
        /* find the RSN_IE */
        rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@@ -3713,6 +3769,12 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 
        brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon);
 
+       err = brcmf_cfg80211_set_channel(cfg, ifp, settings->chandef.chan);
+       if (err < 0) {
+               brcmf_err("Set Channel failed, %d\n", err);
+               goto exit;
+       }
+
        if (settings->beacon_interval) {
                err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
                                            settings->beacon_interval);
@@ -3789,8 +3851,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
 
 exit:
-       if (err)
+       if (err) {
                brcmf_set_mpc(ifp, 1);
+               brcmf_configure_arp_offload(ifp, true);
+       }
        return err;
 }
 
@@ -3831,6 +3895,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
                        brcmf_err("bss_enable config failed %d\n", err);
        }
        brcmf_set_mpc(ifp, 1);
+       brcmf_configure_arp_offload(ifp, true);
        set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
        clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
 
@@ -3917,6 +3982,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
        struct brcmf_fil_af_params_le *af_params;
        bool ack;
        s32 chan_nr;
+       u32 freq;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3929,6 +3995,8 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                return -EPERM;
        }
 
+       vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
        if (ieee80211_is_probe_resp(mgmt->frame_control)) {
                /* Right now the only reason to get a probe response */
                /* is for p2p listen response or for p2p GO from     */
@@ -3944,7 +4012,6 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                ie_offset =  DOT11_MGMT_HDR_LEN +
                             DOT11_BCN_PRB_FIXED_LEN;
                ie_len = len - ie_offset;
-               vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
                if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
                        vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
                err = brcmf_vif_set_mgmt_ie(vif,
@@ -3968,8 +4035,15 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN);
                /* Add the length exepted for 802.11 header  */
                action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN);
-               /* Add the channel */
-               chan_nr = ieee80211_frequency_to_channel(chan->center_freq);
+               /* Add the channel. Use the one specified as parameter if any or
+                * the current one (got from the firmware) otherwise
+                */
+               if (chan)
+                       freq = chan->center_freq;
+               else
+                       brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL,
+                                             &freq);
+               chan_nr = ieee80211_frequency_to_channel(freq);
                af_params->channel = cpu_to_le32(chan_nr);
 
                memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN],
@@ -4140,11 +4214,15 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
                .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
                         BIT(NL80211_IFTYPE_P2P_GO)
        },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+       }
 };
 static const struct ieee80211_iface_combination brcmf_iface_combos[] = {
        {
                 .max_interfaces = BRCMF_IFACE_MAX_CNT,
-                .num_different_channels = 1, /* no multi-channel for now */
+                .num_different_channels = 2,
                 .n_limits = ARRAY_SIZE(brcmf_iface_limits),
                 .limits = brcmf_iface_limits
        }
@@ -4197,7 +4275,8 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
                                 BIT(NL80211_IFTYPE_ADHOC) |
                                 BIT(NL80211_IFTYPE_AP) |
                                 BIT(NL80211_IFTYPE_P2P_CLIENT) |
-                                BIT(NL80211_IFTYPE_P2P_GO);
+                                BIT(NL80211_IFTYPE_P2P_GO) |
+                                BIT(NL80211_IFTYPE_P2P_DEVICE);
        wiphy->iface_combinations = brcmf_iface_combos;
        wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
        wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
@@ -4251,20 +4330,16 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
        return vif;
 }
 
-void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
+                   struct brcmf_cfg80211_vif *vif)
 {
-       struct brcmf_cfg80211_info *cfg;
-       struct wiphy *wiphy;
-
-       wiphy = vif->wdev.wiphy;
-       cfg = wiphy_priv(wiphy);
        list_del(&vif->list);
        cfg->vif_cnt--;
 
        kfree(vif);
        if (!cfg->vif_cnt) {
-               wiphy_unregister(wiphy);
-               wiphy_free(wiphy);
+               wiphy_unregister(cfg->wiphy);
+               wiphy_free(cfg->wiphy);
        }
 }
 
@@ -4641,7 +4716,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
                return 0;
 
        case BRCMF_E_IF_DEL:
-               ifp->vif = NULL;
                mutex_unlock(&event->vif_event_lock);
                /* event may not be upon user request */
                if (brcmf_cfg80211_vif_event_armed(cfg))
@@ -4847,8 +4921,7 @@ cfg80211_p2p_attach_out:
        wl_deinit_priv(cfg);
 
 cfg80211_attach_out:
-       brcmf_free_vif(vif);
-       wiphy_free(wiphy);
+       brcmf_free_vif(cfg, vif);
        return NULL;
 }
 
@@ -4860,7 +4933,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
        wl_deinit_priv(cfg);
        brcmf_btcoex_detach(cfg);
        list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
-               brcmf_free_vif(vif);
+               brcmf_free_vif(cfg, vif);
        }
 }
 
@@ -5224,6 +5297,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
        if (err)
                goto default_conf_out;
 
+       brcmf_configure_arp_offload(ifp, true);
+
        cfg->dongle_up = true;
 default_conf_out:
 
index a71cff84cdcf57b0a140f3bf8c1a9d910f3e8bc3..d9bdaf9a72d0fd2d606a5ab041a6e283aec5770e 100644 (file)
@@ -487,7 +487,8 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
                                           enum nl80211_iftype type,
                                           bool pm_block);
-void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
+void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
+                   struct brcmf_cfg80211_vif *vif);
 
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
                          const u8 *vndr_ie_buf, u32 vndr_ie_len);
index 1585cc5bf866b847e86f6210074b4c89b6c0b26f..bd982856d3853b4c6415b43c137d76b3eb4eeabf 100644 (file)
@@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                if (supr_status) {
                        update_rate = false;
                        if (supr_status == TX_STATUS_SUPR_BADCH) {
-                               brcms_err(wlc->hw->d11core,
+                               brcms_dbg_ht(wlc->hw->d11core,
                                          "%s: Pkt tx suppressed, illegal channel possibly %d\n",
                                          __func__, CHSPEC_CHANNEL(
                                          wlc->default_bss->chanspec));
index 13e36119ae9f03b3f80fe407edc7fa85bc6e2ae6..0880742eab170ff86f362bb54cd494f342959efe 100644 (file)
@@ -13,34 +13,18 @@ config CW1200_WLAN_SDIO
        depends on CW1200 && MMC
        help
          Enable support for the CW1200 connected via an SDIO bus.
+         By default this driver only supports the Sagrad SG901-1091/1098 EVK
+         and similar designs that utilize a hardware reset circuit. To
+         support different CW1200 SDIO designs you will need to override
+         the default platform data by calling cw1200_sdio_set_platform_data()
+         in your board setup file.
 
 config CW1200_WLAN_SPI
        tristate "Support SPI platforms"
        depends on CW1200 && SPI
        help
-         Enables support for the CW1200 connected via a SPI bus.
-
-config CW1200_WLAN_SAGRAD
-       tristate "Support Sagrad SG901-1091/1098 modules"
-       depends on CW1200_WLAN_SDIO
-       help
-         This provides the platform data glue to support the
-         Sagrad SG901-1091/1098 modules in their standard SDIO EVK.
-         It also includes example SPI platform data.
-
-menu "Driver debug features"
-       depends on CW1200 && DEBUG_FS
-
-config CW1200_ETF
-       bool "Enable CW1200 Engineering Test Framework hooks"
-       help
-         If you don't know what this is, just say N.
-
-config CW1200_ITP
-       bool "Enable ITP access"
-       help
-         If you don't know what this is, just say N.
-
-endmenu
+         Enables support for the CW1200 connected via a SPI bus.  You will
+         need to add appropriate platform data glue in your board setup
+         file.
 
 endif
index 1aa3682066e0411a0b7778f8cf4216324f065b42..b086aac6547af81a0727a5a67619267a91525cb5 100644 (file)
@@ -9,16 +9,13 @@ cw1200_core-y := \
                sta.o \
                scan.o \
                debug.o
-cw1200_core-$(CONFIG_CW1200_ITP)       += itp.o
 cw1200_core-$(CONFIG_PM)       += pm.o
 
 # CFLAGS_sta.o += -DDEBUG
 
 cw1200_wlan_sdio-y := cw1200_sdio.o
 cw1200_wlan_spi-y := cw1200_spi.o
-cw1200_wlan_sagrad-y := cw1200_sagrad.o
 
 obj-$(CONFIG_CW1200) += cw1200_core.o
 obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o
 obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o
-obj-$(CONFIG_CW1200_WLAN_SAGRAD) += cw1200_wlan_sagrad.o
index cf7375f92fb35023dff817301adc17be30b98167..c1ec2a4dd8c02c6800a515ea152f6c91b1dbe35f 100644 (file)
@@ -23,7 +23,7 @@
 #include "bh.h"
 #include "hwio.h"
 #include "wsm.h"
-#include "sbus.h"
+#include "hwbus.h"
 #include "debug.h"
 #include "fwio.h"
 
@@ -31,7 +31,8 @@ static int cw1200_bh(void *arg);
 
 #define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4)
 /* an SPI message cannot be bigger than (2"12-1)*2 bytes
- * "*2" to cvt to bytes */
+ * "*2" to cvt to bytes
+ */
 #define MAX_SZ_RD_WR_BUFFERS   (DOWNLOAD_BLOCK_SIZE_WR*2)
 #define PIGGYBACK_CTRL_REG     (2)
 #define EFFECTIVE_BUF_SIZE     (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG)
@@ -103,7 +104,7 @@ void cw1200_irq_handler(struct cw1200_common *priv)
        pr_debug("[BH] irq.\n");
 
        /* Disable Interrupts! */
-       /* NOTE:  sbus_ops->lock already held */
+       /* NOTE:  hwbus_ops->lock already held */
        __cw1200_irq_enable(priv, 0);
 
        if (/* WARN_ON */(priv->bh_error))
@@ -217,7 +218,8 @@ static int cw1200_device_wakeup(struct cw1200_common *priv)
                return ret;
 
        /* If the device returns WLAN_RDY as 1, the device is active and will
-        * remain active. */
+        * remain active.
+        */
        if (ctrl_reg & ST90TDS_CONT_RDY_BIT) {
                pr_debug("[BH] Device awake.\n");
                return 1;
@@ -262,11 +264,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv,
        }
 
        /* Add SIZE of PIGGYBACK reg (CONTROL Reg)
-        * to the NEXT Message length + 2 Bytes for SKB */
+        * to the NEXT Message length + 2 Bytes for SKB
+        */
        read_len = read_len + 2;
 
-       alloc_len = priv->sbus_ops->align_size(
-               priv->sbus_priv, read_len);
+       alloc_len = priv->hwbus_ops->align_size(
+               priv->hwbus_priv, read_len);
 
        /* Check if not exceeding CW1200 capabilities */
        if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) {
@@ -384,8 +387,8 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv,
 
        atomic_add(1, &priv->bh_tx);
 
-       tx_len = priv->sbus_ops->align_size(
-               priv->sbus_priv, tx_len);
+       tx_len = priv->hwbus_ops->align_size(
+               priv->hwbus_priv, tx_len);
 
        /* Check if not exceeding CW1200 capabilities */
        if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE))
@@ -597,15 +600,15 @@ static int cw1200_bh(void *arg)
 
        done:
                /* Re-enable device interrupts */
-               priv->sbus_ops->lock(priv->sbus_priv);
+               priv->hwbus_ops->lock(priv->hwbus_priv);
                __cw1200_irq_enable(priv, 1);
-               priv->sbus_ops->unlock(priv->sbus_priv);
+               priv->hwbus_ops->unlock(priv->hwbus_priv);
        }
 
        /* Explicitly disable device interrupts */
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
        __cw1200_irq_enable(priv, 0);
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
 
        if (!term) {
                pr_err("[BH] Fatal error, exiting.\n");
index e9424e635883ac81527d64ff446fb5a16238c5b6..243e96353d137f55a40550f72d2da7be869dab98 100644 (file)
 #include "pm.h"
 
 /* Forward declarations */
-struct sbus_ops;
+struct hwbus_ops;
 struct task_struct;
 struct cw1200_debug_priv;
 struct firmware;
 
-#ifdef CONFIG_CW1200_ETF
-extern int etf_mode;
-extern char *etf_firmware;
-#endif
-
 #define CW1200_MAX_CTRL_FRAME_LEN      (0x1000)
 
 #define CW1200_MAX_STA_IN_AP_MODE      (5)
@@ -109,8 +104,8 @@ struct cw1200_common {
        u8 mac_addr[ETH_ALEN];
 
        /* Hardware interface */
-       const struct sbus_ops           *sbus_ops;
-       struct sbus_priv                *sbus_priv;
+       const struct hwbus_ops          *hwbus_ops;
+       struct hwbus_priv               *hwbus_priv;
 
        /* Hardware information */
        enum {
@@ -212,7 +207,8 @@ struct cw1200_common {
        /* Scan status */
        struct cw1200_scan scan;
        /* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid
-        * FW issue with sleeping/waking up. */
+        * FW issue with sleeping/waking up.
+        */
        atomic_t                        recent_scan;
        struct delayed_work             clear_recent_scan_work;
 
@@ -287,10 +283,6 @@ struct cw1200_common {
        struct work_struct      linkid_reset_work;
        u8                      action_frame_sa[ETH_ALEN];
        u8                      action_linkid;
-
-#ifdef CONFIG_CW1200_ETF
-       struct sk_buff_head etf_q;
-#endif
 };
 
 struct cw1200_sta_priv {
@@ -298,8 +290,8 @@ struct cw1200_sta_priv {
 };
 
 /* interfaces for the drivers */
-int cw1200_core_probe(const struct sbus_ops *sbus_ops,
-                     struct sbus_priv *sbus,
+int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
+                     struct hwbus_priv *hwbus,
                      struct device *pdev,
                      struct cw1200_common **pself,
                      int ref_clk, const u8 *macaddr,
diff --git a/drivers/net/wireless/cw1200/cw1200_sagrad.c b/drivers/net/wireless/cw1200/cw1200_sagrad.c
deleted file mode 100644 (file)
index a5ada0e..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Platform glue data for ST-Ericsson CW1200 driver
- *
- * Copyright (c) 2013, Sagrad, Inc
- * Author: Solomon Peachy <speachy@sagrad.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/cw1200_platform.h>
-
-MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
-MODULE_DESCRIPTION("ST-Ericsson CW1200 Platform glue driver");
-MODULE_LICENSE("GPL");
-
-/* Define just one of these.  Feel free to customize as needed */
-#define SAGRAD_1091_1098_EVK_SDIO
-/* #define SAGRAD_1091_1098_EVK_SPI */
-
-#ifdef SAGRAD_1091_1098_EVK_SDIO
-#if 0
-static struct resource cw1200_href_resources[] = {
-       {
-               .start = 215,  /* fix me as appropriate */
-               .end = 215,    /* ditto */
-               .flags = IORESOURCE_IO,
-               .name = "cw1200_wlan_reset",
-       },
-       {
-               .start = 216,  /* fix me as appropriate */
-               .end = 216,    /* ditto */
-               .flags = IORESOURCE_IO,
-               .name = "cw1200_wlan_powerup",
-       },
-       {
-               .start = NOMADIK_GPIO_TO_IRQ(216), /* fix me as appropriate */
-               .end = NOMADIK_GPIO_TO_IRQ(216),   /* ditto */
-               .flags = IORESOURCE_IRQ,
-               .name = "cw1200_wlan_irq",
-       },
-};
-#endif
-
-static int cw1200_power_ctrl(const struct cw1200_platform_data_sdio *pdata,
-                            bool enable)
-{
-       /* Control 3v3 and 1v8 to hardware as appropriate */
-       /* Note this is not needed if it's controlled elsewhere or always on */
-
-       /* May require delay for power to stabilize */
-       return 0;
-}
-
-static int cw1200_clk_ctrl(const struct cw1200_platform_data_sdio *pdata,
-                          bool enable)
-{
-       /* Turn CLK_32K off and on as appropriate. */
-       /* Note this is not needed if it's always on */
-
-       /* May require delay for clock to stabilize */
-       return 0;
-}
-
-static struct cw1200_platform_data_sdio cw1200_platform_data = {
-       .ref_clk = 38400,
-       .have_5ghz = false,
-#if 0
-       .reset = &cw1200_href_resources[0],
-       .powerup = &cw1200_href_resources[1],
-       .irq = &cw1200_href_resources[2],
-#endif
-       .power_ctrl = cw1200_power_ctrl,
-       .clk_ctrl = cw1200_clk_ctrl,
-/*     .macaddr = ??? */
-       .sdd_file = "sdd_sagrad_1091_1098.bin",
-};
-#endif
-
-#ifdef SAGRAD_1091_1098_EVK_SPI
-/* Note that this is an example of integrating into your board support file */
-static struct resource cw1200_href_resources[] = {
-       {
-               .start = GPIO_RF_RESET,
-               .end = GPIO_RF_RESET,
-               .flags = IORESOURCE_IO,
-               .name = "cw1200_wlan_reset",
-       },
-       {
-               .start = GPIO_RF_POWERUP,
-               .end = GPIO_RF_POWERUP,
-               .flags = IORESOURCE_IO,
-               .name = "cw1200_wlan_powerup",
-       },
-};
-
-static int cw1200_power_ctrl(const struct cw1200_platform_data_spi *pdata,
-                            bool enable)
-{
-       /* Control 3v3 and 1v8 to hardware as appropriate */
-       /* Note this is not needed if it's controlled elsewhere or always on */
-
-       /* May require delay for power to stabilize */
-       return 0;
-}
-static int cw1200_clk_ctrl(const struct cw1200_platform_data_spi *pdata,
-                          bool enable)
-{
-       /* Turn CLK_32K off and on as appropriate. */
-       /* Note this is not needed if it's always on */
-
-       /* May require delay for clock to stabilize */
-       return 0;
-}
-
-static struct cw1200_platform_data_spi cw1200_platform_data = {
-       .ref_clk = 38400,
-       .spi_bits_per_word = 16,
-       .reset = &cw1200_href_resources[0],
-       .powerup = &cw1200_href_resources[1],
-       .power_ctrl = cw1200_power_ctrl,
-       .clk_ctrl = cw1200_clk_ctrl,
-/*     .macaddr = ??? */
-       .sdd_file = "sdd_sagrad_1091_1098.bin",
-};
-static struct spi_board_info myboard_spi_devices[] __initdata = {
-       {
-               .modalias = "cw1200_wlan_spi",
-               .max_speed_hz = 10000000, /* 52MHz Max */
-               .bus_num = 0,
-               .irq = WIFI_IRQ,
-               .platform_data = &cw1200_platform_data,
-               .chip_select = 0,
-       },
-};
-#endif
-
-
-const void *cw1200_get_platform_data(void)
-{
-       return &cw1200_platform_data;
-}
-EXPORT_SYMBOL_GPL(cw1200_get_platform_data);
index 863510d062fb73be6ebd91477e93f87b12503587..ebdcdf44f1557de4230125be8862e6f333fccbc2 100644 (file)
@@ -19,8 +19,8 @@
 #include <net/mac80211.h>
 
 #include "cw1200.h"
-#include "sbus.h"
-#include <linux/cw1200_platform.h>
+#include "hwbus.h"
+#include <linux/platform_data/net-cw1200.h>
 #include "hwio.h"
 
 MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>");
@@ -29,7 +29,22 @@ MODULE_LICENSE("GPL");
 
 #define SDIO_BLOCK_SIZE (512)
 
-struct sbus_priv {
+/* Default platform data for Sagrad modules */
+static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = {
+       .ref_clk = 38400,
+       .have_5ghz = false,
+       .sdd_file = "sdd_sagrad_1091_1098.bin",
+};
+
+/* Allow platform data to be overridden */
+static struct cw1200_platform_data_sdio *global_plat_data = &sagrad_109x_evk_platform_data;
+
+void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata)
+{
+       global_plat_data = pdata;
+}
+
+struct hwbus_priv {
        struct sdio_func        *func;
        struct cw1200_common    *core;
        const struct cw1200_platform_data_sdio *pdata;
@@ -48,35 +63,35 @@ static const struct sdio_device_id cw1200_sdio_ids[] = {
        { /* end: all zeroes */                 },
 };
 
-/* sbus_ops implemetation */
+/* hwbus_ops implemetation */
 
-static int cw1200_sdio_memcpy_fromio(struct sbus_priv *self,
+static int cw1200_sdio_memcpy_fromio(struct hwbus_priv *self,
                                     unsigned int addr,
                                     void *dst, int count)
 {
        return sdio_memcpy_fromio(self->func, dst, addr, count);
 }
 
-static int cw1200_sdio_memcpy_toio(struct sbus_priv *self,
+static int cw1200_sdio_memcpy_toio(struct hwbus_priv *self,
                                   unsigned int addr,
                                   const void *src, int count)
 {
        return sdio_memcpy_toio(self->func, addr, (void *)src, count);
 }
 
-static void cw1200_sdio_lock(struct sbus_priv *self)
+static void cw1200_sdio_lock(struct hwbus_priv *self)
 {
        sdio_claim_host(self->func);
 }
 
-static void cw1200_sdio_unlock(struct sbus_priv *self)
+static void cw1200_sdio_unlock(struct hwbus_priv *self)
 {
        sdio_release_host(self->func);
 }
 
 static void cw1200_sdio_irq_handler(struct sdio_func *func)
 {
-       struct sbus_priv *self = sdio_get_drvdata(func);
+       struct hwbus_priv *self = sdio_get_drvdata(func);
 
        /* note:  sdio_host already claimed here. */
        if (self->core)
@@ -90,7 +105,7 @@ static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id)
 
 static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
 {
-       struct sbus_priv *self = dev_id;
+       struct hwbus_priv *self = dev_id;
 
        if (self->core) {
                sdio_claim_host(self->func);
@@ -102,10 +117,9 @@ static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id)
        }
 }
 
-static int cw1200_request_irq(struct sbus_priv *self)
+static int cw1200_request_irq(struct hwbus_priv *self)
 {
        int ret;
-       const struct resource *irq = self->pdata->irq;
        u8 cccr;
 
        cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret);
@@ -122,15 +136,15 @@ static int cw1200_request_irq(struct sbus_priv *self)
        if (WARN_ON(ret))
                goto err;
 
-       ret = enable_irq_wake(irq->start);
+       ret = enable_irq_wake(self->pdata->irq);
        if (WARN_ON(ret))
                goto err;
 
        /* Request the IRQ */
-       ret =  request_threaded_irq(irq->start, cw1200_gpio_hardirq,
+       ret =  request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq,
                                    cw1200_gpio_irq,
                                    IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                                   irq->name, self);
+                                   "cw1200_wlan_irq", self);
        if (WARN_ON(ret))
                goto err;
 
@@ -140,7 +154,7 @@ err:
        return ret;
 }
 
-static int cw1200_sdio_irq_subscribe(struct sbus_priv *self)
+static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self)
 {
        int ret = 0;
 
@@ -155,15 +169,15 @@ static int cw1200_sdio_irq_subscribe(struct sbus_priv *self)
        return ret;
 }
 
-static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self)
+static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self)
 {
        int ret = 0;
 
        pr_debug("SW IRQ unsubscribe\n");
 
        if (self->pdata->irq) {
-               disable_irq_wake(self->pdata->irq->start);
-               free_irq(self->pdata->irq->start, self);
+               disable_irq_wake(self->pdata->irq);
+               free_irq(self->pdata->irq, self);
        } else {
                sdio_claim_host(self->func);
                ret = sdio_release_irq(self->func);
@@ -174,12 +188,10 @@ static int cw1200_sdio_irq_unsubscribe(struct sbus_priv *self)
 
 static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
 {
-       const struct resource *reset = pdata->reset;
-
-       if (reset) {
-               gpio_set_value(reset->start, 0);
+       if (pdata->reset) {
+               gpio_set_value(pdata->reset, 0);
                msleep(30); /* Min is 2 * CLK32K cycles */
-               gpio_free(reset->start);
+               gpio_free(pdata->reset);
        }
 
        if (pdata->power_ctrl)
@@ -192,20 +204,17 @@ static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata)
 
 static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
 {
-       const struct resource *reset = pdata->reset;
-       const struct resource *powerup = pdata->reset;
-
        /* Ensure I/Os are pulled low */
-       if (reset) {
-               gpio_request(reset->start, reset->name);
-               gpio_direction_output(reset->start, 0);
+       if (pdata->reset) {
+               gpio_request(pdata->reset, "cw1200_wlan_reset");
+               gpio_direction_output(pdata->reset, 0);
        }
-       if (powerup) {
-               gpio_request(powerup->start, powerup->name);
-               gpio_direction_output(powerup->start, 0);
+       if (pdata->powerup) {
+               gpio_request(pdata->powerup, "cw1200_wlan_powerup");
+               gpio_direction_output(pdata->powerup, 0);
        }
-       if (reset || powerup)
-               msleep(50); /* Settle time */
+       if (pdata->reset || pdata->powerup)
+               msleep(10); /* Settle time? */
 
        /* Enable 3v3 and 1v8 to hardware */
        if (pdata->power_ctrl) {
@@ -225,19 +234,19 @@ static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata)
        }
 
        /* Enable POWERUP signal */
-       if (powerup) {
-               gpio_set_value(powerup->start, 1);
+       if (pdata->powerup) {
+               gpio_set_value(pdata->powerup, 1);
                msleep(250); /* or more..? */
        }
        /* Enable RSTn signal */
-       if (reset) {
-               gpio_set_value(reset->start, 1);
+       if (pdata->reset) {
+               gpio_set_value(pdata->reset, 1);
                msleep(50); /* Or more..? */
        }
        return 0;
 }
 
-static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size)
+static size_t cw1200_sdio_align_size(struct hwbus_priv *self, size_t size)
 {
        if (self->pdata->no_nptb)
                size = round_up(size, SDIO_BLOCK_SIZE);
@@ -247,18 +256,18 @@ static size_t cw1200_sdio_align_size(struct sbus_priv *self, size_t size)
        return size;
 }
 
-static int cw1200_sdio_pm(struct sbus_priv *self, bool suspend)
+static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend)
 {
        int ret = 0;
 
        if (self->pdata->irq)
-               ret = irq_set_irq_wake(self->pdata->irq->start, suspend);
+               ret = irq_set_irq_wake(self->pdata->irq, suspend);
        return ret;
 }
 
-static struct sbus_ops cw1200_sdio_sbus_ops = {
-       .sbus_memcpy_fromio     = cw1200_sdio_memcpy_fromio,
-       .sbus_memcpy_toio       = cw1200_sdio_memcpy_toio,
+static struct hwbus_ops cw1200_sdio_hwbus_ops = {
+       .hwbus_memcpy_fromio    = cw1200_sdio_memcpy_fromio,
+       .hwbus_memcpy_toio      = cw1200_sdio_memcpy_toio,
        .lock                   = cw1200_sdio_lock,
        .unlock                 = cw1200_sdio_unlock,
        .align_size             = cw1200_sdio_align_size,
@@ -267,26 +276,26 @@ static struct sbus_ops cw1200_sdio_sbus_ops = {
 
 /* Probe Function to be called by SDIO stack when device is discovered */
 static int cw1200_sdio_probe(struct sdio_func *func,
-                                      const struct sdio_device_id *id)
+                            const struct sdio_device_id *id)
 {
-       struct sbus_priv *self;
+       struct hwbus_priv *self;
        int status;
 
        pr_info("cw1200_wlan_sdio: Probe called\n");
 
-       /* We are only able to handle the wlan function */
+       /* We are only able to handle the wlan function */
        if (func->num != 0x01)
                return -ENODEV;
 
        self = kzalloc(sizeof(*self), GFP_KERNEL);
        if (!self) {
-               pr_err("Can't allocate SDIO sbus_priv.\n");
+               pr_err("Can't allocate SDIO hwbus_priv.\n");
                return -ENOMEM;
        }
 
        func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
 
-       self->pdata = cw1200_get_platform_data();
+       self->pdata = global_plat_data; /* FIXME */
        self->func = func;
        sdio_set_drvdata(func, self);
        sdio_claim_host(func);
@@ -295,7 +304,7 @@ static int cw1200_sdio_probe(struct sdio_func *func,
 
        status = cw1200_sdio_irq_subscribe(self);
 
-       status = cw1200_core_probe(&cw1200_sdio_sbus_ops,
+       status = cw1200_core_probe(&cw1200_sdio_hwbus_ops,
                                   self, &func->dev, &self->core,
                                   self->pdata->ref_clk,
                                   self->pdata->macaddr,
@@ -314,10 +323,11 @@ static int cw1200_sdio_probe(struct sdio_func *func,
 }
 
 /* Disconnect Function to be called by SDIO stack when
- * device is disconnected */
+ * device is disconnected
+ */
 static void cw1200_sdio_disconnect(struct sdio_func *func)
 {
-       struct sbus_priv *self = sdio_get_drvdata(func);
+       struct hwbus_priv *self = sdio_get_drvdata(func);
 
        if (self) {
                cw1200_sdio_irq_unsubscribe(self);
@@ -338,7 +348,7 @@ static int cw1200_sdio_suspend(struct device *dev)
 {
        int ret;
        struct sdio_func *func = dev_to_sdio_func(dev);
-       struct sbus_priv *self = sdio_get_drvdata(func);
+       struct hwbus_priv *self = sdio_get_drvdata(func);
 
        if (!cw1200_can_suspend(self->core))
                return -EAGAIN;
@@ -380,7 +390,8 @@ static int __init cw1200_sdio_init(void)
        const struct cw1200_platform_data_sdio *pdata;
        int ret;
 
-       pdata = cw1200_get_platform_data();
+       /* FIXME -- this won't support multiple devices */
+       pdata = global_plat_data;
 
        if (cw1200_sdio_on(pdata)) {
                ret = -1;
@@ -402,7 +413,9 @@ err:
 static void __exit cw1200_sdio_exit(void)
 {
        const struct cw1200_platform_data_sdio *pdata;
-       pdata = cw1200_get_platform_data();
+
+       /* FIXME -- this won't support multiple devices */
+       pdata = global_plat_data;
        sdio_unregister_driver(&sdio_driver);
        cw1200_sdio_off(pdata);
 }
index 75adef0c0cfdc14df464e45dca5f67ffdd974f20..953bd1904d3d8ed459576e65e3387ec10bea2bd8 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/device.h>
 
 #include "cw1200.h"
-#include "sbus.h"
-#include <linux/cw1200_platform.h>
+#include "hwbus.h"
+#include <linux/platform_data/net-cw1200.h>
 #include "hwio.h"
 
 MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>");
@@ -35,7 +35,7 @@ MODULE_ALIAS("spi:cw1200_wlan_spi");
 
 /* #define SPI_DEBUG */
 
-struct sbus_priv {
+struct hwbus_priv {
        struct spi_device       *func;
        struct cw1200_common    *core;
        const struct cw1200_platform_data_spi *pdata;
@@ -47,18 +47,16 @@ struct sbus_priv {
 #define SET_WRITE 0x7FFF /* usage: and operation */
 #define SET_READ 0x8000  /* usage: or operation */
 
-/*
-   Notes on byte ordering:
+/* Notes on byte ordering:
    LE:  B0 B1 B2 B3
    BE:  B3 B2 B1 B0
 
    Hardware expects 32-bit data to be written as 16-bit BE words:
 
    B1 B0 B3 B2
-
 */
 
-static int cw1200_spi_memcpy_fromio(struct sbus_priv *self,
+static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self,
                                     unsigned int addr,
                                     void *dst, int count)
 {
@@ -119,7 +117,7 @@ static int cw1200_spi_memcpy_fromio(struct sbus_priv *self,
        return ret;
 }
 
-static int cw1200_spi_memcpy_toio(struct sbus_priv *self,
+static int cw1200_spi_memcpy_toio(struct hwbus_priv *self,
                                   unsigned int addr,
                                   const void *src, int count)
 {
@@ -187,7 +185,7 @@ static int cw1200_spi_memcpy_toio(struct sbus_priv *self,
        return rval;
 }
 
-static void cw1200_spi_lock(struct sbus_priv *self)
+static void cw1200_spi_lock(struct hwbus_priv *self)
 {
        unsigned long flags;
 
@@ -209,7 +207,7 @@ static void cw1200_spi_lock(struct sbus_priv *self)
        return;
 }
 
-static void cw1200_spi_unlock(struct sbus_priv *self)
+static void cw1200_spi_unlock(struct hwbus_priv *self)
 {
        unsigned long flags;
 
@@ -221,7 +219,7 @@ static void cw1200_spi_unlock(struct sbus_priv *self)
 
 static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
 {
-       struct sbus_priv *self = dev_id;
+       struct hwbus_priv *self = dev_id;
 
        if (self->core) {
                cw1200_irq_handler(self->core);
@@ -231,7 +229,7 @@ static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id)
        }
 }
 
-static int cw1200_spi_irq_subscribe(struct sbus_priv *self)
+static int cw1200_spi_irq_subscribe(struct hwbus_priv *self)
 {
        int ret;
 
@@ -255,7 +253,7 @@ exit:
        return ret;
 }
 
-static int cw1200_spi_irq_unsubscribe(struct sbus_priv *self)
+static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self)
 {
        int ret = 0;
 
@@ -268,12 +266,10 @@ static int cw1200_spi_irq_unsubscribe(struct sbus_priv *self)
 
 static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
 {
-       const struct resource *reset = pdata->reset;
-
-       if (reset) {
-               gpio_set_value(reset->start, 0);
+       if (pdata->reset) {
+               gpio_set_value(pdata->reset, 0);
                msleep(30); /* Min is 2 * CLK32K cycles */
-               gpio_free(reset->start);
+               gpio_free(pdata->reset);
        }
 
        if (pdata->power_ctrl)
@@ -286,19 +282,16 @@ static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata)
 
 static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
 {
-       const struct resource *reset = pdata->reset;
-       const struct resource *powerup = pdata->reset;
-
        /* Ensure I/Os are pulled low */
-       if (reset) {
-               gpio_request(reset->start, reset->name);
-               gpio_direction_output(reset->start, 0);
+       if (pdata->reset) {
+               gpio_request(pdata->reset, "cw1200_wlan_reset");
+               gpio_direction_output(pdata->reset, 0);
        }
-       if (powerup) {
-               gpio_request(powerup->start, powerup->name);
-               gpio_direction_output(powerup->start, 0);
+       if (pdata->powerup) {
+               gpio_request(pdata->powerup, "cw1200_wlan_powerup");
+               gpio_direction_output(pdata->powerup, 0);
        }
-       if (reset || powerup)
+       if (pdata->reset || pdata->powerup)
                msleep(10); /* Settle time? */
 
        /* Enable 3v3 and 1v8 to hardware */
@@ -319,31 +312,31 @@ static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata)
        }
 
        /* Enable POWERUP signal */
-       if (powerup) {
-               gpio_set_value(powerup->start, 1);
+       if (pdata->powerup) {
+               gpio_set_value(pdata->powerup, 1);
                msleep(250); /* or more..? */
        }
        /* Enable RSTn signal */
-       if (reset) {
-               gpio_set_value(reset->start, 1);
+       if (pdata->reset) {
+               gpio_set_value(pdata->reset, 1);
                msleep(50); /* Or more..? */
        }
        return 0;
 }
 
-static size_t cw1200_spi_align_size(struct sbus_priv *self, size_t size)
+static size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size)
 {
        return size & 1 ? size + 1 : size;
 }
 
-static int cw1200_spi_pm(struct sbus_priv *self, bool suspend)
+static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend)
 {
        return irq_set_irq_wake(self->func->irq, suspend);
 }
 
-static struct sbus_ops cw1200_spi_sbus_ops = {
-       .sbus_memcpy_fromio     = cw1200_spi_memcpy_fromio,
-       .sbus_memcpy_toio       = cw1200_spi_memcpy_toio,
+static struct hwbus_ops cw1200_spi_hwbus_ops = {
+       .hwbus_memcpy_fromio    = cw1200_spi_memcpy_fromio,
+       .hwbus_memcpy_toio      = cw1200_spi_memcpy_toio,
        .lock                   = cw1200_spi_lock,
        .unlock                 = cw1200_spi_unlock,
        .align_size             = cw1200_spi_align_size,
@@ -355,7 +348,7 @@ static int cw1200_spi_probe(struct spi_device *func)
 {
        const struct cw1200_platform_data_spi *plat_data =
                func->dev.platform_data;
-       struct sbus_priv *self;
+       struct hwbus_priv *self;
        int status;
 
        /* Sanity check speed */
@@ -389,7 +382,7 @@ static int cw1200_spi_probe(struct spi_device *func)
 
        self = kzalloc(sizeof(*self), GFP_KERNEL);
        if (!self) {
-               pr_err("Can't allocate SPI sbus_priv.");
+               pr_err("Can't allocate SPI hwbus_priv.");
                return -ENOMEM;
        }
 
@@ -401,7 +394,7 @@ static int cw1200_spi_probe(struct spi_device *func)
 
        status = cw1200_spi_irq_subscribe(self);
 
-       status = cw1200_core_probe(&cw1200_spi_sbus_ops,
+       status = cw1200_core_probe(&cw1200_spi_hwbus_ops,
                                   self, &func->dev, &self->core,
                                   self->pdata->ref_clk,
                                   self->pdata->macaddr,
@@ -420,7 +413,7 @@ static int cw1200_spi_probe(struct spi_device *func)
 /* Disconnect Function to be called by SPI stack when device is disconnected */
 static int cw1200_spi_disconnect(struct spi_device *func)
 {
-       struct sbus_priv *self = spi_get_drvdata(func);
+       struct hwbus_priv *self = spi_get_drvdata(func);
 
        if (self) {
                cw1200_spi_irq_unsubscribe(self);
@@ -438,7 +431,7 @@ static int cw1200_spi_disconnect(struct spi_device *func)
 #ifdef CONFIG_PM
 static int cw1200_spi_suspend(struct device *dev, pm_message_t state)
 {
-       struct sbus_priv *self = spi_get_drvdata(to_spi_device(dev));
+       struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
 
        if (!cw1200_can_suspend(self->core))
                return -EAGAIN;
index eb40c9c61a512987711ca3d7fd25a2948c677439..e323b4d54338e490b5424c89cccd7a0ec19fc832 100644 (file)
@@ -357,134 +357,6 @@ static const struct file_operations fops_counters = {
        .owner = THIS_MODULE,
 };
 
-#ifdef CONFIG_CW1200_ETF
-static int cw1200_etf_out_show(struct seq_file *seq, void *v)
-{
-       struct cw1200_common *priv = seq->private;
-       struct sk_buff *skb;
-       u32 len = 0;
-
-       skb = skb_dequeue(&priv->etf_q);
-
-       if (skb)
-               len = skb->len;
-
-       seq_write(seq, &len, sizeof(len));
-
-       if (skb) {
-               seq_write(seq, skb->data, len);
-               kfree_skb(skb);
-       }
-
-       return 0;
-}
-
-static int cw1200_etf_out_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, &cw1200_etf_out_show,
-                          inode->i_private);
-}
-
-static const struct file_operations fops_etf_out = {
-       .open = cw1200_etf_out_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = single_release,
-       .owner = THIS_MODULE,
-};
-
-struct etf_req_msg;
-static int etf_request(struct cw1200_common *priv,
-                      struct etf_req_msg *msg, u32 len);
-
-#define MAX_RX_SZE 2600
-
-struct etf_in_state {
-       struct cw1200_common *priv;
-       u32 total_len;
-       u8 buf[MAX_RX_SZE];
-       u32 written;
-};
-
-static int cw1200_etf_in_open(struct inode *inode, struct file *file)
-{
-       struct etf_in_state *etf = kmalloc(sizeof(struct etf_in_state),
-                                          GFP_KERNEL);
-
-       if (!etf)
-               return -ENOMEM;
-
-       etf->written = 0;
-       etf->total_len = 0;
-       etf->priv = inode->i_private;
-
-       file->private_data = etf;
-
-       return 0;
-}
-
-static int cw1200_etf_in_release(struct inode *inode, struct file *file)
-{
-       kfree(file->private_data);
-       return 0;
-}
-
-static ssize_t cw1200_etf_in_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       struct etf_in_state *etf = file->private_data;
-
-       ssize_t written = 0;
-
-       if (!etf->total_len) {
-               if (count < sizeof(etf->total_len)) {
-                       pr_err("count < sizeof(total_len)\n");
-                       return -EINVAL;
-               }
-
-               if (copy_from_user(&etf->total_len, user_buf,
-                                  sizeof(etf->total_len))) {
-                       pr_err("copy_from_user (len) failed\n");
-                       return -EFAULT;
-               }
-
-               written += sizeof(etf->total_len);
-               count -= sizeof(etf->total_len);
-       }
-
-       if (!count)
-               goto done;
-
-       if (copy_from_user(etf->buf + etf->written, user_buf + written,
-                          count)) {
-               pr_err("copy_from_user (payload %zu) failed\n", count);
-               return -EFAULT;
-       }
-
-       written += count;
-       etf->written += count;
-
-       if (etf->written >= etf->total_len) {
-               if (etf_request(etf->priv, (struct etf_req_msg *)etf->buf,
-                               etf->total_len)) {
-                       pr_err("etf_request failed\n");
-                       return -EIO;
-               }
-       }
-
-done:
-       return written;
-}
-
-static const struct file_operations fops_etf_in = {
-       .open = cw1200_etf_in_open,
-       .release = cw1200_etf_in_release,
-       .write = cw1200_etf_in_write,
-       .llseek = default_llseek,
-       .owner = THIS_MODULE,
-};
-#endif /* CONFIG_CW1200_ETF */
-
 static ssize_t cw1200_wsm_dumps(struct file *file,
        const char __user *user_buf, size_t count, loff_t *ppos)
 {
@@ -532,27 +404,10 @@ int cw1200_debug_init(struct cw1200_common *priv)
                                 priv, &fops_counters))
                goto err;
 
-#ifdef CONFIG_CW1200_ETF
-       if (etf_mode) {
-               skb_queue_head_init(&priv->etf_q);
-
-               if (!debugfs_create_file("etf_out", S_IRUSR, d->debugfs_phy,
-                                        priv, &fops_etf_out))
-                       goto err;
-               if (!debugfs_create_file("etf_in", S_IWUSR, d->debugfs_phy,
-                                        priv, &fops_etf_in))
-                       goto err;
-       }
-#endif /* CONFIG_CW1200_ETF */
-
        if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy,
                                 priv, &fops_wsm_dumps))
                goto err;
 
-       ret = cw1200_itp_init(priv);
-       if (ret)
-               goto err;
-
        return 0;
 
 err:
@@ -566,93 +421,8 @@ void cw1200_debug_release(struct cw1200_common *priv)
 {
        struct cw1200_debug_priv *d = priv->debug;
        if (d) {
-               cw1200_itp_release(priv);
+               debugfs_remove_recursive(d->debugfs_phy);
                priv->debug = NULL;
                kfree(d);
        }
 }
-
-#ifdef CONFIG_CW1200_ETF
-struct cw1200_sdd {
-       u8 id;
-       u8 len;
-       u8 data[];
-};
-
-struct etf_req_msg {
-       u32 id;
-       u32 len;
-       u8 data[];
-};
-
-static int parse_sdd_file(struct cw1200_common *priv, u8 *data, u32 length)
-{
-       struct cw1200_sdd *ie;
-
-       while (length > 0) {
-               ie = (struct cw1200_sdd *)data;
-               if (ie->id == SDD_REFERENCE_FREQUENCY_ELT_ID) {
-                       priv->hw_refclk = cpu_to_le16(*((u16 *)ie->data));
-                       pr_info("Using Reference clock frequency %d KHz\n",
-                               priv->hw_refclk);
-                       break;
-               }
-
-               length -= ie->len + sizeof(*ie);
-               data += ie->len + sizeof(*ie);
-       }
-       return 0;
-}
-
-char *etf_firmware;
-
-#define ST90TDS_START_ADAPTER           0x09 /* Loads firmware too */
-#define ST90TDS_STOP_ADAPTER            0x0A
-#define ST90TDS_CONFIG_ADAPTER          0x0E /* Send configuration params */
-#define ST90TDS_SBUS_READ               0x13
-#define ST90TDS_SBUS_WRITE              0x14
-#define ST90TDS_GET_DEVICE_OPTION       0x19
-#define ST90TDS_SET_DEVICE_OPTION       0x1A
-#define ST90TDS_SEND_SDD                0x1D /* SDD File used to find DPLL */
-
-#include "fwio.h"
-
-static int etf_request(struct cw1200_common *priv,
-                      struct etf_req_msg *msg,
-                      u32 len)
-{
-       int rval = -1;
-       switch (msg->id) {
-       case ST90TDS_START_ADAPTER:
-               etf_firmware = "cw1200_etf.bin";
-               pr_info("ETF_START (len %d, '%s')\n", len, etf_firmware);
-               rval = cw1200_load_firmware(priv);
-               break;
-       case ST90TDS_STOP_ADAPTER:
-               pr_info("ETF_STOP (unhandled)\n");
-               break;
-       case ST90TDS_SEND_SDD:
-               pr_info("ETF_SDD\n");
-               rval = parse_sdd_file(priv, msg->data, msg->len);
-               break;
-       case ST90TDS_CONFIG_ADAPTER:
-               pr_info("ETF_CONFIG_ADAP (unhandled)\n");
-               break;
-       case ST90TDS_SBUS_READ:
-               pr_info("ETF_SBUS_READ (unhandled)\n");
-               break;
-       case ST90TDS_SBUS_WRITE:
-               pr_info("ETF_SBUS_WRITE (unhandled)\n");
-               break;
-       case ST90TDS_SET_DEVICE_OPTION:
-               pr_info("ETF_SET_DEV_OPT (unhandled)\n");
-               break;
-       default:
-               pr_info("ETF_PASSTHRU (0x%08x)\n", msg->id);
-               rval = wsm_raw_cmd(priv, (u8 *)msg, len);
-               break;
-       }
-
-       return rval;
-}
-#endif /* CONFIG_CW1200_ETF */
index 1fea5b29a8194617efeff76db7b5fc941d56308d..b525aba53bfc05913e3caf99dd38c1302336e19a 100644 (file)
@@ -12,8 +12,6 @@
 #ifndef CW1200_DEBUG_H_INCLUDED
 #define CW1200_DEBUG_H_INCLUDED
 
-#include "itp.h"
-
 struct cw1200_debug_priv {
        struct dentry *debugfs_phy;
        int tx;
@@ -30,9 +28,6 @@ struct cw1200_debug_priv {
        int ba_acc;
        int ba_cnt_rx;
        int ba_acc_rx;
-#ifdef CONFIG_CW1200_ITP
-       struct cw1200_itp itp;
-#endif /* CONFIG_CW1200_ITP */
 };
 
 int cw1200_debug_init(struct cw1200_common *priv);
index ad01cd2a59ecdfc17489c72967b8931d49a54f08..acdff0f7f952e03fa25b51b47a9e83eda37d85c6 100644 (file)
@@ -22,7 +22,7 @@
 #include "cw1200.h"
 #include "fwio.h"
 #include "hwio.h"
-#include "sbus.h"
+#include "hwbus.h"
 #include "bh.h"
 
 static int cw1200_get_hw_type(u32 config_reg_val, int *major_revision)
@@ -139,11 +139,6 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
        val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT;
        REG_WRITE(ST90TDS_CONFIG_REG_ID, val32);
 
-#ifdef CONFIG_CW1200_ETF
-       if (etf_mode)
-               fw_path = etf_firmware;
-#endif
-
        /* Load a firmware file */
        ret = request_firmware(&firmware, fw_path, priv->pdev);
        if (ret) {
@@ -489,9 +484,9 @@ int cw1200_load_firmware(struct cw1200_common *priv)
        }
 
        /* Enable interrupt signalling */
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
        ret = __cw1200_irq_enable(priv, 1);
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        if (ret < 0)
                goto unsubscribe;
 
@@ -518,8 +513,8 @@ out:
 
 unsubscribe:
        /* Disable interrupt signalling */
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
        ret = __cw1200_irq_enable(priv, 0);
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
diff --git a/drivers/net/wireless/cw1200/hwbus.h b/drivers/net/wireless/cw1200/hwbus.h
new file mode 100644 (file)
index 0000000..8b2fc83
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Common hwbus abstraction layer interface for cw1200 wireless driver
+ *
+ * Copyright (c) 2010, ST-Ericsson
+ * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef CW1200_HWBUS_H
+#define CW1200_HWBUS_H
+
+struct hwbus_priv;
+
+void cw1200_irq_handler(struct cw1200_common *priv);
+
+/* This MUST be wrapped with hwbus_ops->lock/unlock! */
+int __cw1200_irq_enable(struct cw1200_common *priv, int enable);
+
+struct hwbus_ops {
+       int (*hwbus_memcpy_fromio)(struct hwbus_priv *self, unsigned int addr,
+                                       void *dst, int count);
+       int (*hwbus_memcpy_toio)(struct hwbus_priv *self, unsigned int addr,
+                                       const void *src, int count);
+       void (*lock)(struct hwbus_priv *self);
+       void (*unlock)(struct hwbus_priv *self);
+       size_t (*align_size)(struct hwbus_priv *self, size_t size);
+       int (*power_mgmt)(struct hwbus_priv *self, bool suspend);
+};
+
+#endif /* CW1200_HWBUS_H */
index 1af7b3d421b222644358f2302db8ca6e2e3c8908..dad3fb3318180467d70551aebe77172cf9a1275d 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "cw1200.h"
 #include "hwio.h"
-#include "sbus.h"
+#include "hwbus.h"
 
  /* Sdio addr is 4*spi_addr */
 #define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2)
@@ -46,7 +46,7 @@ static int __cw1200_reg_read(struct cw1200_common *priv, u16 addr,
        addr_sdio = SPI_REG_ADDR_TO_SDIO(addr);
        sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio);
 
-       return priv->sbus_ops->sbus_memcpy_fromio(priv->sbus_priv,
+       return priv->hwbus_ops->hwbus_memcpy_fromio(priv->hwbus_priv,
                                                  sdio_reg_addr_17bit,
                                                  buf, buf_len);
 }
@@ -61,7 +61,7 @@ static int __cw1200_reg_write(struct cw1200_common *priv, u16 addr,
        addr_sdio = SPI_REG_ADDR_TO_SDIO(addr);
        sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio);
 
-       return priv->sbus_ops->sbus_memcpy_toio(priv->sbus_priv,
+       return priv->hwbus_ops->hwbus_memcpy_toio(priv->hwbus_priv,
                                                sdio_reg_addr_17bit,
                                                buf, buf_len);
 }
@@ -100,9 +100,9 @@ int cw1200_reg_read(struct cw1200_common *priv, u16 addr, void *buf,
                        size_t buf_len)
 {
        int ret;
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
        ret = __cw1200_reg_read(priv, addr, buf, buf_len, 0);
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
 
@@ -110,9 +110,9 @@ int cw1200_reg_write(struct cw1200_common *priv, u16 addr, const void *buf,
                        size_t buf_len)
 {
        int ret;
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
        ret = __cw1200_reg_write(priv, addr, buf, buf_len, 0);
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
 
@@ -121,7 +121,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len)
        int ret, retry = 1;
        int buf_id_rx = priv->buf_id_rx;
 
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
 
        while (retry <= MAX_RETRY) {
                ret = __cw1200_reg_read(priv,
@@ -138,7 +138,7 @@ int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len)
                }
        }
 
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
 
@@ -148,7 +148,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf,
        int ret, retry = 1;
        int buf_id_tx = priv->buf_id_tx;
 
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
 
        while (retry <= MAX_RETRY) {
                ret = __cw1200_reg_write(priv,
@@ -165,7 +165,7 @@ int cw1200_data_write(struct cw1200_common *priv, const void *buf,
                }
        }
 
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
 
@@ -178,10 +178,9 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf,
        if ((buf_len / 2) >= 0x1000) {
                pr_err("Can't read more than 0xfff words.\n");
                return -EINVAL;
-               goto out;
        }
 
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
        /* Write address */
        ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr);
        if (ret < 0) {
@@ -230,7 +229,7 @@ int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf,
        }
 
 out:
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
 
@@ -244,7 +243,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf,
                return -EINVAL;
        }
 
-       priv->sbus_ops->lock(priv->sbus_priv);
+       priv->hwbus_ops->lock(priv->hwbus_priv);
 
        /* Write address */
        ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr);
@@ -262,7 +261,7 @@ int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf,
        }
 
 out:
-       priv->sbus_ops->unlock(priv->sbus_priv);
+       priv->hwbus_ops->unlock(priv->hwbus_priv);
        return ret;
 }
 
index 7ee73fe32ccf56d310f43d4d66e180813fae9d6e..563329cfead65eeac3e1596ef424e7248cabe959 100644 (file)
@@ -97,9 +97,8 @@ struct download_cntl_t {
 
 #define CW1200_APB(addr)               (PAC_SHARED_MEMORY_SILICON + (addr))
 
-/* ***************************************************************
-*Device register definitions
-*************************************************************** */
+/* Device register definitions */
+
 /* WBF - SPI Register Addresses */
 #define ST90TDS_ADDR_ID_BASE           (0x0000)
 /* 16/32 bits */
diff --git a/drivers/net/wireless/cw1200/itp.c b/drivers/net/wireless/cw1200/itp.c
deleted file mode 100644 (file)
index c0730bb..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-/*
- * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers
- * ITP code
- *
- * Copyright (c) 2010, ST-Ericsson
- * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/poll.h>
-#include <linux/time.h>
-#include <linux/random.h>
-#include <linux/kallsyms.h>
-#include <net/mac80211.h>
-#include "cw1200.h"
-#include "debug.h"
-#include "itp.h"
-#include "sta.h"
-
-static int __cw1200_itp_open(struct cw1200_common *priv);
-static int __cw1200_itp_close(struct cw1200_common *priv);
-static void cw1200_itp_rx_start(struct cw1200_common *priv);
-static void cw1200_itp_rx_stop(struct cw1200_common *priv);
-static void cw1200_itp_rx_stats(struct cw1200_common *priv);
-static void cw1200_itp_rx_reset(struct cw1200_common *priv);
-static void cw1200_itp_tx_stop(struct cw1200_common *priv);
-static void cw1200_itp_handle(struct cw1200_common *priv,
-                             struct sk_buff *skb);
-static void cw1200_itp_err(struct cw1200_common *priv,
-                          int err,
-                          int arg);
-static void __cw1200_itp_tx_stop(struct cw1200_common *priv);
-
-static ssize_t cw1200_itp_read(struct file *file,
-       char __user *user_buf, size_t count, loff_t *ppos)
-{
-       struct cw1200_common *priv = file->private_data;
-       struct cw1200_itp *itp = &priv->debug->itp;
-       struct sk_buff *skb;
-       int ret;
-
-       if (skb_queue_empty(&itp->log_queue))
-               return 0;
-
-       skb = skb_dequeue(&itp->log_queue);
-       ret = copy_to_user(user_buf, skb->data, skb->len);
-       *ppos += skb->len;
-       skb->data[skb->len] = 0;
-       pr_debug("[ITP] >>> %s", skb->data);
-       consume_skb(skb);
-
-       return skb->len - ret;
-}
-
-static ssize_t cw1200_itp_write(struct file *file,
-       const char __user *user_buf, size_t count, loff_t *ppos)
-{
-       struct cw1200_common *priv = file->private_data;
-       struct sk_buff *skb;
-
-       if (!count || count > 1024)
-               return -EINVAL;
-       skb = dev_alloc_skb(count + 1);
-       if (!skb)
-               return -ENOMEM;
-       skb_trim(skb, 0);
-       skb_put(skb, count + 1);
-       if (copy_from_user(skb->data, user_buf, count)) {
-               kfree_skb(skb);
-               return -EFAULT;
-       }
-       skb->data[count] = 0;
-
-       cw1200_itp_handle(priv, skb);
-       consume_skb(skb);
-       return count;
-}
-
-static unsigned int cw1200_itp_poll(struct file *file, poll_table *wait)
-{
-       struct cw1200_common *priv = file->private_data;
-       struct cw1200_itp *itp = &priv->debug->itp;
-       unsigned int mask = 0;
-
-       poll_wait(file, &itp->read_wait, wait);
-
-       if (!skb_queue_empty(&itp->log_queue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mask |= POLLOUT | POLLWRNORM;
-
-       return mask;
-}
-
-static int cw1200_itp_open(struct inode *inode, struct file *file)
-{
-       struct cw1200_common *priv = inode->i_private;
-       struct cw1200_itp *itp = &priv->debug->itp;
-       int ret = 0;
-
-       file->private_data = priv;
-       if (atomic_inc_return(&itp->open_count) == 1) {
-               ret = __cw1200_itp_open(priv);
-               if (ret && !atomic_dec_return(&itp->open_count))
-                       __cw1200_itp_close(priv);
-       } else {
-               atomic_dec(&itp->open_count);
-               ret = -EBUSY;
-       }
-
-       return ret;
-}
-
-static int cw1200_itp_close(struct inode *inode, struct file *file)
-{
-       struct cw1200_common *priv = file->private_data;
-       struct cw1200_itp *itp = &priv->debug->itp;
-       if (!atomic_dec_return(&itp->open_count)) {
-               __cw1200_itp_close(priv);
-               wake_up(&itp->close_wait);
-       }
-       return 0;
-}
-
-static const struct file_operations fops_itp = {
-       .open = cw1200_itp_open,
-       .read = cw1200_itp_read,
-       .write = cw1200_itp_write,
-       .poll = cw1200_itp_poll,
-       .release = cw1200_itp_close,
-       .llseek = default_llseek,
-       .owner = THIS_MODULE,
-};
-
-static void cw1200_itp_fill_pattern(u8 *data, int size,
-               enum cw1200_itp_data_modes mode)
-{
-       if (size <= 0)
-               return;
-
-       switch (mode) {
-       default:
-       case ITP_DATA_ZEROS:
-               memset(data, 0x0, size);
-               break;
-       case ITP_DATA_ONES:
-               memset(data, 0xff, size);
-               break;
-       case ITP_DATA_ZERONES:
-               memset(data, 0x55, size);
-               break;
-       case ITP_DATA_RANDOM:
-               get_random_bytes(data, size);
-               break;
-       }
-       return;
-}
-
-static void cw1200_itp_tx_work(struct work_struct *work)
-{
-       struct cw1200_itp *itp = container_of(work, struct cw1200_itp,
-                   tx_work.work);
-       struct cw1200_common *priv = itp->priv;
-       atomic_set(&priv->bh_tx, 1);
-       wake_up(&priv->bh_wq);
-}
-
-static void cw1200_itp_tx_finish(struct work_struct *work)
-{
-       struct cw1200_itp *itp = container_of(work, struct cw1200_itp,
-                   tx_finish.work);
-       __cw1200_itp_tx_stop(itp->priv);
-}
-
-int cw1200_itp_init(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-
-       itp->priv = priv;
-       atomic_set(&itp->open_count, 0);
-       atomic_set(&itp->stop_tx, 0);
-       atomic_set(&itp->awaiting_confirm, 0);
-       skb_queue_head_init(&itp->log_queue);
-       spin_lock_init(&itp->tx_lock);
-       init_waitqueue_head(&itp->read_wait);
-       init_waitqueue_head(&itp->write_wait);
-       init_waitqueue_head(&itp->close_wait);
-       INIT_DELAYED_WORK(&itp->tx_work, cw1200_itp_tx_work);
-       INIT_DELAYED_WORK(&itp->tx_finish, cw1200_itp_tx_finish);
-       itp->data = NULL;
-       itp->hdr_len = WSM_TX_EXTRA_HEADROOM +
-                       sizeof(struct ieee80211_hdr_3addr);
-
-       if (!debugfs_create_file("itp", S_IRUSR | S_IWUSR,
-                                priv->debug->debugfs_phy, priv, &fops_itp))
-               return -ENOMEM;
-
-       return 0;
-}
-
-void cw1200_itp_release(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-
-       wait_event_interruptible(itp->close_wait,
-                                !atomic_read(&itp->open_count));
-
-       WARN_ON(atomic_read(&itp->open_count));
-
-       skb_queue_purge(&itp->log_queue);
-       cw1200_itp_tx_stop(priv);
-}
-
-static int __cw1200_itp_open(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-
-       if (!priv->vif)
-               return -EINVAL;
-       if (priv->join_status)
-               return -EINVAL;
-       itp->saved_channel = priv->channel;
-       if (!priv->channel)
-               priv->channel = &priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0];
-       wsm_set_bssid_filtering(priv, false);
-       cw1200_itp_rx_reset(priv);
-       return 0;
-}
-
-static int __cw1200_itp_close(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       if (atomic_read(&itp->test_mode) == TEST_MODE_RX_TEST)
-               cw1200_itp_rx_stop(priv);
-       cw1200_itp_tx_stop(priv);
-       cw1200_disable_listening(priv);
-       cw1200_update_filtering(priv);
-       priv->channel = itp->saved_channel;
-       return 0;
-}
-
-bool cw1200_is_itp(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       return atomic_read(&itp->open_count) != 0;
-}
-
-static void cw1200_itp_rx_reset(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       itp->rx_cnt = 0;
-       itp->rx_rssi = 0;
-       itp->rx_rssi_max = -1000;
-       itp->rx_rssi_min = 1000;
-}
-
-static void cw1200_itp_rx_start(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-
-       pr_debug("[ITP] RX start, band = %d, ch = %d\n",
-                itp->band, itp->ch);
-       atomic_set(&itp->test_mode, TEST_MODE_RX_TEST);
-       cw1200_update_listening(priv, false);
-       priv->channel = &priv->hw->
-               wiphy->bands[itp->band]->channels[itp->ch];
-       cw1200_update_listening(priv, true);
-       wsm_set_bssid_filtering(priv, false);
-}
-
-static void cw1200_itp_rx_stop(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       pr_debug("[ITP] RX stop\n");
-       atomic_set(&itp->test_mode, TEST_MODE_NO_TEST);
-       cw1200_itp_rx_reset(priv);
-}
-
-static void cw1200_itp_rx_stats(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       struct sk_buff *skb;
-       char buf[128];
-       int len, ret;
-       struct wsm_mib_counters_table counters;
-
-       ret = wsm_get_counters_table(priv, &counters);
-
-       if (ret)
-               cw1200_itp_err(priv, -EBUSY, 20);
-
-       if (!itp->rx_cnt)
-               len = snprintf(buf, sizeof(buf), "1,0,0,0,0,%d\n",
-                              counters.rx_packet_errors);
-       else
-               len = snprintf(buf, sizeof(buf), "1,%d,%ld,%d,%d,%d\n",
-                              itp->rx_cnt,
-                              itp->rx_cnt ? itp->rx_rssi / itp->rx_cnt : 0,
-                              itp->rx_rssi_min, itp->rx_rssi_max,
-                              counters.rx_packet_errors);
-
-       if (len <= 0) {
-               cw1200_itp_err(priv, -EBUSY, 21);
-               return;
-       }
-
-       skb = dev_alloc_skb(len);
-       if (!skb) {
-               cw1200_itp_err(priv, -ENOMEM, 22);
-               return;
-       }
-
-       itp->rx_cnt = 0;
-       itp->rx_rssi = 0;
-       itp->rx_rssi_max = -1000;
-       itp->rx_rssi_min = 1000;
-
-       skb_trim(skb, 0);
-       skb_put(skb, len);
-
-       memcpy(skb->data, buf, len);
-       skb_queue_tail(&itp->log_queue, skb);
-       wake_up(&itp->read_wait);
-}
-
-static void cw1200_itp_tx_start(struct cw1200_common *priv)
-{
-       struct wsm_tx *tx;
-       struct ieee80211_hdr_3addr *hdr;
-       struct cw1200_itp *itp = &priv->debug->itp;
-       struct wsm_mib_association_mode assoc_mode = {
-               .flags = WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE,
-               .preamble = itp->preamble,
-       };
-       int len;
-       u8 da_addr[6] = ITP_DEFAULT_DA_ADDR;
-
-       /* Rates index 4 and 5 are not supported */
-       if (itp->rate > 3)
-               itp->rate += 2;
-
-       pr_debug("[ITP] TX start: band = %d, ch = %d, rate = %d, preamble = %d, number = %d, data_mode = %d, interval = %d, power = %d, data_len = %d\n",
-                itp->band, itp->ch, itp->rate, itp->preamble,
-                itp->number, itp->data_mode, itp->interval_us,
-                itp->power, itp->data_len);
-
-       len = itp->hdr_len + itp->data_len;
-
-       itp->data = kmalloc(len, GFP_KERNEL);
-       tx = (struct wsm_tx *)itp->data;
-       tx->hdr.len = itp->data_len + itp->hdr_len;
-       tx->hdr.id = __cpu_to_le16(0x0004 | 1 << 6);
-       tx->max_tx_rate = itp->rate;
-       tx->queue_id = 3;
-       tx->more = 0;
-       tx->flags = 0xc;
-       tx->packet_id = 0x55ff55;
-       tx->reserved = 0;
-       tx->expire_time = 1;
-
-       if (itp->preamble == ITP_PREAMBLE_GREENFIELD)
-               tx->ht_tx_parameters = WSM_HT_TX_GREENFIELD;
-       else if (itp->preamble == ITP_PREAMBLE_MIXED)
-               tx->ht_tx_parameters = WSM_HT_TX_MIXED;
-
-       hdr = (struct ieee80211_hdr_3addr *)&itp->data[sizeof(struct wsm_tx)];
-       memset(hdr, 0, sizeof(*hdr));
-       hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS);
-       memcpy(hdr->addr1, da_addr, ETH_ALEN);
-       memcpy(hdr->addr2, priv->vif->addr, ETH_ALEN);
-       memcpy(hdr->addr3, da_addr, ETH_ALEN);
-
-       cw1200_itp_fill_pattern(&itp->data[itp->hdr_len],
-                               itp->data_len, itp->data_mode);
-
-       cw1200_update_listening(priv, false);
-       priv->channel = &priv->hw->wiphy->bands[itp->band]->channels[itp->ch];
-       WARN_ON(wsm_set_output_power(priv, itp->power));
-       if (itp->preamble == ITP_PREAMBLE_SHORT ||
-           itp->preamble == ITP_PREAMBLE_LONG)
-               WARN_ON(wsm_set_association_mode(priv,
-                                                &assoc_mode));
-       wsm_set_bssid_filtering(priv, false);
-       cw1200_update_listening(priv, true);
-
-       spin_lock_bh(&itp->tx_lock);
-       atomic_set(&itp->test_mode, TEST_MODE_TX_TEST);
-       atomic_set(&itp->awaiting_confirm, 0);
-       atomic_set(&itp->stop_tx, 0);
-       atomic_set(&priv->bh_tx, 1);
-       ktime_get_ts(&itp->last_sent);
-       wake_up(&priv->bh_wq);
-       spin_unlock_bh(&itp->tx_lock);
-}
-
-void __cw1200_itp_tx_stop(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       spin_lock_bh(&itp->tx_lock);
-       kfree(itp->data);
-       itp->data = NULL;
-       atomic_set(&itp->test_mode, TEST_MODE_NO_TEST);
-       spin_unlock_bh(&itp->tx_lock);
-}
-
-static void cw1200_itp_tx_stop(struct cw1200_common *priv)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       pr_debug("[ITP] TX stop\n");
-       atomic_set(&itp->stop_tx, 1);
-       flush_workqueue(priv->workqueue);
-
-       /* time for FW to confirm all tx requests */
-       msleep(500);
-
-       __cw1200_itp_tx_stop(priv);
-}
-
-static int cw1200_print_fw_version(struct cw1200_common *priv,
-                                  u8 *buf, size_t len)
-{
-       return snprintf(buf, len, "%s %d.%d",
-                       cw1200_fw_types[priv->wsm_caps.fw_type],
-                       priv->wsm_caps.fw_ver,
-                       priv->wsm_caps.fw_build);
-}
-
-static void cw1200_itp_get_version(struct cw1200_common *priv,
-               enum cw1200_itp_version_type type)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       struct sk_buff *skb;
-       char buf[ITP_BUF_SIZE];
-       size_t size = 0;
-       int len;
-       pr_debug("[ITP] print %s version\n",
-                type == ITP_CHIP_ID ? "chip" : "firmware");
-
-       len = snprintf(buf, ITP_BUF_SIZE, "2,");
-       if (len <= 0) {
-               cw1200_itp_err(priv, -EINVAL, 40);
-               return;
-       }
-       size += len;
-
-       switch (type) {
-       case ITP_CHIP_ID:
-               len = cw1200_print_fw_version(priv, buf+size,
-                               ITP_BUF_SIZE - size);
-
-               if (len <= 0) {
-                       cw1200_itp_err(priv, -EINVAL, 41);
-                       return;
-               }
-               size += len;
-               break;
-       case ITP_FW_VER:
-               len = snprintf(buf+size, ITP_BUF_SIZE - size,
-                               "%d.%d", priv->wsm_caps.hw_id,
-                               priv->wsm_caps.hw_subid);
-               if (len <= 0) {
-                       cw1200_itp_err(priv, -EINVAL, 42);
-                       return;
-               }
-               size += len;
-               break;
-       default:
-               cw1200_itp_err(priv, -EINVAL, 43);
-               break;
-       }
-
-       len = snprintf(buf+size, ITP_BUF_SIZE-size, "\n");
-       if (len <= 0) {
-               cw1200_itp_err(priv, -EINVAL, 44);
-               return;
-       }
-       size += len;
-
-       skb = dev_alloc_skb(size);
-       if (!skb) {
-               cw1200_itp_err(priv, -ENOMEM, 45);
-               return;
-       }
-
-       skb_trim(skb, 0);
-       skb_put(skb, size);
-
-       memcpy(skb->data, buf, size);
-       skb_queue_tail(&itp->log_queue, skb);
-       wake_up(&itp->read_wait);
-}
-
-int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data,
-               size_t *tx_len, int *burst)
-{
-       struct cw1200_itp *itp;
-       struct timespec now;
-       int time_left_us;
-
-       if (!priv->debug)
-               return 0;
-
-       itp     = &priv->debug->itp;
-
-       if (!itp)
-               return 0;
-
-       spin_lock_bh(&itp->tx_lock);
-       if (atomic_read(&itp->test_mode) != TEST_MODE_TX_TEST)
-               goto out;
-
-       if (atomic_read(&itp->stop_tx))
-               goto out;
-
-       if (itp->number == 0) {
-               atomic_set(&itp->stop_tx, 1);
-               queue_delayed_work(priv->workqueue, &itp->tx_finish, HZ/10);
-               goto out;
-       }
-
-       if (!itp->data)
-               goto out;
-
-       if (priv->hw_bufs_used >= 2) {
-               if (!atomic_read(&priv->bh_rx))
-                       atomic_set(&priv->bh_rx, 1);
-               atomic_set(&priv->bh_tx, 1);
-               goto out;
-       }
-
-       ktime_get_ts(&now);
-       time_left_us = (itp->last_sent.tv_sec - now.tv_sec)*1000000 +
-               (itp->last_sent.tv_nsec - now.tv_nsec)/1000 +
-               itp->interval_us;
-
-       if (time_left_us > ITP_TIME_THRES_US) {
-               queue_delayed_work(priv->workqueue, &itp->tx_work,
-                                  ITP_US_TO_MS(time_left_us)*HZ/1000);
-               goto out;
-       }
-
-       if (time_left_us > 50)
-               udelay(time_left_us);
-
-       if (itp->number > 0)
-               itp->number--;
-
-       *data = itp->data;
-       *tx_len = itp->data_len + itp->hdr_len;
-
-       if (itp->data_mode == ITP_DATA_RANDOM)
-               cw1200_itp_fill_pattern(&itp->data[itp->hdr_len],
-                                       itp->data_len, itp->data_mode);
-       *burst = 2;
-       atomic_set(&priv->bh_tx, 1);
-       ktime_get_ts(&itp->last_sent);
-       atomic_add(1, &itp->awaiting_confirm);
-       spin_unlock_bh(&itp->tx_lock);
-       return 1;
-
-out:
-       spin_unlock_bh(&itp->tx_lock);
-       return 0;
-}
-
-bool cw1200_itp_rxed(struct cw1200_common *priv, struct sk_buff *skb)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       struct ieee80211_rx_status *rx = IEEE80211_SKB_RXCB(skb);
-       int signal;
-
-       if (atomic_read(&itp->test_mode) != TEST_MODE_RX_TEST)
-               return cw1200_is_itp(priv);
-       if (rx->freq != priv->channel->center_freq)
-               return true;
-
-       signal = rx->signal;
-       itp->rx_cnt++;
-       itp->rx_rssi += signal;
-       if (itp->rx_rssi_min > rx->signal)
-               itp->rx_rssi_min = rx->signal;
-       if (itp->rx_rssi_max < rx->signal)
-               itp->rx_rssi_max = rx->signal;
-
-       return true;
-}
-
-void cw1200_itp_wake_up_tx(struct cw1200_common *priv)
-{
-       wake_up(&priv->debug->itp.write_wait);
-}
-
-bool cw1200_itp_tx_running(struct cw1200_common *priv)
-{
-       if (atomic_read(&priv->debug->itp.awaiting_confirm) ||
-           atomic_read(&priv->debug->itp.test_mode) ==
-           TEST_MODE_TX_TEST) {
-               atomic_sub(1, &priv->debug->itp.awaiting_confirm);
-               return true;
-       }
-       return false;
-}
-
-static void cw1200_itp_handle(struct cw1200_common *priv,
-                             struct sk_buff *skb)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       const struct wiphy *wiphy = priv->hw->wiphy;
-       int cmd;
-       int ret;
-
-       pr_debug("[ITP] <<< %s", skb->data);
-       if (sscanf(skb->data, "%d", &cmd) != 1) {
-               cw1200_itp_err(priv, -EINVAL, 1);
-               return;
-       }
-
-       switch (cmd) {
-       case 1: /* RX test */
-               if (atomic_read(&itp->test_mode)) {
-                       cw1200_itp_err(priv, -EBUSY, 0);
-                       return;
-               }
-               ret = sscanf(skb->data, "%d,%d,%d",
-                               &cmd, &itp->band, &itp->ch);
-               if (ret != 3) {
-                       cw1200_itp_err(priv, -EINVAL, ret + 1);
-                       return;
-               }
-               if (itp->band >= 2) {
-                       cw1200_itp_err(priv, -EINVAL, 2);
-               } else if (!wiphy->bands[itp->band]) {
-                       cw1200_itp_err(priv, -EINVAL, 2);
-               } else if (itp->ch >= wiphy->bands[itp->band]->n_channels) {
-                       cw1200_itp_err(priv, -EINVAL, 3);
-               } else {
-                       cw1200_itp_rx_stats(priv);
-                       cw1200_itp_rx_start(priv);
-               }
-               break;
-       case 2: /* RX stat */
-               cw1200_itp_rx_stats(priv);
-               break;
-       case 3: /* RX/TX stop */
-               if (atomic_read(&itp->test_mode) == TEST_MODE_RX_TEST) {
-                       cw1200_itp_rx_stats(priv);
-                       cw1200_itp_rx_stop(priv);
-               } else if (atomic_read(&itp->test_mode) == TEST_MODE_TX_TEST) {
-                       cw1200_itp_tx_stop(priv);
-               } else {
-                       cw1200_itp_err(priv, -EBUSY, 0);
-               }
-               break;
-       case 4: /* TX start */
-               if (atomic_read(&itp->test_mode) != TEST_MODE_NO_TEST) {
-                       cw1200_itp_err(priv, -EBUSY, 0);
-                       return;
-               }
-               ret = sscanf(skb->data, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
-                               &cmd, &itp->band, &itp->ch, &itp->rate,
-                               &itp->preamble, &itp->number, &itp->data_mode,
-                               &itp->interval_us, &itp->power, &itp->data_len);
-               if (ret != 10) {
-                       cw1200_itp_err(priv, -EINVAL, ret + 1);
-                       return;
-               }
-               if (itp->band >= 2) {
-                       cw1200_itp_err(priv, -EINVAL, 2);
-               } else if (!wiphy->bands[itp->band]) {
-                       cw1200_itp_err(priv, -EINVAL, 2);
-               } else if (itp->ch >= wiphy->bands[itp->band]->n_channels) {
-                       cw1200_itp_err(priv, -EINVAL, 3);
-               } else if (itp->rate >= 20) {
-                       cw1200_itp_err(priv, -EINVAL, 4);
-               } else if (itp->preamble >= ITP_PREAMBLE_MAX) {
-                       cw1200_itp_err(priv, -EINVAL, 5);
-               } else if (itp->data_mode >= ITP_DATA_MAX_MODE) {
-                       cw1200_itp_err(priv, -EINVAL, 7);
-               } else if (itp->data_len < ITP_MIN_DATA_SIZE ||
-                          itp->data_len > (priv->wsm_caps.input_buffer_size - itp->hdr_len)) {
-                       cw1200_itp_err(priv, -EINVAL, 8);
-               } else {
-                   cw1200_itp_tx_start(priv);
-               }
-               break;
-       case 5:
-               cw1200_itp_get_version(priv, ITP_CHIP_ID);
-               break;
-       case 6:
-               cw1200_itp_get_version(priv, ITP_FW_VER);
-               break;
-       }
-}
-
-static void cw1200_itp_err(struct cw1200_common *priv,
-                          int err, int arg)
-{
-       struct cw1200_itp *itp = &priv->debug->itp;
-       struct sk_buff *skb;
-       static char buf[255];
-       int len;
-
-       len = snprintf(buf, sizeof(buf), "%d,%d\n",
-               err, arg);
-       if (len <= 0)
-               return;
-
-       skb = dev_alloc_skb(len);
-       if (!skb)
-               return;
-
-       skb_trim(skb, 0);
-       skb_put(skb, len);
-
-       memcpy(skb->data, buf, len);
-       skb_queue_tail(&itp->log_queue, skb);
-       wake_up(&itp->read_wait);
-
-       len = sprint_symbol(buf,
-                       (unsigned long)__builtin_return_address(0));
-       if (len <= 0)
-               return;
-       pr_debug("[ITP] error %d,%d from %s\n",
-                err, arg, buf);
-}
diff --git a/drivers/net/wireless/cw1200/itp.h b/drivers/net/wireless/cw1200/itp.h
deleted file mode 100644 (file)
index 1e9dfb7..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * ITP code for ST-Ericsson CW1200 mac80211 driver
- *
- * Copyright (c) 2011, ST-Ericsson
- * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef CW1200_ITP_H_INCLUDED
-#define CW1200_ITP_H_INCLUDED
-
-struct cw200_common;
-struct wsm_tx_confirm;
-struct dentry;
-
-#ifdef CONFIG_CW1200_ITP
-
-/*extern*/ struct ieee80211_channel;
-
-#define TEST_MODE_NO_TEST      (0)
-#define TEST_MODE_RX_TEST      (1)
-#define TEST_MODE_TX_TEST      (2)
-#define ITP_DEFAULT_DA_ADDR {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
-#define ITP_MIN_DATA_SIZE 6
-#define ITP_MAX_DATA_SIZE 1600
-#define ITP_TIME_THRES_US 10000
-#define ITP_US_TO_MS(x) ((x)/1000)
-#define ITP_MS_TO_US(x) ((x)*1000)
-#define ITP_BUF_SIZE 255
-
-
-enum cw1200_itp_data_modes {
-       ITP_DATA_ZEROS,
-       ITP_DATA_ONES,
-       ITP_DATA_ZERONES,
-       ITP_DATA_RANDOM,
-       ITP_DATA_MAX_MODE,
-};
-
-enum cw1200_itp_version_type {
-       ITP_CHIP_ID,
-       ITP_FW_VER,
-};
-
-enum cw1200_itp_preamble_type {
-       ITP_PREAMBLE_LONG,
-       ITP_PREAMBLE_SHORT,
-       ITP_PREAMBLE_OFDM,
-       ITP_PREAMBLE_MIXED,
-       ITP_PREAMBLE_GREENFIELD,
-       ITP_PREAMBLE_MAX,
-};
-
-
-struct cw1200_itp {
-       struct cw1200_common    *priv;
-       atomic_t                open_count;
-       atomic_t                awaiting_confirm;
-       struct sk_buff_head     log_queue;
-       wait_queue_head_t       read_wait;
-       wait_queue_head_t       write_wait;
-       wait_queue_head_t       close_wait;
-       struct ieee80211_channel *saved_channel;
-       atomic_t                stop_tx;
-       struct delayed_work     tx_work;
-       struct delayed_work     tx_finish;
-       spinlock_t              tx_lock;
-       struct timespec         last_sent;
-       atomic_t                test_mode;
-       int                     rx_cnt;
-       long                    rx_rssi;
-       int                     rx_rssi_max;
-       int                     rx_rssi_min;
-       unsigned                band;
-       unsigned                ch;
-       unsigned                rate;
-       unsigned                preamble;
-       unsigned int            number;
-       unsigned                data_mode;
-       int                     interval_us;
-       int                     power;
-       u8                      *data;
-       int                     hdr_len;
-       int                     data_len;
-};
-
-int cw1200_itp_init(struct cw1200_common *priv);
-void cw1200_itp_release(struct cw1200_common *priv);
-
-bool cw1200_is_itp(struct cw1200_common *priv);
-bool cw1200_itp_rxed(struct cw1200_common *priv, struct sk_buff *skb);
-void cw1200_itp_wake_up_tx(struct cw1200_common *priv);
-int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data,
-               size_t *tx_len, int *burst);
-bool cw1200_itp_tx_running(struct cw1200_common *priv);
-
-#else /* CONFIG_CW1200_ITP */
-
-static inline int cw1200_itp_init(struct cw1200_common *priv)
-{
-       return 0;
-}
-
-static inline void cw1200_itp_release(struct cw1200_common *priv)
-{
-}
-
-static inline bool cw1200_is_itp(struct cw1200_common *priv)
-{
-       return false;
-}
-
-static inline bool cw1200_itp_rxed(struct cw1200_common *priv,
-                                  struct sk_buff *skb)
-{
-       return false;
-}
-
-
-static inline void cw1200_itp_consume_txed(struct cw1200_common *priv)
-{
-}
-
-static inline void cw1200_itp_wake_up_tx(struct cw1200_common *priv)
-{
-}
-
-static inline int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data,
-                                   size_t *tx_len, int *burst)
-{
-       return 0;
-}
-
-static inline bool cw1200_itp_tx_running(struct cw1200_common *priv)
-{
-       return false;
-}
-
-#endif /* CONFIG_CW1200_ITP */
-
-#endif /* CW1200_ITP_H_INCLUDED */
index ef4b0b915f8743c85b7b692cf0b2e32705337fd6..da885036ca5f2889f2bef9993a75d319aff5c944 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "cw1200.h"
 #include "txrx.h"
-#include "sbus.h"
+#include "hwbus.h"
 #include "fwio.h"
 #include "hwio.h"
 #include "bh.h"
@@ -61,12 +61,6 @@ int cw1200_power_mode = wsm_power_mode_quiescent;
 module_param(cw1200_power_mode, int, 0644);
 MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode.  0 == active, 1 == doze, 2 == quiescent (default)");
 
-#ifdef CONFIG_CW1200_ETF
-int etf_mode;
-module_param(etf_mode, int, 0644);
-MODULE_PARM_DESC(etf_mode, "Enable EngineeringTestingFramework operation");
-#endif
-
 #define RATETAB_ENT(_rate, _rateid, _flags)            \
        {                                               \
                .bitrate        = (_rate),              \
@@ -251,6 +245,14 @@ module_param(cw1200_ba_tx_tids, int, 0644);
 MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs");
 MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs");
 
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support cw1200_wowlan_support = {
+       /* Support only for limited wowlan functionalities */
+       .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
+};
+#endif
+
+
 static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
                                                const bool have_5ghz)
 {
@@ -295,10 +297,7 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
                                          BIT(NL80211_IFTYPE_P2P_GO);
 
 #ifdef CONFIG_PM
-       /* Support only for limited wowlan functionalities */
-       hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY |
-               WIPHY_WOWLAN_DISCONNECT;
-       hw->wiphy->wowlan.n_patterns = 0;
+       hw->wiphy->wowlan = &cw1200_wowlan_support;
 #endif
 
        hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
@@ -418,11 +417,6 @@ static int cw1200_register_common(struct ieee80211_hw *dev)
        struct cw1200_common *priv = dev->priv;
        int err;
 
-#ifdef CONFIG_CW1200_ETF
-       if (etf_mode)
-               goto done;
-#endif
-
 #ifdef CONFIG_PM
        err = cw1200_pm_init(&priv->pm_state, priv);
        if (err) {
@@ -442,9 +436,6 @@ static int cw1200_register_common(struct ieee80211_hw *dev)
                return err;
        }
 
-#ifdef CONFIG_CW1200_ETF
-done:
-#endif
        cw1200_debug_init(priv);
 
        pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy));
@@ -461,13 +452,7 @@ static void cw1200_unregister_common(struct ieee80211_hw *dev)
        struct cw1200_common *priv = dev->priv;
        int i;
 
-#ifdef CONFIG_CW1200_ETF
-       if (!etf_mode) {
-#endif
-               ieee80211_unregister_hw(dev);
-#ifdef CONFIG_CW1200_ETF
-       }
-#endif
+       ieee80211_unregister_hw(dev);
 
        del_timer_sync(&priv->mcast_timeout);
        cw1200_unregister_bh(priv);
@@ -528,8 +513,8 @@ u32 cw1200_dpll_from_clk(u16 clk_khz)
        }
 }
 
-int cw1200_core_probe(const struct sbus_ops *sbus_ops,
-                     struct sbus_priv *sbus,
+int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
+                     struct hwbus_priv *hwbus,
                      struct device *pdev,
                      struct cw1200_common **core,
                      int ref_clk, const u8 *macaddr,
@@ -556,8 +541,8 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
        if (cw1200_sdd_path)
                priv->sdd_path = cw1200_sdd_path;
 
-       priv->sbus_ops = sbus_ops;
-       priv->sbus_priv = sbus;
+       priv->hwbus_ops = hwbus_ops;
+       priv->hwbus_priv = hwbus;
        priv->pdev = pdev;
        SET_IEEE80211_DEV(priv->hw, pdev);
 
@@ -568,11 +553,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
        if (err)
                goto err1;
 
-#ifdef CONFIG_CW1200_ETF
-       if (etf_mode)
-               goto skip_fw;
-#endif
-
        err = cw1200_load_firmware(priv);
        if (err)
                goto err2;
@@ -594,9 +574,6 @@ int cw1200_core_probe(const struct sbus_ops *sbus_ops,
        /* Enable multi-TX confirmation */
        wsm_use_multi_tx_conf(priv, true);
 
-#ifdef CONFIG_CW1200_ETF
-skip_fw:
-#endif
        err = cw1200_register_common(dev);
        if (err)
                goto err2;
@@ -616,9 +593,9 @@ EXPORT_SYMBOL_GPL(cw1200_core_probe);
 void cw1200_core_release(struct cw1200_common *self)
 {
        /* Disable device interrupts */
-       self->sbus_ops->lock(self->sbus_priv);
+       self->hwbus_ops->lock(self->hwbus_priv);
        __cw1200_irq_enable(self, 0);
-       self->sbus_ops->unlock(self->sbus_priv);
+       self->hwbus_ops->unlock(self->hwbus_priv);
 
        /* And then clean up */
        cw1200_unregister_common(self->hw);
index 79edfb93b2924b9d594a4725648d91d2eb0121a8..b37abb9f0453b1ca530fd3f11e746b8558cc3054 100644 (file)
@@ -15,7 +15,7 @@
 #include "pm.h"
 #include "sta.h"
 #include "bh.h"
-#include "sbus.h"
+#include "hwbus.h"
 
 #define CW1200_BEACON_SKIPPING_MULTIPLIER 3
 
@@ -264,7 +264,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        pm_state->suspend_state = state;
 
        /* Enable IRQ wake */
-       ret = priv->sbus_ops->power_mgmt(priv->sbus_priv, true);
+       ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true);
        if (ret) {
                wiphy_err(priv->hw->wiphy,
                          "PM request failed: %d. WoW is disabled.\n", ret);
@@ -313,7 +313,7 @@ int cw1200_wow_resume(struct ieee80211_hw *hw)
        pm_state->suspend_state = NULL;
 
        /* Disable IRQ wake */
-       priv->sbus_ops->power_mgmt(priv->sbus_priv, false);
+       priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false);
 
        /* Scan.lock must be released before BH is resumed other way
         * in case when BSS_LOST command arrived the processing of the
diff --git a/drivers/net/wireless/cw1200/sbus.h b/drivers/net/wireless/cw1200/sbus.h
deleted file mode 100644 (file)
index 603fd25..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Common sbus abstraction layer interface for cw1200 wireless driver
- *
- * Copyright (c) 2010, ST-Ericsson
- * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef CW1200_SBUS_H
-#define CW1200_SBUS_H
-
-/*
- * sbus priv forward definition.
- * Implemented and instantiated in particular modules.
- */
-struct sbus_priv;
-
-void cw1200_irq_handler(struct cw1200_common *priv);
-
-/* This MUST be wrapped with sbus_ops->lock/unlock! */
-int __cw1200_irq_enable(struct cw1200_common *priv, int enable);
-
-struct sbus_ops {
-       int (*sbus_memcpy_fromio)(struct sbus_priv *self, unsigned int addr,
-                                       void *dst, int count);
-       int (*sbus_memcpy_toio)(struct sbus_priv *self, unsigned int addr,
-                                       const void *src, int count);
-       void (*lock)(struct sbus_priv *self);
-       void (*unlock)(struct sbus_priv *self);
-       size_t (*align_size)(struct sbus_priv *self, size_t size);
-       int (*power_mgmt)(struct sbus_priv *self, bool suspend);
-};
-
-#endif /* CW1200_SBUS_H */
index 679c55f15c67b1e6d9ca61ffa4c6f472fedaf862..4cd0352b508d44c52701cce75eb76534adcb537e 100644 (file)
@@ -483,15 +483,14 @@ void cw1200_update_filtering(struct cw1200_common *priv)
                bf_tbl.num = __cpu_to_le32(3);
        }
 
-       /*
-       * When acting as p2p client being connected to p2p GO, in order to
-       * receive frames from a different p2p device, turn off bssid filter.
-       *
-       * WARNING: FW dependency!
-       * This can only be used with FW WSM371 and its successors.
-       * In that FW version even with bssid filter turned off,
-       * device will block most of the unwanted frames.
-       */
+       /* When acting as p2p client being connected to p2p GO, in order to
+        * receive frames from a different p2p device, turn off bssid filter.
+        *
+        * WARNING: FW dependency!
+        * This can only be used with FW WSM371 and its successors.
+        * In that FW version even with bssid filter turned off,
+        * device will block most of the unwanted frames.
+        */
        if (is_p2p)
                bssid_filtering = false;
 
@@ -1015,17 +1014,17 @@ void cw1200_event_handler(struct work_struct *work)
                        /* RSSI: signed Q8.0, RCPI: unsigned Q7.1
                         * RSSI = RCPI / 2 - 110
                         */
-                       int rcpiRssi = (int)(event->evt.data & 0xFF);
+                       int rcpi_rssi = (int)(event->evt.data & 0xFF);
                        int cqm_evt;
                        if (priv->cqm_use_rssi)
-                               rcpiRssi = (s8)rcpiRssi;
+                               rcpi_rssi = (s8)rcpi_rssi;
                        else
-                               rcpiRssi =  rcpiRssi / 2 - 110;
+                               rcpi_rssi =  rcpi_rssi / 2 - 110;
 
-                       cqm_evt = (rcpiRssi <= priv->cqm_rssi_thold) ?
+                       cqm_evt = (rcpi_rssi <= priv->cqm_rssi_thold) ?
                                NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW :
                                NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
-                       pr_debug("[CQM] RSSI event: %d.\n", rcpiRssi);
+                       pr_debug("[CQM] RSSI event: %d.\n", rcpi_rssi);
                        ieee80211_cqm_rssi_notify(priv->vif, cqm_evt,
                                                  GFP_KERNEL);
                        break;
@@ -1068,8 +1067,7 @@ void cw1200_bss_params_work(struct work_struct *work)
 /* ******************************************************************** */
 /* Internal API                                                                */
 
-/*
- * This function is called to Parse the SDD file
+/* This function is called to Parse the SDD file
  * to extract listen_interval and PTA related information
  * sdd is a TLV: u8 id, u8 len, u8 data[]
  */
index 0e40890e19935ff743c068a53dbebfaa0a78fba3..44ca10cb0d393aa4b83d9a94c69530d10f24697f 100644 (file)
@@ -75,9 +75,6 @@ static void tx_policy_build(const struct cw1200_common *priv,
        BUG_ON(rates[0].idx < 0);
        memset(policy, 0, sizeof(*policy));
 
-       /* minstrel is buggy a little bit, so distille
-        * incoming rates first. */
-
        /* Sort rates in descending order. */
        for (i = 1; i < count; ++i) {
                if (rates[i].idx < 0) {
@@ -108,7 +105,8 @@ static void tx_policy_build(const struct cw1200_common *priv,
        count = i + 1;
 
        /* Re-fill policy trying to keep every requested rate and with
-        * respect to the global max tx retransmission count. */
+        * respect to the global max tx retransmission count.
+        */
        if (limit < count)
                limit = count;
        if (total > limit) {
@@ -129,7 +127,6 @@ static void tx_policy_build(const struct cw1200_common *priv,
        if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) &&
            rates[0].idx > 4 && rates[0].count > 2 &&
            rates[1].idx < 2) {
-               /* ">> 1" is an equivalent of "/ 2", but faster */
                int mid_rate = (rates[0].idx + 4) >> 1;
 
                /* Decrease number of retries for the initial rate */
@@ -151,7 +148,8 @@ static void tx_policy_build(const struct cw1200_common *priv,
                        /* Fallback to 1 Mbps is a really bad thing,
                         * so let's try to increase probability of
                         * successful transmission on the lowest g rate
-                        * even more */
+                        * even more
+                        */
                        if (rates[0].count >= 3) {
                                --rates[0].count;
                                ++rates[2].count;
@@ -190,13 +188,12 @@ static void tx_policy_build(const struct cw1200_common *priv,
                policy->retry_count += retries;
        }
 
-       pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n",
+       pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d\n",
                 count,
                 rates[0].idx, rates[0].count,
                 rates[1].idx, rates[1].count,
                 rates[2].idx, rates[2].count,
-                rates[3].idx, rates[3].count,
-                rates[4].idx, rates[4].count);
+                rates[3].idx, rates[3].count);
 }
 
 static inline bool tx_policy_is_equal(const struct tx_policy *wanted,
@@ -221,7 +218,8 @@ static int tx_policy_find(struct tx_policy_cache *cache,
 {
        /* O(n) complexity. Not so good, but there's only 8 entries in
         * the cache.
-        * Also lru helps to reduce search time. */
+        * Also lru helps to reduce search time.
+        */
        struct tx_policy_cache_entry *it;
        /* First search for policy in "used" list */
        list_for_each_entry(it, &cache->used, link) {
@@ -265,7 +263,8 @@ void tx_policy_clean(struct cw1200_common *priv)
        for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) {
                entry = &cache->cache[idx];
                /* Policy usage count should be 0 at this time as all queues
-                  should be empty */
+                  should be empty
+                */
                if (WARN_ON(entry->policy.usage_count)) {
                        entry->policy.usage_count = 0;
                        list_move(&entry->link, &cache->free);
@@ -320,7 +319,8 @@ static int tx_policy_get(struct cw1200_common *priv,
                struct tx_policy_cache_entry *entry;
                *renew = true;
                /* If policy is not found create a new one
-                * using the oldest entry in "free" list */
+                * using the oldest entry in "free" list
+                */
                entry = list_entry(cache->free.prev,
                        struct tx_policy_cache_entry, link);
                entry->policy = wanted;
@@ -613,7 +613,8 @@ cw1200_tx_h_bt(struct cw1200_common *priv,
                                 priv->listen_interval,
                                 mgt_frame->u.assoc_req.listen_interval);
                        /* Replace listen interval derieved from
-                        * the one read from SDD */
+                        * the one read from SDD
+                        */
                        mgt_frame->u.assoc_req.listen_interval =
                                priv->listen_interval;
                }
@@ -668,7 +669,8 @@ cw1200_tx_h_rate_policy(struct cw1200_common *priv,
                pr_debug("[TX] TX policy renew.\n");
                /* It's not so optimal to stop TX queues every now and then.
                 * Better to reimplement task scheduling with
-                * a counter. TODO. */
+                * a counter. TODO.
+                */
                wsm_lock_tx_async(priv);
                cw1200_tx_queues_lock(priv);
                if (queue_work(priv->workqueue,
@@ -833,8 +835,7 @@ static int cw1200_handle_pspoll(struct cw1200_common *priv,
        priv->pspoll_mask |= pspoll_mask;
        drop = 0;
 
-       /* Do not report pspols if data for given link id is
-        * queued already. */
+       /* Do not report pspols if data for given link id is queued already. */
        for (i = 0; i < 4; ++i) {
                if (cw1200_queue_get_num_queued(&priv->tx_queue[i],
                                                pspoll_mask)) {
@@ -862,9 +863,6 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
        pr_debug("[TX] TX confirm: %d, %d.\n",
                 arg->status, arg->ack_failures);
 
-       if (cw1200_itp_tx_running(priv))
-               return;
-
        if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) {
                /* STA is stopped. */
                return;
@@ -928,7 +926,8 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
                        cw1200_debug_txed(priv);
                        if (arg->flags & WSM_TX_STATUS_AGGREGATION) {
                                /* Do not report aggregation to mac80211:
-                                * it confuses minstrel a lot. */
+                                * it confuses minstrel a lot.
+                                */
                                /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */
                                cw1200_debug_txed_agg(priv);
                        }
@@ -1002,8 +1001,7 @@ void cw1200_skb_dtor(struct cw1200_common *priv,
                                          txpriv->raw_link_id, txpriv->tid);
                tx_policy_put(priv, txpriv->rate_id);
        }
-       if (!cw1200_is_itp(priv))
-               ieee80211_tx_status(priv->hw, skb);
+       ieee80211_tx_status(priv->hw, skb);
 }
 
 void cw1200_rx_cb(struct cw1200_common *priv,
@@ -1049,7 +1047,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
            ieee80211_is_action(frame->frame_control) &&
            (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) {
                /* Link ID already exists for the ACTION frame.
-                * Reset and Remap */
+                * Reset and Remap
+                */
                WARN_ON(work_pending(&priv->linkid_reset_work));
                memcpy(&priv->action_frame_sa[0],
                       ieee80211_get_SA(frame), ETH_ALEN);
@@ -1079,7 +1078,6 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                if (cw1200_handle_pspoll(priv, skb))
                        goto drop;
 
-       hdr->mactime = 0; /* Not supported by WSM */
        hdr->band = ((arg->channel_number & 0xff00) ||
                     (arg->channel_number > 14)) ?
                        IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
@@ -1107,7 +1105,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED;
 
                /* Oops... There is no fast way to ask mac80211 about
-                * IV/ICV lengths. Even defineas are not exposed.*/
+                * IV/ICV lengths. Even defineas are not exposed.
+                */
                switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) {
                case WSM_RX_STATUS_WEP:
                        iv_len = 4 /* WEP_IV_LEN */;
@@ -1154,6 +1153,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                hdr->mactime = le64_to_cpu(hdr->mactime);
                if (skb->len >= 8)
                        skb_trim(skb, skb->len - 8);
+       } else {
+               hdr->mactime = 0;
        }
 
        cw1200_debug_rxed(priv);
@@ -1197,7 +1198,8 @@ void cw1200_rx_cb(struct cw1200_common *priv,
 
        /* Stay awake after frame is received to give
         * userspace chance to react and acquire appropriate
-        * wakelock. */
+        * wakelock.
+        */
        if (ieee80211_is_auth(frame->frame_control))
                grace_period = 5 * HZ;
        else if (ieee80211_is_deauth(frame->frame_control))
@@ -1206,9 +1208,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                grace_period = 1 * HZ;
        cw1200_pm_stay_awake(&priv->pm_state, grace_period);
 
-       if (cw1200_itp_rxed(priv, skb)) {
-               consume_skb(skb);
-       } else if (early_data) {
+       if (early_data) {
                spin_lock_bh(&priv->ps_state_lock);
                /* Double-check status with lock held */
                if (entry->status == CW1200_LINK_SOFT)
index f3fd9b218724c7aafc758dda89709bf661976117..d95094fdcc50599a9faeff0911289a55012168b4 100644 (file)
@@ -21,7 +21,6 @@
 #include "bh.h"
 #include "sta.h"
 #include "debug.h"
-#include "itp.h"
 
 #define WSM_CMD_TIMEOUT                (2 * HZ) /* With respect to interrupt loss */
 #define WSM_CMD_START_TIMEOUT  (7 * HZ)
@@ -929,6 +928,8 @@ static int wsm_event_indication(struct cw1200_common *priv, struct wsm_buf *buf)
        }
 
        event = kzalloc(sizeof(struct cw1200_wsm_event), GFP_KERNEL);
+       if (!event)
+               return -ENOMEM;
 
        event->evt.id = __le32_to_cpu(WSM_GET32(buf));
        event->evt.data = __le32_to_cpu(WSM_GET32(buf));
@@ -1105,15 +1106,11 @@ static int wsm_cmd_send(struct cw1200_common *priv,
        else
                pr_debug("[WSM] >>> 0x%.4X (%zu)\n", cmd, buf_len);
 
-       /*
-        * Due to buggy SPI on CW1200, we need to
+       /* Due to buggy SPI on CW1200, we need to
         * pad the message by a few bytes to ensure
         * that it's completely received.
         */
-#ifdef CONFIG_CW1200_ETF
-       if (!etf_mode)
-#endif
-               buf_len += 4;
+       buf_len += 4;
 
        /* Fill HI message header */
        /* BH will add sequence number */
@@ -1164,29 +1161,6 @@ done:
        return ret;
 }
 
-#ifdef CONFIG_CW1200_ETF
-int wsm_raw_cmd(struct cw1200_common *priv, u8 *data, size_t len)
-{
-       struct wsm_buf *buf = &priv->wsm_cmd_buf;
-       int ret;
-
-       u16 *cmd = (u16 *)(data + 2);
-
-       wsm_cmd_lock(priv);
-
-       WSM_PUT(buf, data + 4, len - 4);  /* Skip over header (u16+u16) */
-
-       ret = wsm_cmd_send(priv, buf, NULL, __le16_to_cpu(*cmd), WSM_CMD_TIMEOUT);
-
-       wsm_cmd_unlock(priv);
-       return ret;
-
-nomem:
-       wsm_cmd_unlock(priv);
-       return -ENOMEM;
-}
-#endif /* CONFIG_CW1200_ETF */
-
 /* ******************************************************************** */
 /* WSM TX port control                                                 */
 
@@ -1342,34 +1316,6 @@ int wsm_handle_rx(struct cw1200_common *priv, u16 id,
        pr_debug("[WSM] <<< 0x%.4X (%td)\n", id,
                 wsm_buf.end - wsm_buf.begin);
 
-#ifdef CONFIG_CW1200_ETF
-       if (etf_mode) {
-               struct sk_buff *skb = alloc_skb(wsm_buf.end - wsm_buf.begin, GFP_KERNEL);
-
-               /* Strip out Sequence num before passing up */
-               wsm->id = __le16_to_cpu(wsm->id);
-               wsm->id &= 0x0FFF;
-               wsm->id = __cpu_to_le16(wsm->id);
-
-               memcpy(skb_put(skb, wsm_buf.end - wsm_buf.begin),
-                      wsm_buf.begin,
-                      wsm_buf.end - wsm_buf.begin);
-               skb_queue_tail(&priv->etf_q, skb);
-
-               /* Special case for startup */
-               if (id == WSM_STARTUP_IND_ID) {
-                       wsm_startup_indication(priv, &wsm_buf);
-               } else if (id & 0x0400) {
-                       spin_lock(&priv->wsm_cmd.lock);
-                       priv->wsm_cmd.done = 1;
-                       spin_unlock(&priv->wsm_cmd.lock);
-                       wake_up(&priv->wsm_cmd_wq);
-               }
-
-               goto out;
-       }
-#endif
-
        if (id == WSM_TX_CONFIRM_IND_ID) {
                ret = wsm_tx_confirm(priv, &wsm_buf, link_id);
        } else if (id == WSM_MULTI_TX_CONFIRM_ID) {
@@ -1731,12 +1677,6 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data,
        /* More is used only for broadcasts. */
        bool more = false;
 
-#ifdef CONFIG_CW1200_ITP
-       count = cw1200_itp_get_tx(priv, data, tx_len, burst);
-       if (count)
-               return count;
-#endif
-
        if (priv->wsm_cmd.ptr) { /* CMD request */
                ++count;
                spin_lock(&priv->wsm_cmd.lock);
index 8d902d6a7dc4f965b8baaf8291b0aa90414d24e7..2816171f7a1dafae322555608ea7e05d1406daa0 100644 (file)
@@ -314,13 +314,16 @@ struct cw1200_common;
 #define WSM_JOIN_FLAGS_P2P_GO          BIT(1)
 /* Force to join BSS with the BSSID and the
  * SSID specified without waiting for beacons. The
- * ProbeForJoin parameter is ignored. */
+ * ProbeForJoin parameter is ignored.
+ */
 #define WSM_JOIN_FLAGS_FORCE           BIT(2)
 /* Give probe request/response higher
- * priority over the BT traffic */
+ * priority over the BT traffic
+ */
 #define WSM_JOIN_FLAGS_PRIO            BIT(3)
 /* Issue immediate join confirmation and use
- * join complete to notify about completion */
+ * join complete to notify about completion
+ */
 #define WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND BIT(5)
 
 /* Key types */
@@ -1015,22 +1018,19 @@ struct wsm_add_key {
        u16 reserved;
        union {
                struct {
-                       u8 peer[6];     /* MAC address of the
-                                                * peer station */
+                       u8 peer[6];     /* MAC address of the peer station */
                        u8 reserved;
                        u8 keylen;              /* Key length in bytes */
                        u8 keydata[16];         /* Key data */
                } __packed wep_pairwise;
                struct {
-                       u8 keyid;               /* Unique per key identifier
-                                                * (0..3) */
+                       u8 keyid;       /* Unique per key identifier (0..3) */
                        u8 keylen;              /* Key length in bytes */
                        u16 reserved;
                        u8 keydata[16];         /* Key data */
                } __packed wep_group;
                struct {
-                       u8 peer[6];     /* MAC address of the
-                                                * peer station */
+                       u8 peer[6];     /* MAC address of the peer station */
                        u16 reserved;
                        u8 keydata[16]; /* TKIP key data */
                        u8 rx_mic_key[8];               /* Rx MIC key */
@@ -1044,8 +1044,7 @@ struct wsm_add_key {
                        u8 rx_seqnum[8];        /* Receive Sequence Counter */
                } __packed tkip_group;
                struct {
-                       u8 peer[6];     /* MAC address of the
-                                                * peer station */
+                       u8 peer[6];     /* MAC address of the peer station */
                        u16 reserved;
                        u8 keydata[16]; /* AES key data */
                } __packed aes_pairwise;
@@ -1056,8 +1055,7 @@ struct wsm_add_key {
                        u8 rx_seqnum[8];        /* Receive Sequence Counter */
                } __packed aes_group;
                struct {
-                       u8 peer[6];     /* MAC address of the
-                                                * peer station */
+                       u8 peer[6];     /* MAC address of the peer station */
                        u8 keyid;               /* Key ID */
                        u8 reserved;
                        u8 keydata[16]; /* WAPI key data */
@@ -1550,7 +1548,8 @@ struct wsm_tx_rate_retry_policy {
         *          finishes.
         * BIT(3) - Count initial frame transmission as part of
         *          rate retry counting but not as a retry
-        *          attempt */
+        *          attempt
+        */
        u8 flags;
        u8 rate_recoveries;
        u8 reserved[3];
@@ -1618,24 +1617,24 @@ static inline int wsm_set_udp_port_filter(struct cw1200_common *priv,
 #define D11_MAX_SSID_LEN               (32)
 
 struct wsm_p2p_device_type {
-       __le16 categoryId;
+       __le16 category_id;
        u8 oui[4];
-       __le16 subCategoryId;
+       __le16 subcategory_id;
 } __packed;
 
 struct wsm_p2p_device_info {
        struct wsm_p2p_device_type primaryDevice;
        u8 reserved1[3];
-       u8 devNameSize;
-       u8 localDevName[D11_MAX_SSID_LEN];
+       u8 devname_size;
+       u8 local_devname[D11_MAX_SSID_LEN];
        u8 reserved2[3];
-       u8 numSecDevSupported;
-       struct wsm_p2p_device_type secondaryDevices[0];
+       u8 num_secdev_supported;
+       struct wsm_p2p_device_type secdevs[0];
 } __packed;
 
 /* 4.36 SetWCDMABand - WO */
 struct wsm_cdma_band {
-       u8 WCDMA_Band;
+       u8 wcdma_band;
        u8 reserved[3];
 } __packed;
 
@@ -1668,19 +1667,19 @@ struct wsm_ht_protection {
 #define WSM_GPIO_ALL_PINS      0xFF
 
 struct wsm_gpio_command {
-       u8 GPIO_Command;
+       u8 command;
        u8 pin;
        __le16 config;
 } __packed;
 
 /* 4.41 TSFCounter - RO */
 struct wsm_tsf_counter {
-       __le64 TSF_Counter;
+       __le64 tsf_counter;
 } __packed;
 
 /* 4.43 Keep alive period */
 struct wsm_keep_alive_period {
-       __le16 keepAlivePeriod;
+       __le16 period;
        u8 reserved[2];
 } __packed;
 
@@ -1688,7 +1687,7 @@ static inline int wsm_keep_alive_period(struct cw1200_common *priv,
                                        int period)
 {
        struct wsm_keep_alive_period arg = {
-               .keepAlivePeriod = __cpu_to_le16(period),
+               .period = __cpu_to_le16(period),
        };
        return wsm_write_mib(priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD,
                        &arg, sizeof(arg));
@@ -1739,13 +1738,13 @@ static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv,
 
 /* P2P Power Save Mode Info - 4.31 */
 struct wsm_p2p_ps_modeinfo {
-       u8      oppPsCTWindow;
+       u8      opp_ps_ct_window;
        u8      count;
        u8      reserved;
-       u8      dtimCount;
+       u8      dtim_count;
        __le32  duration;
        __le32  interval;
-       __le32  startTime;
+       __le32  start_time;
 } __packed;
 
 static inline int wsm_set_p2p_ps_modeinfo(struct cw1200_common *priv,
@@ -1871,9 +1870,4 @@ static inline u8 wsm_queue_id_to_wsm(u8 queue_id)
        return queue_mapping[queue_id];
 }
 
-
-#ifdef CONFIG_CW1200_ETF
-int wsm_raw_cmd(struct cw1200_common *priv, u8 *data, size_t len);
-#endif
-
 #endif /* CW1200_HWIO_H_INCLUDED */
index 15920aaa5dd6c766184335360937139295769dbe..f8ab193009cd9f3044a3d8846d4da4e7cbaec3e5 100644 (file)
@@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
        if ((val & 0x0000ff00) != 0)
                pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
 
-       pci_set_power_state(pci_dev, PCI_D0);
-
        if (!ipw2100_hw_is_adapter_in_system(dev)) {
                printk(KERN_WARNING DRV_NAME
                       "Device not found via register read.\n");
index b37a582ccbe7872eca2e5f5f8da14abe32f335e1..866ce6c684055e3e6a06f79681c75f73f9ccae27 100644 (file)
@@ -3727,7 +3727,8 @@ il3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * 5. Setup HW Constants
         * ********************/
        /* Device-specific setup */
-       if (il3945_hw_set_hw_params(il)) {
+       err = il3945_hw_set_hw_params(il);
+       if (err) {
                IL_ERR("failed to set hw settings\n");
                goto out_eeprom_free;
        }
index dc1e6da9976af0977ae197475694a8f544ae1643..c092033945cc460022e1c8ea28e2622a9db0a79f 100644 (file)
@@ -331,6 +331,19 @@ il3945_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
                return;
        }
 
+       /*
+        * Firmware will not transmit frame on passive channel, if it not yet
+        * received some valid frame on that channel. When this error happen
+        * we have to wait until firmware will unblock itself i.e. when we
+        * note received beacon or other frame. We unblock queues in
+        * il3945_pass_packet_to_mac80211 or in il_mac_bss_info_changed.
+        */
+       if (unlikely((status & TX_STATUS_MSK) == TX_STATUS_FAIL_PASSIVE_NO_RX) &&
+           il->iw_mode == NL80211_IFTYPE_STATION) {
+               il_stop_queues_by_reason(il, IL_STOP_REASON_PASSIVE);
+               D_INFO("Stopped queues - RX waiting on passive channel\n");
+       }
+
        txq->time_stamp = jiffies;
        info = IEEE80211_SKB_CB(txq->skbs[txq->q.read_ptr]);
        ieee80211_tx_info_clear_status(info);
@@ -488,6 +501,11 @@ il3945_pass_packet_to_mac80211(struct il_priv *il, struct il_rx_buf *rxb,
                return;
        }
 
+       if (unlikely(test_bit(IL_STOP_REASON_PASSIVE, &il->stop_reason))) {
+               il_wake_queues_by_reason(il, IL_STOP_REASON_PASSIVE);
+               D_INFO("Woke queues - frame received on passive channel\n");
+       }
+
        skb = dev_alloc_skb(128);
        if (!skb) {
                IL_ERR("dev_alloc_skb failed\n");
index 9a95045c97b6b4fe6041f457a1999ecfb7926d12..d287fd2dce4250f636040a2e933e9c6ca5c9b394 100644 (file)
@@ -588,6 +588,11 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr,
                return;
        }
 
+       if (unlikely(test_bit(IL_STOP_REASON_PASSIVE, &il->stop_reason))) {
+               il_wake_queues_by_reason(il, IL_STOP_REASON_PASSIVE);
+               D_INFO("Woke queues - frame received on passive channel\n");
+       }
+
        /* In case of HW accelerated crypto and bad decryption, drop */
        if (!il->cfg->mod_params->sw_crypto &&
            il_set_decrypted_flag(il, hdr, ampdu_status, stats))
@@ -2806,6 +2811,19 @@ il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb)
                return;
        }
 
+       /*
+        * Firmware will not transmit frame on passive channel, if it not yet
+        * received some valid frame on that channel. When this error happen
+        * we have to wait until firmware will unblock itself i.e. when we
+        * note received beacon or other frame. We unblock queues in
+        * il4965_pass_packet_to_mac80211 or in il_mac_bss_info_changed.
+        */
+       if (unlikely((status & TX_STATUS_MSK) == TX_STATUS_FAIL_PASSIVE_NO_RX) &&
+           il->iw_mode == NL80211_IFTYPE_STATION) {
+               il_stop_queues_by_reason(il, IL_STOP_REASON_PASSIVE);
+               D_INFO("Stopped queues - RX waiting on passive channel\n");
+       }
+
        spin_lock_irqsave(&il->sta_lock, flags);
        if (txq->sched_retry) {
                const u32 scd_ssn = il4965_get_scd_ssn(tx_resp);
@@ -5741,7 +5759,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length)
        hw->flags =
            IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
            IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
-           IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+           IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
+           IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
        if (il->cfg->sku & IL_SKU_N)
                hw->flags |=
                    IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
index 592d0aa634a8f7693bafc85235ecbd9ae123d039..3195aad440ddf6317b1b9b34d2e2f57e773755c3 100644 (file)
@@ -1423,7 +1423,7 @@ il_setup_rx_scan_handlers(struct il_priv *il)
 }
 EXPORT_SYMBOL(il_setup_rx_scan_handlers);
 
-inline u16
+u16
 il_get_active_dwell_time(struct il_priv *il, enum ieee80211_band band,
                         u8 n_probes)
 {
@@ -5306,6 +5306,17 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        if (changes & BSS_CHANGED_BSSID) {
                D_MAC80211("BSSID %pM\n", bss_conf->bssid);
 
+               /*
+                * On passive channel we wait with blocked queues to see if
+                * there is traffic on that channel. If no frame will be
+                * received (what is very unlikely since scan detects AP on
+                * that channel, but theoretically possible), mac80211 associate
+                * procedure will time out and mac80211 will call us with NULL
+                * bssid. We have to unblock queues on such condition.
+                */
+               if (is_zero_ether_addr(bss_conf->bssid))
+                       il_wake_queues_by_reason(il, IL_STOP_REASON_PASSIVE);
+
                /*
                 * If there is currently a HW scan going on in the background,
                 * then we need to cancel it, otherwise sometimes we are not
index f8246f2d88f9baf0cbb006621fbfbc3845966e26..83f8ed8a5528cbd209c97560e9ab9c59d2294a90 100644 (file)
@@ -1299,6 +1299,8 @@ struct il_priv {
        /* queue refcounts */
 #define IL_MAX_HW_QUEUES       32
        unsigned long queue_stopped[BITS_TO_LONGS(IL_MAX_HW_QUEUES)];
+#define IL_STOP_REASON_PASSIVE 0
+       unsigned long stop_reason;
        /* for each AC */
        atomic_t queue_stop_count[4];
 
@@ -1832,16 +1834,16 @@ u32 il_usecs_to_beacons(struct il_priv *il, u32 usec, u32 beacon_interval);
 __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
                          u32 beacon_interval);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern const struct dev_pm_ops il_pm_ops;
 
 #define IL_LEGACY_PM_OPS       (&il_pm_ops)
 
-#else /* !CONFIG_PM */
+#else /* !CONFIG_PM_SLEEP */
 
 #define IL_LEGACY_PM_OPS       NULL
 
-#endif /* !CONFIG_PM */
+#endif /* !CONFIG_PM_SLEEP */
 
 /*****************************************************
 *  Error Handling Debugging
@@ -2256,6 +2258,19 @@ il_set_swq_id(struct il_tx_queue *txq, u8 ac, u8 hwq)
        txq->swq_id = (hwq << 2) | ac;
 }
 
+static inline void
+_il_wake_queue(struct il_priv *il, u8 ac)
+{
+       if (atomic_dec_return(&il->queue_stop_count[ac]) <= 0)
+               ieee80211_wake_queue(il->hw, ac);
+}
+
+static inline void
+_il_stop_queue(struct il_priv *il, u8 ac)
+{
+       if (atomic_inc_return(&il->queue_stop_count[ac]) > 0)
+               ieee80211_stop_queue(il->hw, ac);
+}
 static inline void
 il_wake_queue(struct il_priv *il, struct il_tx_queue *txq)
 {
@@ -2264,8 +2279,7 @@ il_wake_queue(struct il_priv *il, struct il_tx_queue *txq)
        u8 hwq = (queue >> 2) & 0x1f;
 
        if (test_and_clear_bit(hwq, il->queue_stopped))
-               if (atomic_dec_return(&il->queue_stop_count[ac]) <= 0)
-                       ieee80211_wake_queue(il->hw, ac);
+               _il_wake_queue(il, ac);
 }
 
 static inline void
@@ -2276,8 +2290,27 @@ il_stop_queue(struct il_priv *il, struct il_tx_queue *txq)
        u8 hwq = (queue >> 2) & 0x1f;
 
        if (!test_and_set_bit(hwq, il->queue_stopped))
-               if (atomic_inc_return(&il->queue_stop_count[ac]) > 0)
-                       ieee80211_stop_queue(il->hw, ac);
+               _il_stop_queue(il, ac);
+}
+
+static inline void
+il_wake_queues_by_reason(struct il_priv *il, int reason)
+{
+       u8 ac;
+
+       if (test_and_clear_bit(reason, &il->stop_reason))
+               for (ac = 0; ac < 4; ac++)
+                       _il_wake_queue(il, ac);
+}
+
+static inline void
+il_stop_queues_by_reason(struct il_priv *il, int reason)
+{
+       u8 ac;
+
+       if (!test_and_set_bit(reason, &il->stop_reason))
+               for (ac = 0; ac < 4; ac++)
+                       _il_stop_queue(il, ac);
 }
 
 #ifdef ieee80211_stop_queue
index f1b8df16dbba44105e546ff1e7cefd1d14855ba2..5cd87f94926640086e5ffbebf0f05226b93062ce 100644 (file)
@@ -915,6 +915,9 @@ struct iwl_priv {
        __le64 replay_ctr;
        __le16 last_seq_ctl;
        bool have_rekey_data;
+#ifdef CONFIG_PM_SLEEP
+       struct wiphy_wowlan_support wowlan_support;
+#endif
 
        /* device_pointers: pointers to ucode event tables */
        struct {
index ac7ed3f809a0b7a7603329cd2f2f874098356719..eef64bb854f723ebaf744597d0e90461ef0e5ddc 100644 (file)
@@ -208,20 +208,21 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
            priv->trans->ops->d3_suspend &&
            priv->trans->ops->d3_resume &&
            device_can_wakeup(priv->trans->dev)) {
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT |
-                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                         WIPHY_WOWLAN_RFKILL_RELEASE;
+               priv->wowlan_support.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                                            WIPHY_WOWLAN_DISCONNECT |
+                                            WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                            WIPHY_WOWLAN_RFKILL_RELEASE;
                if (!iwlwifi_mod_params.sw_crypto)
-                       hw->wiphy->wowlan.flags |=
+                       priv->wowlan_support.flags |=
                                WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
                                WIPHY_WOWLAN_GTK_REKEY_FAILURE;
 
-               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
-               hw->wiphy->wowlan.pattern_min_len =
+               priv->wowlan_support.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
+               priv->wowlan_support.pattern_min_len =
                                        IWLAGN_WOWLAN_MIN_PATTERN_LEN;
-               hw->wiphy->wowlan.pattern_max_len =
+               priv->wowlan_support.pattern_max_len =
                                        IWLAGN_WOWLAN_MAX_PATTERN_LEN;
+               hw->wiphy->wowlan = &priv->wowlan_support;
        }
 #endif
 
@@ -430,7 +431,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
        iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
                    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
-       iwl_trans_d3_suspend(priv->trans);
+       iwl_trans_d3_suspend(priv->trans, false);
 
        goto out;
 
@@ -504,7 +505,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        /* we'll clear ctx->vif during iwlagn_prepare_restart() */
        vif = ctx->vif;
 
-       ret = iwl_trans_d3_resume(priv->trans, &d3_status);
+       ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
        if (ret)
                goto out_unlock;
 
index 7d145091630880ceafe9b4626f37df95e976e4e2..429337a2b9a15189c0c0fefc94389a884e3b43f3 100644 (file)
@@ -62,8 +62,7 @@
 
 #ifndef __iwl_drv_h__
 #define __iwl_drv_h__
-
-#include <linux/module.h>
+#include <linux/export.h>
 
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
index 25745daa0d5da4142abef88f506b8bee614d8905..84acb4deca8a0fb2509456280cbb5b8250bedd09 100644 (file)
@@ -413,6 +413,9 @@ static int iwl_phy_db_send_all_channel_groups(
                if (!entry)
                        return -EINVAL;
 
+               if (WARN_ON_ONCE(!entry->size))
+                       continue;
+
                /* Send the requested PHY DB section */
                err = iwl_send_phy_db_cmd(phy_db,
                                          type,
index 84f1c8dc97413fa3fe5c2cb48f33bfcc9c031505..be4b2ac3dbbf008dbe872d11359bbc5bcc55d2a5 100644 (file)
@@ -428,8 +428,9 @@ struct iwl_trans_ops {
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
        void (*stop_device)(struct iwl_trans *trans);
 
-       void (*d3_suspend)(struct iwl_trans *trans);
-       int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status);
+       void (*d3_suspend)(struct iwl_trans *trans, bool test);
+       int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
+                        bool test);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -588,17 +589,18 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
        trans->state = IWL_TRANS_NO_FW;
 }
 
-static inline void iwl_trans_d3_suspend(struct iwl_trans *trans)
+static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
 {
        might_sleep();
-       trans->ops->d3_suspend(trans);
+       trans->ops->d3_suspend(trans, test);
 }
 
 static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
-                                     enum iwl_d3_status *status)
+                                     enum iwl_d3_status *status,
+                                     bool test)
 {
        might_sleep();
-       return trans->ops->d3_resume(trans, status);
+       return trans->ops->d3_resume(trans, status, test);
 }
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
index f03655f303aab4e87fe3bd8d4658939c23ee7838..9a4d94a1f90d66deb8003e455c4499a86ccfc50d 100644 (file)
@@ -174,7 +174,7 @@ static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
 static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
        cpu_to_le32(0xaaaaaaaa),
        cpu_to_le32(0xaaaaaaaa),
-       cpu_to_le32(0xaeaaaaaa),
+       cpu_to_le32(0xaaaaaaaa),
        cpu_to_le32(0xaaaaaaaa),
        cpu_to_le32(0xcc00ff28),
        cpu_to_le32(0x0000aaaa),
index 4d3c978b5c76a08c2f8ee0f18c1015ff81f8fe5a..7a2ef3f013fdcf06a51e204bb356894016ba89cc 100644 (file)
@@ -63,6 +63,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/ip.h>
+#include <linux/fs.h>
 #include <net/cfg80211.h>
 #include <net/ipv6.h>
 #include <net/tcp.h>
@@ -756,7 +757,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        return 0;
 }
 
-int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
+                            struct cfg80211_wowlan *wowlan,
+                            bool test)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        struct iwl_d3_iter_data suspend_iter_data = {
@@ -769,7 +772,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
        struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
        struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct iwl_d3_manager_config d3_cfg_cmd = {
+       struct iwl_d3_manager_config d3_cfg_cmd_data = {
                /*
                 * Program the minimum sleep time to 10 seconds, as many
                 * platforms have issues processing a wakeup signal while
@@ -777,17 +780,30 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                 */
                .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
        };
+       struct iwl_host_cmd d3_cfg_cmd = {
+               .id = D3_CONFIG_CMD,
+               .flags = CMD_SYNC | CMD_WANT_SKB,
+               .data[0] = &d3_cfg_cmd_data,
+               .len[0] = sizeof(d3_cfg_cmd_data),
+       };
        struct wowlan_key_data key_data = {
                .use_rsc_tsc = false,
                .tkip = &tkip_cmd,
                .use_tkip = false,
        };
        int ret, i;
+       int len __maybe_unused;
        u16 seq;
        u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
 
-       if (WARN_ON(!wowlan))
+       if (!wowlan) {
+               /*
+                * mac80211 shouldn't get here, but for D3 test
+                * it doesn't warrant a warning
+                */
+               WARN_ON(!test);
                return -EINVAL;
+       }
 
        key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
        if (!key_data.rsc_tsc)
@@ -1012,14 +1028,26 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                goto out;
 
        /* must be last -- this switches firmware state */
-       ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
-                                  sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+       ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd);
        if (ret)
                goto out;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) &
+               FH_RSCSR_FRAME_SIZE_MSK;
+       if (len >= sizeof(u32) * 2) {
+               mvm->d3_test_pme_ptr =
+                       le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data);
+       } else if (test) {
+               /* in test mode we require the pointer */
+               ret = -EIO;
+               goto out;
+       }
+#endif
+       iwl_free_resp(&d3_cfg_cmd);
 
        clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
 
-       iwl_trans_d3_suspend(mvm->trans);
+       iwl_trans_d3_suspend(mvm->trans, test);
  out:
        mvm->aux_sta.sta_id = old_aux_sta_id;
        mvm_ap_sta->sta_id = old_ap_sta_id;
@@ -1034,6 +1062,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        return ret;
 }
 
+int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+{
+       return __iwl_mvm_suspend(hw, wowlan, false);
+}
+
 static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
                                         struct ieee80211_vif *vif)
 {
@@ -1238,9 +1271,8 @@ static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm)
 #endif
 }
 
-int iwl_mvm_resume(struct ieee80211_hw *hw)
+static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 {
-       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        struct iwl_d3_iter_data resume_iter_data = {
                .mvm = mvm,
        };
@@ -1260,7 +1292,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
 
        vif = resume_iter_data.vif;
 
-       ret = iwl_trans_d3_resume(mvm->trans, &d3_status);
+       ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
        if (ret)
                goto out_unlock;
 
@@ -1277,7 +1309,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
  out_unlock:
        mutex_unlock(&mvm->mutex);
 
-       if (vif)
+       if (!test && vif)
                ieee80211_resume_disconnect(vif);
 
        /* return 1 to reconfigure the device */
@@ -1285,9 +1317,106 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
        return 1;
 }
 
+int iwl_mvm_resume(struct ieee80211_hw *hw)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+       return __iwl_mvm_resume(mvm, false);
+}
+
 void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 
        device_set_wakeup_enable(mvm->trans->dev, enabled);
 }
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
+{
+       struct iwl_mvm *mvm = inode->i_private;
+       int err;
+
+       if (mvm->d3_test_active)
+               return -EBUSY;
+
+       file->private_data = inode->i_private;
+
+       ieee80211_stop_queues(mvm->hw);
+       synchronize_net();
+
+       /* start pseudo D3 */
+       rtnl_lock();
+       err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
+       rtnl_unlock();
+       if (err > 0)
+               err = -EINVAL;
+       if (err) {
+               ieee80211_wake_queues(mvm->hw);
+               return err;
+       }
+       mvm->d3_test_active = true;
+       return 0;
+}
+
+static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       u32 pme_asserted;
+
+       while (true) {
+               pme_asserted = iwl_trans_read_mem32(mvm->trans,
+                                                   mvm->d3_test_pme_ptr);
+               if (pme_asserted)
+                       break;
+               if (msleep_interruptible(100))
+                       break;
+       }
+
+       return 0;
+}
+
+static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
+                                             struct ieee80211_vif *vif)
+{
+       if (vif->type == NL80211_IFTYPE_STATION)
+               ieee80211_connection_loss(vif);
+}
+
+static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
+{
+       struct iwl_mvm *mvm = inode->i_private;
+       int remaining_time = 10;
+
+       mvm->d3_test_active = false;
+       __iwl_mvm_resume(mvm, true);
+       iwl_abort_notification_waits(&mvm->notif_wait);
+       ieee80211_restart_hw(mvm->hw);
+
+       /* wait for restart and disconnect all interfaces */
+       while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+              remaining_time > 0) {
+               remaining_time--;
+               msleep(1000);
+       }
+
+       if (remaining_time == 0)
+               IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n");
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_d3_test_disconn_work_iter, NULL);
+
+       ieee80211_wake_queues(mvm->hw);
+
+       return 0;
+}
+
+const struct file_operations iwl_dbgfs_d3_test_ops = {
+       .llseek = no_llseek,
+       .open = iwl_mvm_d3_test_open,
+       .read = iwl_mvm_d3_test_read,
+       .release = iwl_mvm_d3_test_release,
+};
+#endif
index 69e0806075a22cd739f8a6807d21009d9e89afdd..b7643c16201f67ca44779c3d040fef0184824f9b 100644 (file)
@@ -938,6 +938,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
 #ifdef CONFIG_PM_SLEEP
        MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR);
 #endif
 
        /*
index d68640ea41d42e3ea0612d1fa562de1b00ba50e6..98b1feb43d388f70bc4aadf0f4434cc714744d05 100644 (file)
 #define MAC_INDEX_MIN_DRIVER   0
 #define NUM_MAC_INDEX_DRIVER   MAC_INDEX_AUX
 
-#define AC_NUM 4 /* Number of access categories */
+enum iwl_ac {
+       AC_BK,
+       AC_BE,
+       AC_VI,
+       AC_VO,
+       AC_NUM,
+};
 
 /**
  * enum iwl_mac_protection_flags - MAC context flags
index b4e8e597d2b7038514791e87f6e3e9d6b7008220..273b0cc197ab4e2e7e8af2ea2b65d6baffcdb8a9 100644 (file)
@@ -193,14 +193,11 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
 u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
                                struct ieee80211_vif *vif)
 {
-       u32 qmask, ac;
+       u32 qmask = 0, ac;
 
        if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
                return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
 
-       qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ?
-               BIT(vif->cab_queue) : 0;
-
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
                        qmask |= BIT(vif->hw_queue[ac]);
@@ -365,7 +362,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                break;
        case NL80211_IFTYPE_AP:
                iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue,
-                                       IWL_MVM_TX_FIFO_VO);
+                                       IWL_MVM_TX_FIFO_MCAST);
                /* fall through */
        default:
                for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
@@ -553,6 +550,10 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);
        }
 
+       /* in AP mode, the MCAST FIFO takes the EDCA params from VO */
+       if (vif->type == NL80211_IFTYPE_AP)
+               cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST);
+
        if (vif->bss_conf.qos)
                cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
 
index 12337aac2947ac87bdf5435440bd0709da50d4a0..e08683b2053183f7e7ea9df370a37bdb4b70c2e4 100644 (file)
 static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
        {
                .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION) |
-                       BIT(NL80211_IFTYPE_AP),
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP) |
+                       BIT(NL80211_IFTYPE_P2P_CLIENT) |
+                       BIT(NL80211_IFTYPE_P2P_GO),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
        },
 };
 
@@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        hw->chanctx_data_size = sizeof(u16);
 
        hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_AP);
+               BIT(NL80211_IFTYPE_P2P_CLIENT) |
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_P2P_GO) |
+               BIT(NL80211_IFTYPE_P2P_DEVICE);
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
                            WIPHY_FLAG_DISABLE_BEACON_HINTS |
@@ -224,20 +236,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
            mvm->trans->ops->d3_suspend &&
            mvm->trans->ops->d3_resume &&
            device_can_wakeup(mvm->trans->dev)) {
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT |
-                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                         WIPHY_WOWLAN_RFKILL_RELEASE;
+               mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                                   WIPHY_WOWLAN_DISCONNECT |
+                                   WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                   WIPHY_WOWLAN_RFKILL_RELEASE;
                if (!iwlwifi_mod_params.sw_crypto)
-                       hw->wiphy->wowlan.flags |=
-                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                               WIPHY_WOWLAN_GTK_REKEY_FAILURE |
-                               WIPHY_WOWLAN_4WAY_HANDSHAKE;
-
-               hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
-               hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
-               hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
-               hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
+                       mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                                            WIPHY_WOWLAN_GTK_REKEY_FAILURE |
+                                            WIPHY_WOWLAN_4WAY_HANDSHAKE;
+
+               mvm->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
+               mvm->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
+               mvm->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
+               mvm->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
+               hw->wiphy->wowlan = &mvm->wowlan;
        }
 #endif
 
@@ -597,21 +609,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        mvmvif->phy_ctxt = NULL;
        iwl_mvm_mac_ctxt_remove(mvm, vif);
  out_release:
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * Check if only one additional interface remains after releasing
-        * current one. Update power mode on the remaining interface.
-        */
        if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
                mvm->vif_count--;
-       IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
-                          mvm->vif_count);
-       if (mvm->vif_count == 1) {
-               ieee80211_iterate_active_interfaces(
-                                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-                                       iwl_mvm_power_update_iterator, mvm);
-       }
+       ieee80211_iterate_active_interfaces(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_power_update_iterator, mvm);
        iwl_mvm_mac_ctxt_release(mvm, vif);
  out_unlock:
        mutex_unlock(&mvm->mutex);
@@ -649,8 +651,7 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
                 * By now, all the AC queues are empty. The AGG queues are
                 * empty too. We already got all the Tx responses for all the
                 * packets in the queues. The drain work can have been
-                * triggered. Flush it. This work item takes the mutex, so kill
-                * it before we take it.
+                * triggered. Flush it.
                 */
                flush_work(&mvm->sta_drained_wk);
        }
@@ -773,7 +774,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                        if (ret)
                                IWL_ERR(mvm, "failed to update quotas\n");
                }
-       } else if (changes & BSS_CHANGED_DTIM_PERIOD) {
+               ret = iwl_mvm_power_update_mode(mvm, vif);
+               if (ret)
+                       IWL_ERR(mvm, "failed to update power mode\n");
+       } else if (changes & BSS_CHANGED_BEACON_INFO) {
                /*
                 * We received a beacon _after_ association so
                 * remove the session protection.
@@ -781,19 +785,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                iwl_mvm_remove_time_event(mvm, mvmvif,
                                          &mvmvif->time_event_data);
        } else if (changes & BSS_CHANGED_PS) {
-               /*
-                * TODO: remove this temporary code.
-                * Currently MVM FW supports power management only on single
-                * MAC. Avoid power mode update if more than one interface
-                * is active.
-                */
-               IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
-                                  mvm->vif_count);
-               if (mvm->vif_count == 1) {
-                       ret = iwl_mvm_power_update_mode(mvm, vif);
-                       if (ret)
-                               IWL_ERR(mvm, "failed to update power mode\n");
-               }
+               ret = iwl_mvm_power_update_mode(mvm, vif);
+               if (ret)
+                       IWL_ERR(mvm, "failed to update power mode\n");
        }
 }
 
index 6a3220b6273ed052c3a22e9186a6c52525a5a123..c7409f159a36bf9d28314811b9d4a9fe64d42527 100644 (file)
@@ -88,6 +88,7 @@ enum iwl_mvm_tx_fifo {
        IWL_MVM_TX_FIFO_BE,
        IWL_MVM_TX_FIFO_VI,
        IWL_MVM_TX_FIFO_VO,
+       IWL_MVM_TX_FIFO_MCAST = 5,
 };
 
 extern struct ieee80211_ops iwl_mvm_hw_ops;
@@ -457,10 +458,13 @@ struct iwl_mvm {
        struct ieee80211_vif *p2p_device_vif;
 
 #ifdef CONFIG_PM_SLEEP
+       struct wiphy_wowlan_support wowlan;
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
+       bool d3_test_active;
        bool store_d3_resume_sram;
        void *d3_resume_sram;
+       u32 d3_test_pme_ptr;
 #endif
 #endif
 
@@ -669,6 +673,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
                              struct inet6_dev *idev);
 void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif, int idx);
+extern const struct file_operations iwl_dbgfs_d3_test_ops;
 
 /* BT Coex */
 int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
@@ -685,16 +690,11 @@ void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 void
 iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
                                         struct iwl_beacon_filter_cmd *cmd);
-int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm);
 #else
 static inline void
 iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif,
                                         struct iwl_beacon_filter_cmd *cmd)
 {}
-static inline int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm)
-{
-       return 0;
-}
 #endif
 int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
                                 struct ieee80211_vif *vif);
index d7a199b1cdefc691445f9d4c1fdad05f0b48b367..af79a14063a9bcffbb0a624d3b93f97160dbe057 100644 (file)
@@ -215,15 +215,16 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
        RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false),
        RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),
        RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false),
-       RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
-
-       RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
-       RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
 
        RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
        RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false),
        RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true),
 
+       RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
+
+       RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
+       RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
+
        RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
        RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
 
index 1b4db25d53fbab1272b0b6d1bbdf145349121502..a8652ddd6bedb54ed7bd045d44fc414c618b5ce9 100644 (file)
@@ -204,7 +204,8 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
 {
        int ret;
 
-       WARN_ON(ctxt->ref);
+       WARN_ON(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+               ctxt->ref);
        lockdep_assert_held(&mvm->mutex);
 
        ctxt->channel = chandef->chan;
index 67cf24aa72f9b855b2e306d7fbd42596620d0b63..3760a33ca3a40cbb13a266cd7c96912017bfce1e 100644 (file)
@@ -168,6 +168,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                return;
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
+       if (!vif->bss_conf.assoc)
+               cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF &&
@@ -246,6 +248,17 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
                return 0;
 
+       /*
+        * TODO: The following vif_count verification is temporary condition.
+        * Avoid power mode update if more than one interface is currently
+        * active. Remove this condition when FW will support power management
+        * on multiple MACs.
+        */
+       IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n",
+                       mvm->vif_count);
+       if (mvm->vif_count > 1)
+               return 0;
+
        iwl_mvm_power_build_cmd(mvm, vif, &cmd);
        iwl_mvm_power_log(mvm, &cmd);
 
index a1e3e923ea3e12c1fb6a0adabab88d05b1c5530e..29d49cf0fdb207893091e30542d104e34e829d5f 100644 (file)
@@ -169,27 +169,34 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif)
                        num_active_bindings++;
        }
 
-       if (!num_active_bindings)
-               goto send_cmd;
-
-       quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
-       quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
+       quota = 0;
+       quota_rem = 0;
+       if (num_active_bindings) {
+               quota = IWL_MVM_MAX_QUOTA / num_active_bindings;
+               quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings;
+       }
 
        for (idx = 0, i = 0; i < MAX_BINDINGS; i++) {
-               if (data.n_interfaces[i] <= 0)
+               if (data.colors[i] < 0)
                        continue;
 
                cmd.quotas[idx].id_and_color =
                        cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i]));
-               cmd.quotas[idx].quota = cpu_to_le32(quota);
-               cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA);
+
+               if (data.n_interfaces[i] <= 0) {
+                       cmd.quotas[idx].quota = cpu_to_le32(0);
+                       cmd.quotas[idx].max_duration = cpu_to_le32(0);
+               } else {
+                       cmd.quotas[idx].quota = cpu_to_le32(quota);
+                       cmd.quotas[idx].max_duration =
+                               cpu_to_le32(IWL_MVM_MAX_QUOTA);
+               }
                idx++;
        }
 
        /* Give the remainder of the session to the first binding */
        le32_add_cpu(&cmd.quotas[0].quota, quota_rem);
 
-send_cmd:
        ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC,
                                   sizeof(cmd), &cmd);
        if (ret)
index 6a050c69e7d071b8ef33179fb6cad3efdcb2f645..d6beec765d65727ca1d523a47221319e9759208e 100644 (file)
@@ -401,6 +401,17 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm,
 
        load = rs_tl_get_load(lq_data, tid);
 
+       /*
+        * Don't create TX aggregation sessions when in high
+        * BT traffic, as they would just be disrupted by BT.
+        */
+       if (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2) {
+               IWL_DEBUG_COEX(mvm, "BT traffic (%d), no aggregation allowed\n",
+                              BT_MBOX_MSG(&mvm->last_bt_notif,
+                                          3, TRAFFIC_LOAD));
+               return ret;
+       }
+
        if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) {
                IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n",
                             sta->addr, tid);
@@ -1519,6 +1530,29 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
+                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               valid_tx_ant =
+                       first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
+               if (tbl->action != IWL_SISO_SWITCH_ANTENNA1)
+                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+               break;
+       default:
+               IWL_ERR(mvm, "Invalid BT load %d",
+                       BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
+               break;
+       }
+
        start_action = tbl->action;
        while (1) {
                lq_sta->action_counter++;
@@ -1532,7 +1566,9 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
                             tx_chains_num <= 2))
                                break;
 
-                       if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+                       if (window->success_ratio >= IWL_RS_GOOD_RATIO &&
+                           BT_MBOX_MSG(&mvm->last_bt_notif, 3,
+                                       TRAFFIC_LOAD) == 0)
                                break;
 
                        memcpy(search_tbl, tbl, sz);
@@ -1654,6 +1690,28 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
        u8 update_search_tbl_counter = 0;
        int ret;
 
+       switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO2_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO2_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO2_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO2_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(mvm, "Invalid BT load %d",
+                       BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
+               break;
+       }
+
        start_action = tbl->action;
        while (1) {
                lq_sta->action_counter++;
@@ -1791,6 +1849,28 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
        int ret;
        u8 update_search_tbl_counter = 0;
 
+       switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
+       case IWL_BT_COEX_TRAFFIC_LOAD_NONE:
+               /* nothing */
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
+       case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
+               /* avoid antenna B and MIMO */
+               if (tbl->action != IWL_MIMO3_SWITCH_SISO_A)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
+               /* avoid antenna B unless MIMO */
+               if (tbl->action == IWL_MIMO3_SWITCH_SISO_B ||
+                   tbl->action == IWL_MIMO3_SWITCH_SISO_C)
+                       tbl->action = IWL_MIMO3_SWITCH_SISO_A;
+               break;
+       default:
+               IWL_ERR(mvm, "Invalid BT load %d",
+                       BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD));
+               break;
+       }
+
        start_action = tbl->action;
        while (1) {
                lq_sta->action_counter++;
@@ -2302,6 +2382,32 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
             (current_tpt > (100 * tbl->expected_tpt[low]))))
                scale_action = 0;
 
+       if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >=
+            IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               if (lq_sta->last_bt_traffic >
+                   BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
+                       /*
+                        * don't set scale_action, don't want to scale up if
+                        * the rate scale doesn't otherwise think that is a
+                        * good idea.
+                        */
+               } else if (lq_sta->last_bt_traffic <=
+                          BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) {
+                       scale_action = -1;
+               }
+       }
+       lq_sta->last_bt_traffic =
+               BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD);
+
+       if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >=
+            IWL_BT_COEX_TRAFFIC_LOAD_HIGH) &&
+            (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) {
+               /* search for a new modulation */
+               rs_stay_in_table(lq_sta, true);
+               goto lq_update;
+       }
+
        switch (scale_action) {
        case -1:
                /* Decrease starting rate, update uCode's rate table */
@@ -2782,6 +2888,13 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
 
        lq_cmd->agg_time_limit =
                cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+
+       /*
+        * overwrite if needed, pass aggregation time limit
+        * to uCode in uSec - This is racy - but heh, at least it helps...
+        */
+       if (mvm && BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2)
+               lq_cmd->agg_time_limit = cpu_to_le16(1200);
 }
 
 static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
index f66155a57238e868890ea2041811fe291eed4d0d..cff4f6da77338a4056c585ef9ec2368d4416c6a6 100644 (file)
@@ -358,6 +358,18 @@ struct iwl_lq_sta {
        u8 last_bt_traffic;
 };
 
+enum iwl_bt_coex_profile_traffic_load {
+       IWL_BT_COEX_TRAFFIC_LOAD_NONE           = 0,
+       IWL_BT_COEX_TRAFFIC_LOAD_LOW            = 1,
+       IWL_BT_COEX_TRAFFIC_LOAD_HIGH           = 2,
+       IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS     = 3,
+/*
+ * There are no more even though below is a u8, the
+ * indication from the BT device only has two bits.
+ */
+};
+
+
 static inline u8 num_of_ant(u8 mask)
 {
        return  !!((mask) & ANT_A) +
index 2278858d5658f14a4e9b4d5fc6ed9001e78c3a1c..62fe5209093bf7637cb024b2c81dfd301cfd4649 100644 (file)
@@ -229,9 +229,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
                if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
                        mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
 
-       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-               mvm_sta->tfd_queue_msk |= BIT(vif->cab_queue);
-
        /* for HW restart - need to reset the seq_number etc... */
        memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data));
 
@@ -1292,17 +1289,11 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
        struct iwl_mvm_add_sta_cmd cmd = {
                .add_modify = STA_MODE_MODIFY,
                .sta_id = mvmsta->sta_id,
-               .modify_mask = STA_MODIFY_SLEEPING_STA_TX_COUNT,
-               .sleep_state_flags = cpu_to_le16(STA_SLEEP_STATE_AWAKE),
+               .station_flags_msk = cpu_to_le32(STA_FLG_PS),
                .mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color),
        };
        int ret;
 
-       /*
-        * Same modify mask for sleep_tx_count and sleep_state_flags but this
-        * should be fine since if we set the STA as "awake", then
-        * sleep_tx_count is not relevant.
-        */
        ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
index 3efa0a0cc987eee536757477dd9fd7ac46dd7cf0..94b265eb32b82bfb7a5f467cef60963f5da8d252 100644 (file)
@@ -250,7 +250,6 @@ enum iwl_mvm_agg_state {
  *     the first packet to be sent in legacy HW queue in Tx AGG stop flow.
  *     Basically when next_reclaimed reaches ssn, we can tell mac80211 that
  *     we are ready to finish the Tx AGG stop / start flow.
- * @wait_for_ba: Expect block-ack before next Tx reply
  */
 struct iwl_mvm_tid_data {
        u16 seq_number;
@@ -260,7 +259,6 @@ struct iwl_mvm_tid_data {
        enum iwl_mvm_agg_state state;
        u16 txq_id;
        u16 ssn;
-       bool wait_for_ba;
 };
 
 /**
index 4665fc033c1752503221ad4284eb567182dfbf3f..a7e3b8ddf22b87e91abad2dafd3cd7a0be3aede2 100644 (file)
@@ -371,6 +371,9 @@ static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac,
        else
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
 
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
        iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode);
 }
 
index f212f16502ff43c3b446d3f99e136fbf5c4b795a..a830eb6cc411e7c75476d687cf827ddc721f2d47 100644 (file)
@@ -175,7 +175,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
         * table is controlled by LINK_QUALITY commands
         */
 
-       if (ieee80211_is_data(fc)) {
+       if (ieee80211_is_data(fc) && sta) {
                tx_cmd->initial_rate_index = 0;
                tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
                return;
index c9b44ab4af07ac05dc173813c95e80429101765a..1e1332839e4a745b2a57f9d837b112fff52d75bd 100644 (file)
@@ -76,6 +76,11 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd)
 {
        int ret;
 
+#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)
+       if (WARN_ON(mvm->d3_test_active))
+               return -EIO;
+#endif
+
        /*
         * Synchronous commands from this op-mode must hold
         * the mutex, this ensures we don't try to send two
@@ -125,6 +130,11 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd,
 
        lockdep_assert_held(&mvm->mutex);
 
+#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP)
+       if (WARN_ON(mvm->d3_test_active))
+               return -EIO;
+#endif
+
        /*
         * Only synchronous commands can wait for status,
         * we use WANT_SKB so the caller can't.
index 0b021305eedf121149072fecb6ad9f3d039bfd06..197dbe0a868c5c1a97e8a7c386c5a2ce009038e7 100644 (file)
@@ -578,9 +578,17 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        clear_bit(STATUS_RFKILL, &trans_pcie->status);
 }
 
-static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
+static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
 {
        iwl_disable_interrupts(trans);
+
+       /*
+        * in testing mode, the host stays awake and the
+        * hardware won't be reset (not even partially)
+        */
+       if (test)
+               return;
+
        iwl_pcie_disable_ict(trans);
 
        iwl_clear_bit(trans, CSR_GP_CNTRL,
@@ -599,11 +607,18 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans)
 }
 
 static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
-                                   enum iwl_d3_status *status)
+                                   enum iwl_d3_status *status,
+                                   bool test)
 {
        u32 val;
        int ret;
 
+       if (test) {
+               iwl_enable_interrupts(trans);
+               *status = IWL_D3_STATUS_ALIVE;
+               return 0;
+       }
+
        iwl_pcie_set_pwr(trans, false);
 
        val = iwl_read32(trans, CSR_RESET);
index a35c6aefbc3efe1daf2dd171f1054712842e590b..f65da1984d918c6f840f61519fb0a1da899cdbe7 100644 (file)
@@ -1527,7 +1527,8 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                goto cancel;
        }
 
-       if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+       if (!(cmd->flags & CMD_SEND_IN_RFKILL) &&
+           test_bit(STATUS_RFKILL, &trans_pcie->status)) {
                IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
                ret = -ERFKILL;
                goto cancel;
index 69bbf6fdd2d30b7f10ae0122138f0838fdc26b0d..cb34c7895f2a299b8c6b8f6c094f79cd9ab88c85 100644 (file)
@@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
 #endif
                                 BIT(NL80211_IFTYPE_AP) |
                                 BIT(NL80211_IFTYPE_P2P_GO) },
+       { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
 };
 
 static struct ieee80211_iface_combination hwsim_if_comb = {
@@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void)
                        BIT(NL80211_IFTYPE_P2P_CLIENT) |
                        BIT(NL80211_IFTYPE_P2P_GO) |
                        BIT(NL80211_IFTYPE_ADHOC) |
-                       BIT(NL80211_IFTYPE_MESH_POINT);
+                       BIT(NL80211_IFTYPE_MESH_POINT) |
+                       BIT(NL80211_IFTYPE_P2P_DEVICE);
 
                hw->flags = IEEE80211_HW_MFP_CAPABLE |
                            IEEE80211_HW_SIGNAL_DBM |
index 00a82817eb6b4c1dfa763e51211ad41cc33bdf83..856aea25052ba1ee3ce78e5ebd073605a0c7e001 100644 (file)
@@ -2475,6 +2475,16 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
 #endif
 };
 
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
+       .flags = WIPHY_WOWLAN_MAGIC_PKT,
+       .n_patterns = MWIFIEX_MAX_FILTERS,
+       .pattern_min_len = 1,
+       .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
+       .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
+};
+#endif
+
 /*
  * This function registers the device with CFG802.11 subsystem.
  *
@@ -2532,11 +2542,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
 
 #ifdef CONFIG_PM
-       wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
-       wiphy->wowlan.n_patterns = MWIFIEX_MAX_FILTERS;
-       wiphy->wowlan.pattern_min_len = 1;
-       wiphy->wowlan.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN;
-       wiphy->wowlan.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN;
+       wiphy->wowlan = &mwifiex_wowlan_support;
 #endif
 
        wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
index 753b5682d53fe9277dbc3dd92413250509f72ea4..a5f9875cfd6e311f7e87b40890538ee312b37f4b 100644 (file)
 static struct dentry *mwifiex_dfs_dir;
 
 static char *bss_modes[] = {
-       "Unknown",
-       "Ad-hoc",
-       "Managed",
-       "Auto"
+       "UNSPECIFIED",
+       "ADHOC",
+       "STATION",
+       "AP",
+       "AP_VLAN",
+       "WDS",
+       "MONITOR",
+       "MESH_POINT",
+       "P2P_CLIENT",
+       "P2P_GO",
+       "P2P_DEVICE",
 };
 
 /* size/addr for mwifiex_debug_info */
@@ -200,7 +207,12 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
        p += sprintf(p, "driver_version = %s", fmt);
        p += sprintf(p, "\nverext = %s", priv->version_str);
        p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
-       p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
+
+       if (info.bss_mode >= ARRAY_SIZE(bss_modes))
+               p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
+       else
+               p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
+
        p += sprintf(p, "media_state=\"%s\"\n",
                     (!priv->media_connected ? "Disconnected" : "Connected"));
        p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
index c7f11c0c3bb70e83df1dd2296c3207d7ec948a70..2fe31dcaa6ef2e9deac6afbb6082410774047678 100644 (file)
@@ -52,84 +52,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
        return 0;
 }
 
-static void scan_delay_timer_fn(unsigned long data)
-{
-       struct mwifiex_private *priv = (struct mwifiex_private *)data;
-       struct mwifiex_adapter *adapter = priv->adapter;
-       struct cmd_ctrl_node *cmd_node, *tmp_node;
-       unsigned long flags;
-
-       if (adapter->surprise_removed)
-               return;
-
-       if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
-               /*
-                * Abort scan operation by cancelling all pending scan
-                * commands
-                */
-               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-               list_for_each_entry_safe(cmd_node, tmp_node,
-                                        &adapter->scan_pending_q, list) {
-                       list_del(&cmd_node->list);
-                       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-               }
-               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
-               spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
-               adapter->scan_processing = false;
-               adapter->scan_delay_cnt = 0;
-               adapter->empty_tx_q_cnt = 0;
-               spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-
-               if (priv->scan_request) {
-                       dev_dbg(adapter->dev, "info: aborting scan\n");
-                       cfg80211_scan_done(priv->scan_request, 1);
-                       priv->scan_request = NULL;
-               } else {
-                       priv->scan_aborting = false;
-                       dev_dbg(adapter->dev, "info: scan already aborted\n");
-               }
-               goto done;
-       }
-
-       if (!atomic_read(&priv->adapter->is_tx_received)) {
-               adapter->empty_tx_q_cnt++;
-               if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
-                       /*
-                        * No Tx traffic for 200msec. Get scan command from
-                        * scan pending queue and put to cmd pending queue to
-                        * resume scan operation
-                        */
-                       adapter->scan_delay_cnt = 0;
-                       adapter->empty_tx_q_cnt = 0;
-                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-                       cmd_node = list_first_entry(&adapter->scan_pending_q,
-                                                   struct cmd_ctrl_node, list);
-                       list_del(&cmd_node->list);
-                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-                                              flags);
-
-                       mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
-                                                       true);
-                       queue_work(adapter->workqueue, &adapter->main_work);
-                       goto done;
-               }
-       } else {
-               adapter->empty_tx_q_cnt = 0;
-       }
-
-       /* Delay scan operation further by 20msec */
-       mod_timer(&priv->scan_delay_timer, jiffies +
-                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
-       adapter->scan_delay_cnt++;
-
-done:
-       if (atomic_read(&priv->adapter->is_tx_received))
-               atomic_set(&priv->adapter->is_tx_received, false);
-
-       return;
-}
-
 /*
  * This function initializes the private structure and sets default
  * values to the members.
@@ -211,9 +133,6 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
 
        priv->scan_block = false;
 
-       setup_timer(&priv->scan_delay_timer, scan_delay_timer_fn,
-                   (unsigned long)priv);
-
        return mwifiex_add_bss_prio_tbl(priv);
 }
 
index 5bc7ef8d04d64cb78ba3abd676423366c2488b3c..485871940d3cbfe71e133472d29557ad0ed95073 100644 (file)
@@ -28,6 +28,84 @@ const char driver_version[] = "mwifiex " VERSION " (%s) ";
 static char *cal_data_cfg;
 module_param(cal_data_cfg, charp, 0);
 
+static void scan_delay_timer_fn(unsigned long data)
+{
+       struct mwifiex_private *priv = (struct mwifiex_private *)data;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct cmd_ctrl_node *cmd_node, *tmp_node;
+       unsigned long flags;
+
+       if (adapter->surprise_removed)
+               return;
+
+       if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+               /*
+                * Abort scan operation by cancelling all pending scan
+                * commands
+                */
+               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+               list_for_each_entry_safe(cmd_node, tmp_node,
+                                        &adapter->scan_pending_q, list) {
+                       list_del(&cmd_node->list);
+                       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+               }
+               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+               spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+               adapter->scan_processing = false;
+               adapter->scan_delay_cnt = 0;
+               adapter->empty_tx_q_cnt = 0;
+               spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+               if (priv->scan_request) {
+                       dev_dbg(adapter->dev, "info: aborting scan\n");
+                       cfg80211_scan_done(priv->scan_request, 1);
+                       priv->scan_request = NULL;
+               } else {
+                       priv->scan_aborting = false;
+                       dev_dbg(adapter->dev, "info: scan already aborted\n");
+               }
+               goto done;
+       }
+
+       if (!atomic_read(&priv->adapter->is_tx_received)) {
+               adapter->empty_tx_q_cnt++;
+               if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
+                       /*
+                        * No Tx traffic for 200msec. Get scan command from
+                        * scan pending queue and put to cmd pending queue to
+                        * resume scan operation
+                        */
+                       adapter->scan_delay_cnt = 0;
+                       adapter->empty_tx_q_cnt = 0;
+                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+                       cmd_node = list_first_entry(&adapter->scan_pending_q,
+                                                   struct cmd_ctrl_node, list);
+                       list_del(&cmd_node->list);
+                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+                                              flags);
+
+                       mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+                                                       true);
+                       queue_work(adapter->workqueue, &adapter->main_work);
+                       goto done;
+               }
+       } else {
+               adapter->empty_tx_q_cnt = 0;
+       }
+
+       /* Delay scan operation further by 20msec */
+       mod_timer(&priv->scan_delay_timer, jiffies +
+                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+       adapter->scan_delay_cnt++;
+
+done:
+       if (atomic_read(&priv->adapter->is_tx_received))
+               atomic_set(&priv->adapter->is_tx_received, false);
+
+       return;
+}
+
 /*
  * This function registers the device and performs all the necessary
  * initializations.
@@ -75,6 +153,10 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
 
                adapter->priv[i]->adapter = adapter;
                adapter->priv_num++;
+
+               setup_timer(&adapter->priv[i]->scan_delay_timer,
+                           scan_delay_timer_fn,
+                           (unsigned long)adapter->priv[i]);
        }
        mwifiex_init_lock_list(adapter);
 
index 4be3d33ceae81b25bddbab91ea01482282571f2b..944e8846f6fc757e8f937f0ece42e243279e9a29 100644 (file)
@@ -37,6 +37,9 @@
 /* Offset for TOS field in the IP header */
 #define IPTOS_OFFSET 5
 
+static bool enable_tx_amsdu;
+module_param(enable_tx_amsdu, bool, 0644);
+
 /* WMM information IE */
 static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
        0x00, 0x50, 0xf2, 0x02,
@@ -1233,7 +1236,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
                                mwifiex_send_delba(priv, tid_del, ra, 1);
                        }
                }
-               if (mwifiex_is_amsdu_allowed(priv, tid) &&
+               if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) &&
                    mwifiex_is_11n_aggragation_possible(priv, ptr,
                                                        adapter->tx_buf_size))
                        mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
index f7143733d7e95eaeba3a5f8ea8c2aff80c350334..3d53a09da5a12da22f2697c9a22b7dfb49daaff0 100644 (file)
@@ -1767,33 +1767,45 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
        .config                 = rt2400pci_config,
 };
 
-static const struct data_queue_desc rt2400pci_queue_rx = {
-       .entry_num              = 24,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+static void rt2400pci_queue_init(struct data_queue *queue)
+{
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 24;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = RXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2400pci_queue_tx = {
-       .entry_num              = 24,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 24;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2400pci_queue_bcn = {
-       .entry_num              = 1,
-       .data_size              = MGMT_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_BEACON:
+               queue->limit = 1;
+               queue->data_size = MGMT_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2400pci_queue_atim = {
-       .entry_num              = 8,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_ATIM:
+               queue->limit = 8;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
+
+       default:
+               BUG();
+               break;
+       }
+}
 
 static const struct rt2x00_ops rt2400pci_ops = {
        .name                   = KBUILD_MODNAME,
@@ -1801,11 +1813,7 @@ static const struct rt2x00_ops rt2400pci_ops = {
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = 0,
-       .rx                     = &rt2400pci_queue_rx,
-       .tx                     = &rt2400pci_queue_tx,
-       .bcn                    = &rt2400pci_queue_bcn,
-       .atim                   = &rt2400pci_queue_atim,
+       .queue_init             = rt2400pci_queue_init,
        .lib                    = &rt2400pci_rt2x00_ops,
        .hw                     = &rt2400pci_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
index 77e45b223d158348b958a7b5a88b84cecfc6f3a2..0ac5c589ddceaffe7dd0f7d82ce7a508e37e4bd7 100644 (file)
@@ -2056,33 +2056,45 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
        .config                 = rt2500pci_config,
 };
 
-static const struct data_queue_desc rt2500pci_queue_rx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+static void rt2500pci_queue_init(struct data_queue *queue)
+{
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = RXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2500pci_queue_tx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2500pci_queue_bcn = {
-       .entry_num              = 1,
-       .data_size              = MGMT_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_BEACON:
+               queue->limit = 1;
+               queue->data_size = MGMT_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2500pci_queue_atim = {
-       .entry_num              = 8,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_ATIM:
+               queue->limit = 8;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
+
+       default:
+               BUG();
+               break;
+       }
+}
 
 static const struct rt2x00_ops rt2500pci_ops = {
        .name                   = KBUILD_MODNAME,
@@ -2090,11 +2102,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = 0,
-       .rx                     = &rt2500pci_queue_rx,
-       .tx                     = &rt2500pci_queue_tx,
-       .bcn                    = &rt2500pci_queue_bcn,
-       .atim                   = &rt2500pci_queue_atim,
+       .queue_init             = rt2500pci_queue_init,
        .lib                    = &rt2500pci_rt2x00_ops,
        .hw                     = &rt2500pci_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
index a7f7b365eff476c7f74e33660ea3c850882413f7..85acc79f68b840c48ffe76715546fb10fac377a9 100644 (file)
@@ -1867,33 +1867,45 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .config                 = rt2500usb_config,
 };
 
-static const struct data_queue_desc rt2500usb_queue_rx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+static void rt2500usb_queue_init(struct data_queue *queue)
+{
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = RXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
-static const struct data_queue_desc rt2500usb_queue_tx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
-static const struct data_queue_desc rt2500usb_queue_bcn = {
-       .entry_num              = 1,
-       .data_size              = MGMT_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_bcn),
-};
+       case QID_BEACON:
+               queue->limit = 1;
+               queue->data_size = MGMT_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb_bcn);
+               break;
 
-static const struct data_queue_desc rt2500usb_queue_atim = {
-       .entry_num              = 8,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       case QID_ATIM:
+               queue->limit = 8;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
+
+       default:
+               BUG();
+               break;
+       }
+}
 
 static const struct rt2x00_ops rt2500usb_ops = {
        .name                   = KBUILD_MODNAME,
@@ -1901,11 +1913,7 @@ static const struct rt2x00_ops rt2500usb_ops = {
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = TXD_DESC_SIZE,
-       .rx                     = &rt2500usb_queue_rx,
-       .tx                     = &rt2500usb_queue_tx,
-       .bcn                    = &rt2500usb_queue_bcn,
-       .atim                   = &rt2500usb_queue_atim,
+       .queue_init             = rt2500usb_queue_init,
        .lib                    = &rt2500usb_rt2x00_ops,
        .hw                     = &rt2500usb_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
index 330f1d25726df054f862ec0a7188178243d97efa..7c7478219bbc45837f6f9794f42c84c5bc9a1c77 100644 (file)
@@ -1186,29 +1186,43 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
        .sta_remove             = rt2800_sta_remove,
 };
 
-static const struct data_queue_desc rt2800pci_queue_rx = {
-       .entry_num              = 128,
-       .data_size              = AGGREGATION_SIZE,
-       .desc_size              = RXD_DESC_SIZE,
-       .winfo_size             = RXWI_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+static void rt2800pci_queue_init(struct data_queue *queue)
+{
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 128;
+               queue->data_size = AGGREGATION_SIZE;
+               queue->desc_size = RXD_DESC_SIZE;
+               queue->winfo_size = RXWI_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2800pci_queue_tx = {
-       .entry_num              = 64,
-       .data_size              = AGGREGATION_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .winfo_size             = TXWI_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 64;
+               queue->data_size = AGGREGATION_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->winfo_size = TXWI_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt2800pci_queue_bcn = {
-       .entry_num              = 8,
-       .data_size              = 0, /* No DMA required for beacons */
-       .desc_size              = TXD_DESC_SIZE,
-       .winfo_size             = TXWI_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_BEACON:
+               queue->limit = 8;
+               queue->data_size = 0; /* No DMA required for beacons */
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->winfo_size = TXWI_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
+
+       case QID_ATIM:
+               /* fallthrough */
+       default:
+               BUG();
+               break;
+       }
+}
 
 static const struct rt2x00_ops rt2800pci_ops = {
        .name                   = KBUILD_MODNAME,
@@ -1217,10 +1231,7 @@ static const struct rt2x00_ops rt2800pci_ops = {
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = TXWI_DESC_SIZE,
-       .rx                     = &rt2800pci_queue_rx,
-       .tx                     = &rt2800pci_queue_tx,
-       .bcn                    = &rt2800pci_queue_bcn,
+       .queue_init             = rt2800pci_queue_init,
        .lib                    = &rt2800pci_rt2x00_ops,
        .drv                    = &rt2800pci_rt2800_ops,
        .hw                     = &rt2800pci_mac80211_ops,
index c71a48da9a315b81938471b1d6090be9b2571fef..7edd903dd749dae9d23347c4f3683a20eaa7652e 100644 (file)
@@ -849,85 +849,63 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .sta_remove             = rt2800_sta_remove,
 };
 
-static const struct data_queue_desc rt2800usb_queue_rx = {
-       .entry_num              = 128,
-       .data_size              = AGGREGATION_SIZE,
-       .desc_size              = RXINFO_DESC_SIZE,
-       .winfo_size             = RXWI_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
-
-static const struct data_queue_desc rt2800usb_queue_tx = {
-       .entry_num              = 16,
-       .data_size              = AGGREGATION_SIZE,
-       .desc_size              = TXINFO_DESC_SIZE,
-       .winfo_size             = TXWI_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
-
-static const struct data_queue_desc rt2800usb_queue_bcn = {
-       .entry_num              = 8,
-       .data_size              = MGMT_FRAME_SIZE,
-       .desc_size              = TXINFO_DESC_SIZE,
-       .winfo_size             = TXWI_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+static void rt2800usb_queue_init(struct data_queue *queue)
+{
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       unsigned short txwi_size, rxwi_size;
 
-static const struct rt2x00_ops rt2800usb_ops = {
-       .name                   = KBUILD_MODNAME,
-       .drv_data_size          = sizeof(struct rt2800_drv_data),
-       .max_ap_intf            = 8,
-       .eeprom_size            = EEPROM_SIZE,
-       .rf_size                = RF_SIZE,
-       .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = TXINFO_DESC_SIZE + TXWI_DESC_SIZE,
-       .rx                     = &rt2800usb_queue_rx,
-       .tx                     = &rt2800usb_queue_tx,
-       .bcn                    = &rt2800usb_queue_bcn,
-       .lib                    = &rt2800usb_rt2x00_ops,
-       .drv                    = &rt2800usb_rt2800_ops,
-       .hw                     = &rt2800usb_mac80211_ops,
-#ifdef CONFIG_RT2X00_LIB_DEBUGFS
-       .debugfs                = &rt2800_rt2x00debug,
-#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-};
+       if (rt2x00_rt(rt2x00dev, RT5592)) {
+               txwi_size = TXWI_DESC_SIZE_5592;
+               rxwi_size = RXWI_DESC_SIZE_5592;
+       } else {
+               txwi_size = TXWI_DESC_SIZE;
+               rxwi_size = RXWI_DESC_SIZE;
+       }
 
-static const struct data_queue_desc rt2800usb_queue_rx_5592 = {
-       .entry_num              = 128,
-       .data_size              = AGGREGATION_SIZE,
-       .desc_size              = RXINFO_DESC_SIZE,
-       .winfo_size             = RXWI_DESC_SIZE_5592,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 128;
+               queue->data_size = AGGREGATION_SIZE;
+               queue->desc_size = RXINFO_DESC_SIZE;
+               queue->winfo_size = rxwi_size;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
-static const struct data_queue_desc rt2800usb_queue_tx_5592 = {
-       .entry_num              = 16,
-       .data_size              = AGGREGATION_SIZE,
-       .desc_size              = TXINFO_DESC_SIZE,
-       .winfo_size             = TXWI_DESC_SIZE_5592,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 16;
+               queue->data_size = AGGREGATION_SIZE;
+               queue->desc_size = TXINFO_DESC_SIZE;
+               queue->winfo_size = txwi_size;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
-static const struct data_queue_desc rt2800usb_queue_bcn_5592 = {
-       .entry_num              = 8,
-       .data_size              = MGMT_FRAME_SIZE,
-       .desc_size              = TXINFO_DESC_SIZE,
-       .winfo_size             = TXWI_DESC_SIZE_5592,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       case QID_BEACON:
+               queue->limit = 8;
+               queue->data_size = MGMT_FRAME_SIZE;
+               queue->desc_size = TXINFO_DESC_SIZE;
+               queue->winfo_size = txwi_size;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
+       case QID_ATIM:
+               /* fallthrough */
+       default:
+               BUG();
+               break;
+       }
+}
 
-static const struct rt2x00_ops rt2800usb_ops_5592 = {
+static const struct rt2x00_ops rt2800usb_ops = {
        .name                   = KBUILD_MODNAME,
        .drv_data_size          = sizeof(struct rt2800_drv_data),
        .max_ap_intf            = 8,
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = TXINFO_DESC_SIZE + TXWI_DESC_SIZE_5592,
-       .rx                     = &rt2800usb_queue_rx_5592,
-       .tx                     = &rt2800usb_queue_tx_5592,
-       .bcn                    = &rt2800usb_queue_bcn_5592,
+       .queue_init             = rt2800usb_queue_init,
        .lib                    = &rt2800usb_rt2x00_ops,
        .drv                    = &rt2800usb_rt2800_ops,
        .hw                     = &rt2800usb_mac80211_ops,
@@ -1248,15 +1226,15 @@ static struct usb_device_id rt2800usb_device_table[] = {
 #endif
 #ifdef CONFIG_RT2800USB_RT55XX
        /* Arcadyan */
-       { USB_DEVICE(0x043e, 0x7a32), .driver_info = 5592 },
+       { USB_DEVICE(0x043e, 0x7a32) },
        /* AVM GmbH */
-       { USB_DEVICE(0x057c, 0x8501), .driver_info = 5592 },
+       { USB_DEVICE(0x057c, 0x8501) },
        /* D-Link DWA-160-B2 */
-       { USB_DEVICE(0x2001, 0x3c1a), .driver_info = 5592 },
+       { USB_DEVICE(0x2001, 0x3c1a) },
        /* Proware */
-       { USB_DEVICE(0x043e, 0x7a13), .driver_info = 5592 },
+       { USB_DEVICE(0x043e, 0x7a13) },
        /* Ralink */
-       { USB_DEVICE(0x148f, 0x5572), .driver_info = 5592 },
+       { USB_DEVICE(0x148f, 0x5572) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
        /*
@@ -1361,9 +1339,6 @@ MODULE_LICENSE("GPL");
 static int rt2800usb_probe(struct usb_interface *usb_intf,
                           const struct usb_device_id *id)
 {
-       if (id->driver_info == 5592)
-               return rt2x00usb_probe(usb_intf, &rt2800usb_ops_5592);
-
        return rt2x00usb_probe(usb_intf, &rt2800usb_ops);
 }
 
index 7510723a8c378389b93b90001efe088118f045bb..ee3fc570b11d04b0a6531f182abb1113dcd9be93 100644 (file)
@@ -648,11 +648,7 @@ struct rt2x00_ops {
        const unsigned int eeprom_size;
        const unsigned int rf_size;
        const unsigned int tx_queues;
-       const unsigned int extra_tx_headroom;
-       const struct data_queue_desc *rx;
-       const struct data_queue_desc *tx;
-       const struct data_queue_desc *bcn;
-       const struct data_queue_desc *atim;
+       void (*queue_init)(struct data_queue *queue);
        const struct rt2x00lib_ops *lib;
        const void *drv;
        const struct ieee80211_ops *hw;
@@ -1010,6 +1006,9 @@ struct rt2x00_dev {
         */
        struct list_head bar_list;
        spinlock_t bar_list_lock;
+
+       /* Extra TX headroom required for alignment purposes. */
+       unsigned int extra_tx_headroom;
 };
 
 struct rt2x00_bar_list_entry {
index 6a201725bc5093b7c1ce064d8987f18430f1fce8..f03e3bba51c340e37469888ca77e8613b77412aa 100644 (file)
@@ -334,7 +334,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
        /*
         * Remove the extra tx headroom from the skb.
         */
-       skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+       skb_pull(entry->skb, rt2x00dev->extra_tx_headroom);
 
        /*
         * Signal that the TX descriptor is no longer in the skb.
@@ -1049,7 +1049,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->hw->extra_tx_headroom =
                max_t(unsigned int, IEEE80211_TX_STATUS_HEADROOM,
-                     rt2x00dev->ops->extra_tx_headroom);
+                     rt2x00dev->extra_tx_headroom);
 
        /*
         * Take TX headroom required for alignment into account.
@@ -1256,6 +1256,17 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
        rt2x00dev->hw->wiphy->n_iface_combinations = 1;
 }
 
+static unsigned int rt2x00dev_extra_tx_headroom(struct rt2x00_dev *rt2x00dev)
+{
+       if (WARN_ON(!rt2x00dev->tx))
+               return 0;
+
+       if (rt2x00_is_usb(rt2x00dev))
+               return rt2x00dev->tx[0].winfo_size + rt2x00dev->tx[0].desc_size;
+
+       return rt2x00dev->tx[0].winfo_size;
+}
+
 /*
  * driver allocation handlers.
  */
@@ -1330,13 +1341,16 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
        if (retval)
                goto exit;
 
+       /* Cache TX headroom value */
+       rt2x00dev->extra_tx_headroom = rt2x00dev_extra_tx_headroom(rt2x00dev);
+
        /*
         * Determine which operating modes are supported, all modes
         * which require beaconing, depend on the availability of
         * beacon entries.
         */
        rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
-       if (rt2x00dev->ops->bcn->entry_num > 0)
+       if (rt2x00dev->bcn->limit > 0)
                rt2x00dev->hw->wiphy->interface_modes |=
                    BIT(NL80211_IFTYPE_ADHOC) |
                    BIT(NL80211_IFTYPE_AP) |
index 2c12311467a99cd634c7b204eaccc36eb75d2aaa..6c0a91ff963c6833bb7d325cac7954c7c10b41fc 100644 (file)
@@ -542,8 +542,8 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
        /*
         * Add the requested extra tx headroom in front of the skb.
         */
-       skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
-       memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+       skb_push(entry->skb, rt2x00dev->extra_tx_headroom);
+       memset(entry->skb->data, 0, rt2x00dev->extra_tx_headroom);
 
        /*
         * Call the driver's write_tx_data function, if it exists.
@@ -596,7 +596,7 @@ static void rt2x00queue_bar_check(struct queue_entry *entry)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct ieee80211_bar *bar = (void *) (entry->skb->data +
-                                   rt2x00dev->ops->extra_tx_headroom);
+                                   rt2x00dev->extra_tx_headroom);
        struct rt2x00_bar_list_entry *bar_entry;
 
        if (likely(!ieee80211_is_back_req(bar->frame_control)))
@@ -1161,8 +1161,7 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
        }
 }
 
-static int rt2x00queue_alloc_entries(struct data_queue *queue,
-                                    const struct data_queue_desc *qdesc)
+static int rt2x00queue_alloc_entries(struct data_queue *queue)
 {
        struct queue_entry *entries;
        unsigned int entry_size;
@@ -1170,16 +1169,10 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
 
        rt2x00queue_reset(queue);
 
-       queue->limit = qdesc->entry_num;
-       queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10);
-       queue->data_size = qdesc->data_size;
-       queue->desc_size = qdesc->desc_size;
-       queue->winfo_size = qdesc->winfo_size;
-
        /*
         * Allocate all queue entries.
         */
-       entry_size = sizeof(*entries) + qdesc->priv_size;
+       entry_size = sizeof(*entries) + queue->priv_size;
        entries = kcalloc(queue->limit, entry_size, GFP_KERNEL);
        if (!entries)
                return -ENOMEM;
@@ -1195,7 +1188,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
                entries[i].entry_idx = i;
                entries[i].priv_data =
                    QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit,
-                                           sizeof(*entries), qdesc->priv_size);
+                                           sizeof(*entries), queue->priv_size);
        }
 
 #undef QUEUE_ENTRY_PRIV_OFFSET
@@ -1237,23 +1230,22 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
        int status;
 
-       status = rt2x00queue_alloc_entries(rt2x00dev->rx, rt2x00dev->ops->rx);
+       status = rt2x00queue_alloc_entries(rt2x00dev->rx);
        if (status)
                goto exit;
 
        tx_queue_for_each(rt2x00dev, queue) {
-               status = rt2x00queue_alloc_entries(queue, rt2x00dev->ops->tx);
+               status = rt2x00queue_alloc_entries(queue);
                if (status)
                        goto exit;
        }
 
-       status = rt2x00queue_alloc_entries(rt2x00dev->bcn, rt2x00dev->ops->bcn);
+       status = rt2x00queue_alloc_entries(rt2x00dev->bcn);
        if (status)
                goto exit;
 
        if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) {
-               status = rt2x00queue_alloc_entries(rt2x00dev->atim,
-                                                  rt2x00dev->ops->atim);
+               status = rt2x00queue_alloc_entries(rt2x00dev->atim);
                if (status)
                        goto exit;
        }
@@ -1297,6 +1289,10 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
        queue->aifs = 2;
        queue->cw_min = 5;
        queue->cw_max = 10;
+
+       rt2x00dev->ops->queue_init(queue);
+
+       queue->threshold = DIV_ROUND_UP(queue->limit, 10);
 }
 
 int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
index 4a7b34e9261bde758f560d0a077c8f7f7b1251bf..ebe11722497995a88d941acaa9749cef8fb83e39 100644 (file)
@@ -453,6 +453,7 @@ enum data_queue_flags {
  * @cw_max: The cw max value for outgoing frames (field ignored in RX queue).
  * @data_size: Maximum data size for the frames in this queue.
  * @desc_size: Hardware descriptor size for the data in this queue.
+ * @priv_size: Size of per-queue_entry private data.
  * @usb_endpoint: Device endpoint used for communication (USB only)
  * @usb_maxpacket: Max packet size for given endpoint (USB only)
  */
@@ -481,30 +482,12 @@ struct data_queue {
        unsigned short data_size;
        unsigned char  desc_size;
        unsigned char  winfo_size;
+       unsigned short priv_size;
 
        unsigned short usb_endpoint;
        unsigned short usb_maxpacket;
 };
 
-/**
- * struct data_queue_desc: Data queue description
- *
- * The information in this structure is used by drivers
- * to inform rt2x00lib about the creation of the data queue.
- *
- * @entry_num: Maximum number of entries for a queue.
- * @data_size: Maximum data size for the frames in this queue.
- * @desc_size: Hardware descriptor size for the data in this queue.
- * @priv_size: Size of per-queue_entry private data.
- */
-struct data_queue_desc {
-       unsigned short entry_num;
-       unsigned short data_size;
-       unsigned char  desc_size;
-       unsigned char  winfo_size;
-       unsigned short priv_size;
-};
-
 /**
  * queue_end - Return pointer to the last queue (HELPER MACRO).
  * @__dev: Pointer to &struct rt2x00_dev
index 7e1759b3e49a0ff7c3bebc5b603ed728896494ad..53754bc66d051500ec62ab2fbc9c1b50d199ff2c 100644 (file)
@@ -3025,26 +3025,40 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
        .config                 = rt61pci_config,
 };
 
-static const struct data_queue_desc rt61pci_queue_rx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+static void rt61pci_queue_init(struct data_queue *queue)
+{
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = RXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt61pci_queue_tx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
 
-static const struct data_queue_desc rt61pci_queue_bcn = {
-       .entry_num              = 4,
-       .data_size              = 0, /* No DMA required for beacons */
-       .desc_size              = TXINFO_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_mmio),
-};
+       case QID_BEACON:
+               queue->limit = 4;
+               queue->data_size = 0; /* No DMA required for beacons */
+               queue->desc_size = TXINFO_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_mmio);
+               break;
+
+       case QID_ATIM:
+               /* fallthrough */
+       default:
+               BUG();
+               break;
+       }
+}
 
 static const struct rt2x00_ops rt61pci_ops = {
        .name                   = KBUILD_MODNAME,
@@ -3052,10 +3066,7 @@ static const struct rt2x00_ops rt61pci_ops = {
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = 0,
-       .rx                     = &rt61pci_queue_rx,
-       .tx                     = &rt61pci_queue_tx,
-       .bcn                    = &rt61pci_queue_bcn,
+       .queue_init             = rt61pci_queue_init,
        .lib                    = &rt61pci_rt2x00_ops,
        .hw                     = &rt61pci_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
index 377e09bb0b812cb9c269678a3b6f55696140e48d..1616ed484ceb02c928be16eaa06f72fe76b60dd8 100644 (file)
@@ -2359,26 +2359,40 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .config                 = rt73usb_config,
 };
 
-static const struct data_queue_desc rt73usb_queue_rx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+static void rt73usb_queue_init(struct data_queue *queue)
+{
+       switch (queue->qid) {
+       case QID_RX:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = RXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
-static const struct data_queue_desc rt73usb_queue_tx = {
-       .entry_num              = 32,
-       .data_size              = DATA_FRAME_SIZE,
-       .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       case QID_AC_VO:
+       case QID_AC_VI:
+       case QID_AC_BE:
+       case QID_AC_BK:
+               queue->limit = 32;
+               queue->data_size = DATA_FRAME_SIZE;
+               queue->desc_size = TXD_DESC_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
 
-static const struct data_queue_desc rt73usb_queue_bcn = {
-       .entry_num              = 4,
-       .data_size              = MGMT_FRAME_SIZE,
-       .desc_size              = TXINFO_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb),
-};
+       case QID_BEACON:
+               queue->limit = 4;
+               queue->data_size = MGMT_FRAME_SIZE;
+               queue->desc_size = TXINFO_SIZE;
+               queue->priv_size = sizeof(struct queue_entry_priv_usb);
+               break;
+
+       case QID_ATIM:
+               /* fallthrough */
+       default:
+               BUG();
+               break;
+       }
+}
 
 static const struct rt2x00_ops rt73usb_ops = {
        .name                   = KBUILD_MODNAME,
@@ -2386,10 +2400,7 @@ static const struct rt2x00_ops rt73usb_ops = {
        .eeprom_size            = EEPROM_SIZE,
        .rf_size                = RF_SIZE,
        .tx_queues              = NUM_TX_QUEUES,
-       .extra_tx_headroom      = TXD_DESC_SIZE,
-       .rx                     = &rt73usb_queue_rx,
-       .tx                     = &rt73usb_queue_tx,
-       .bcn                    = &rt73usb_queue_bcn,
+       .queue_init             = rt73usb_queue_init,
        .lib                    = &rt73usb_rt2x00_ops,
        .hw                     = &rt73usb_mac80211_ops,
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
index 999ffc12578be27fb9b07259e69c723eb0efdbd3..c97e9d327331c8b25624327ec4d672c7289f4492 100644 (file)
@@ -764,6 +764,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                                 "can't alloc skb for rx\n");
                        goto done;
                }
+               kmemleak_not_leak(new_skb);
 
                pci_unmap_single(rtlpci->pdev,
                                 *((dma_addr_t *) skb->cb),
index d3a02e73f53ad59f99dd00be5417776d67022466..21ca33a7c770b83e338bd735084d417444810efc 100644 (file)
@@ -550,7 +550,7 @@ do {                                                                \
         rxmcs == DESC92C_RATE11M)
 
 struct phy_rx_agc_info_t {
-       #if __LITTLE_ENDIAN
+       #ifdef __LITTLE_ENDIAN
                u8      gain:7, trsw:1;
        #else
                u8      trsw:1, gain:7;
@@ -574,7 +574,7 @@ struct phy_status_rpt {
        u8      stream_target_csi[2];
        u8      sig_evm;
        u8      rsvd_3;
-#if __LITTLE_ENDIAN
+#ifdef __LITTLE_ENDIAN
        u8      antsel_rx_keep_2:1;     /*ex_intf_flg:1;*/
        u8      sgi_en:1;
        u8      rxsc:2;
index 3d0498e69c8cf1b54a5474fe7bdc7f92d6687239..189ba124a8c6f4cfca817e77d4b0c7027c976459 100644 (file)
@@ -1973,26 +1973,35 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
        }
 }
 
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
-                                  struct ieee80211_sta *sta,
-                                  u8 rssi_level)
+static void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+                                         struct ieee80211_sta *sta)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       u32 ratr_value = (u32) mac->basic_rates;
-       u8 *mcsrate = mac->mcs;
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u32 ratr_value;
        u8 ratr_index = 0;
        u8 nmode = mac->ht_enable;
-       u8 mimo_ps = 1;
-       u16 shortgi_rate = 0;
-       u32 tmp_ratr_value = 0;
+       u8 mimo_ps = IEEE80211_SMPS_OFF;
+       u16 shortgi_rate;
+       u32 tmp_ratr_value;
        u8 curtxbw_40mhz = mac->bw_40;
-       u8 curshortgi_40mhz = mac->sgi_40;
-       u8 curshortgi_20mhz = mac->sgi_20;
+       u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                              1 : 0;
+       u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+                              1 : 0;
        enum wireless_mode wirelessmode = mac->mode;
 
-       ratr_value |= ((*(u16 *) (mcsrate))) << 12;
+       if (rtlhal->current_bandtype == BAND_ON_5G)
+               ratr_value = sta->supp_rates[1] << 4;
+       else
+               ratr_value = sta->supp_rates[0];
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               ratr_value = 0xfff;
+
+       ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+                       sta->ht_cap.mcs.rx_mask[0] << 12);
        switch (wirelessmode) {
        case WIRELESS_MODE_B:
                if (ratr_value & 0x0000000c)
@@ -2006,7 +2015,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
        case WIRELESS_MODE_N_24G:
        case WIRELESS_MODE_N_5G:
                nmode = 1;
-               if (mimo_ps == 0) {
+               if (mimo_ps == IEEE80211_SMPS_STATIC) {
                        ratr_value &= 0x0007F005;
                } else {
                        u32 ratr_mask;
@@ -2016,8 +2025,7 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
                                ratr_mask = 0x000ff005;
                        else
                                ratr_mask = 0x0f0ff005;
-                       if (curtxbw_40mhz)
-                               ratr_mask |= 0x00000010;
+
                        ratr_value &= ratr_mask;
                }
                break;
@@ -2026,41 +2034,74 @@ void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
                        ratr_value &= 0x000ff0ff;
                else
                        ratr_value &= 0x0f0ff0ff;
+
                break;
        }
+
        ratr_value &= 0x0FFFFFFF;
-       if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
-           (!curtxbw_40mhz && curshortgi_20mhz))) {
+
+       if (nmode && ((curtxbw_40mhz &&
+                        curshortgi_40mhz) || (!curtxbw_40mhz &&
+                                              curshortgi_20mhz))) {
+
                ratr_value |= 0x10000000;
                tmp_ratr_value = (ratr_value >> 12);
+
                for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
                        if ((1 << shortgi_rate) & tmp_ratr_value)
                                break;
                }
+
                shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
-                              (shortgi_rate << 4) | (shortgi_rate);
+                   (shortgi_rate << 4) | (shortgi_rate);
        }
+
        rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "%x\n",
+                rtl_read_dword(rtlpriv, REG_ARFR0));
 }
 
-void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
+static void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw,
+                                        struct ieee80211_sta *sta,
+                                        u8 rssi_level)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       u32 ratr_bitmap = (u32) mac->basic_rates;
-       u8 *p_mcsrate = mac->mcs;
-       u8 ratr_index = 0;
-       u8 curtxbw_40mhz = mac->bw_40;
-       u8 curshortgi_40mhz = mac->sgi_40;
-       u8 curshortgi_20mhz = mac->sgi_20;
-       enum wireless_mode wirelessmode = mac->mode;
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_sta_info *sta_entry = NULL;
+       u32 ratr_bitmap;
+       u8 ratr_index;
+       u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
+       u8 curshortgi_40mhz = curtxbw_40mhz &&
+                             (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                               1 : 0;
+       u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+                               1 : 0;
+       enum wireless_mode wirelessmode = 0;
        bool shortgi = false;
        u8 rate_mask[5];
        u8 macid = 0;
-       u8 mimops = 1;
-
-       ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12);
+       u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+       sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+       wirelessmode = sta_entry->wireless_mode;
+       if (mac->opmode == NL80211_IFTYPE_STATION ||
+           mac->opmode == NL80211_IFTYPE_MESH_POINT)
+               curtxbw_40mhz = mac->bw_40;
+       else if (mac->opmode == NL80211_IFTYPE_AP ||
+               mac->opmode == NL80211_IFTYPE_ADHOC)
+               macid = sta->aid + 1;
+
+       if (rtlhal->current_bandtype == BAND_ON_5G)
+               ratr_bitmap = sta->supp_rates[1] << 4;
+       else
+               ratr_bitmap = sta->supp_rates[0];
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               ratr_bitmap = 0xfff;
+       ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+                       sta->ht_cap.mcs.rx_mask[0] << 12);
        switch (wirelessmode) {
        case WIRELESS_MODE_B:
                ratr_index = RATR_INX_WIRELESS_B;
@@ -2071,6 +2112,7 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
                break;
        case WIRELESS_MODE_G:
                ratr_index = RATR_INX_WIRELESS_GB;
+
                if (rssi_level == 1)
                        ratr_bitmap &= 0x00000f00;
                else if (rssi_level == 2)
@@ -2085,7 +2127,8 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
        case WIRELESS_MODE_N_24G:
        case WIRELESS_MODE_N_5G:
                ratr_index = RATR_INX_WIRELESS_NGB;
-               if (mimops == 0) {
+
+               if (mimo_ps == IEEE80211_SMPS_STATIC) {
                        if (rssi_level == 1)
                                ratr_bitmap &= 0x00070000;
                        else if (rssi_level == 2)
@@ -2128,8 +2171,10 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
                                }
                        }
                }
+
                if ((curtxbw_40mhz && curshortgi_40mhz) ||
                    (!curtxbw_40mhz && curshortgi_20mhz)) {
+
                        if (macid == 0)
                                shortgi = true;
                        else if (macid == 1)
@@ -2138,21 +2183,42 @@ void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
                break;
        default:
                ratr_index = RATR_INX_WIRELESS_NGB;
+
                if (rtlphy->rf_type == RF_1T2R)
                        ratr_bitmap &= 0x000ff0ff;
                else
                        ratr_bitmap &= 0x0f0ff0ff;
                break;
        }
-       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, "ratr_bitmap :%x\n",
-                ratr_bitmap);
-       *(u32 *)&rate_mask = ((ratr_bitmap & 0x0fffffff) |
-                                     ratr_index << 28);
+       sta_entry->ratr_index = ratr_index;
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "ratr_bitmap :%x\n", ratr_bitmap);
+       *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+                                    (ratr_index << 28);
        rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
        RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
                 "Rate_index:%x, ratr_val:%x, %5phC\n",
                 ratr_index, ratr_bitmap, rate_mask);
-       rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+       memcpy(rtlpriv->rate_mask, rate_mask, 5);
+       /* rtl92c_fill_h2c_cmd() does USB I/O and will result in a
+        * "scheduled while atomic" if called directly */
+       schedule_work(&rtlpriv->works.fill_h2c_cmd);
+
+       if (macid != 0)
+               sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
+                                struct ieee80211_sta *sta,
+                                u8 rssi_level)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->dm.useramask)
+               rtl92cu_update_hal_rate_mask(hw, sta, rssi_level);
+       else
+               rtl92cu_update_hal_rate_table(hw, sta);
 }
 
 void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw)
index f41a3aa4a26f3a90003a4aa0781e6fb041ef61cd..8e3ec1e25644688c469a38f2e057bbf90a6558cb 100644 (file)
@@ -98,10 +98,6 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw,
                                   u32 add_msr, u32 rm_msr);
 void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
 void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
-                                  struct ieee80211_sta *sta,
-                                  u8 rssi_level);
-void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
 
 void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw);
 bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid);
index 85b6bdb163c0faa04103f03d87a05900d850c270..da4f587199ee5537cd20b0f62a326fd8157afb9a 100644 (file)
@@ -289,14 +289,30 @@ void rtl92c_set_key(struct ieee80211_hw *hw, u32 key_index,
                                macaddr = cam_const_broad;
                                entry_id = key_index;
                        } else {
+                               if (mac->opmode == NL80211_IFTYPE_AP ||
+                                   mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+                                       entry_id = rtl_cam_get_free_entry(hw,
+                                                                p_macaddr);
+                                       if (entry_id >=  TOTAL_CAM_ENTRY) {
+                                               RT_TRACE(rtlpriv, COMP_SEC,
+                                                        DBG_EMERG,
+                                                        "Can not find free hw security cam entry\n");
+                                               return;
+                                       }
+                               } else {
+                                       entry_id = CAM_PAIRWISE_KEY_POSITION;
+                               }
+
                                key_index = PAIRWISE_KEYIDX;
-                               entry_id = CAM_PAIRWISE_KEY_POSITION;
                                is_pairwise = true;
                        }
                }
                if (rtlpriv->sec.key_len[key_index] == 0) {
                        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
                                 "delete one entry\n");
+                       if (mac->opmode == NL80211_IFTYPE_AP ||
+                           mac->opmode == NL80211_IFTYPE_MESH_POINT)
+                               rtl_cam_del_entry(hw, p_macaddr);
                        rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
                } else {
                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
index 23d640a4debdd7c1d336c9e2f57ab51fbe06fd5e..826f085c29dd5d9155ff0ab1e4ea2a8b2832f70c 100644 (file)
@@ -106,8 +106,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
        .update_interrupt_mask = rtl92cu_update_interrupt_mask,
        .get_hw_reg = rtl92cu_get_hw_reg,
        .set_hw_reg = rtl92cu_set_hw_reg,
-       .update_rate_tbl = rtl92cu_update_hal_rate_table,
-       .update_rate_mask = rtl92cu_update_hal_rate_mask,
+       .update_rate_tbl = rtl92cu_update_hal_rate_tbl,
        .fill_tx_desc = rtl92cu_tx_fill_desc,
        .fill_fake_txdesc = rtl92cu_fill_fake_txdesc,
        .fill_tx_cmddesc = rtl92cu_tx_fill_cmddesc,
@@ -137,6 +136,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
        .phy_lc_calibrate = _rtl92cu_phy_lc_calibrate,
        .phy_set_bw_mode_callback = rtl92cu_phy_set_bw_mode_callback,
        .dm_dynamic_txpower = rtl92cu_dm_dynamic_txpower,
+       .fill_h2c_cmd = rtl92c_fill_h2c_cmd,
 };
 
 static struct rtl_mod_params rtl92cu_mod_params = {
@@ -349,6 +349,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/
        {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
        {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
+       {RTL_USB_DEVICE(0x0846, 0xf001, rtl92cu_hal_cfg)}, /*On Netwrks N300MA*/
        {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
        {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/
        {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/
index a1310abd0d54605e6bbd1a1cc9f9200bc3ecbe43..262e1e4c6e5b007065ed2e834e139446566bde6f 100644 (file)
@@ -49,5 +49,8 @@ bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
 u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
                            enum radio_path rfpath, u32 regaddr, u32 bitmask);
 void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+void rtl92cu_update_hal_rate_tbl(struct ieee80211_hw *hw,
+                                struct ieee80211_sta *sta,
+                                u8 rssi_level);
 
 #endif
index 19a765532603b06d4fa647a4b6ebb1651ae77f03..47875ba09ff8128d22375514ff601dbbf1f6af59 100644 (file)
@@ -842,7 +842,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
        long val_y, ele_c = 0;
        u8 ofdm_index[2];
        s8 cck_index = 0;
-       u8 ofdm_index_old[2];
+       u8 ofdm_index_old[2] = {0, 0};
        s8 cck_index_old = 0;
        u8 index;
        int i;
index 76732b0cd221f13d937297f8fd1e4c08fd0c2d89..a3532e0778710ff5975a3c3fec4e21299e45e301 100644 (file)
@@ -824,6 +824,7 @@ static void rtl_usb_stop(struct ieee80211_hw *hw)
 
        /* should after adapter start and interrupt enable. */
        set_hal_stop(rtlhal);
+       cancel_work_sync(&rtlpriv->works.fill_h2c_cmd);
        /* Enable software */
        SET_USB_STOP(rtlusb);
        rtl_usb_deinit(hw);
@@ -1026,6 +1027,16 @@ static bool rtl_usb_tx_chk_waitq_insert(struct ieee80211_hw *hw,
        return false;
 }
 
+static void rtl_fill_h2c_cmd_work_callback(struct work_struct *work)
+{
+       struct rtl_works *rtlworks =
+           container_of(work, struct rtl_works, fill_h2c_cmd);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->cfg->ops->fill_h2c_cmd(hw, H2C_RA_MASK, 5, rtlpriv->rate_mask);
+}
+
 static struct rtl_intf_ops rtl_usb_ops = {
        .adapter_start = rtl_usb_start,
        .adapter_stop = rtl_usb_stop,
@@ -1057,6 +1068,8 @@ int rtl_usb_probe(struct usb_interface *intf,
 
        /* this spin lock must be initialized early */
        spin_lock_init(&rtlpriv->locks.usb_lock);
+       INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
+                 rtl_fill_h2c_cmd_work_callback);
 
        rtlpriv->usb_data_index = 0;
        init_completion(&rtlpriv->firmware_loading_complete);
index 44328baa63898750ac957a6275de09ed7290f0f7..cc03e7c87cbe739c9d762a6462b1b0b6f21e1795 100644 (file)
@@ -1736,6 +1736,8 @@ struct rtl_hal_ops {
        void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw,
                                             bool mstate);
        void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
+       void (*fill_h2c_cmd) (struct ieee80211_hw *hw, u8 element_id,
+                             u32 cmd_len, u8 *p_cmdbuffer);
 };
 
 struct rtl_intf_ops {
@@ -1869,6 +1871,7 @@ struct rtl_works {
        struct delayed_work fwevt_wq;
 
        struct work_struct lps_change_work;
+       struct work_struct fill_h2c_cmd;
 };
 
 struct rtl_debug {
@@ -2048,6 +2051,7 @@ struct rtl_priv {
                };
        };
        bool enter_ps;  /* true when entering PS */
+       u8 rate_mask[5];
 
        /*This must be the last item so
           that it points to the data allocated
index affdb3ec6225a39b7343babcf4633cd47990b90e..4a0bbb13806bd6fd61266c729f4a433d110ac838 100644 (file)
@@ -310,7 +310,7 @@ static void wl12xx_adjust_channels(struct wl1271_cmd_sched_scan_config *cmd,
        memcpy(cmd->channels_2, cmd_channels->channels_2,
               sizeof(cmd->channels_2));
        memcpy(cmd->channels_5, cmd_channels->channels_5,
-              sizeof(cmd->channels_2));
+              sizeof(cmd->channels_5));
        /* channels_4 are not supported, so no need to copy them */
 }
 
index 222d03540200498a9400c9dc867159780bdf9311..9e5484a7366704b55ff360ae2c0b86ac12eb2d6d 100644 (file)
 #define WL127X_IFTYPE_SR_VER   3
 #define WL127X_MAJOR_SR_VER    10
 #define WL127X_SUBTYPE_SR_VER  WLCORE_FW_VER_IGNORE
-#define WL127X_MINOR_SR_VER    115
+#define WL127X_MINOR_SR_VER    133
 /* minimum multi-role FW version for wl127x */
 #define WL127X_IFTYPE_MR_VER   5
 #define WL127X_MAJOR_MR_VER    7
 #define WL127X_SUBTYPE_MR_VER  WLCORE_FW_VER_IGNORE
-#define WL127X_MINOR_MR_VER    115
+#define WL127X_MINOR_MR_VER    42
 
 /* FW chip version for wl128x */
 #define WL128X_CHIP_VER                7
@@ -49,7 +49,7 @@
 #define WL128X_IFTYPE_SR_VER   3
 #define WL128X_MAJOR_SR_VER    10
 #define WL128X_SUBTYPE_SR_VER  WLCORE_FW_VER_IGNORE
-#define WL128X_MINOR_SR_VER    115
+#define WL128X_MINOR_SR_VER    133
 /* minimum multi-role FW version for wl128x */
 #define WL128X_IFTYPE_MR_VER   5
 #define WL128X_MAJOR_MR_VER    7
index 09d944505ac0f54f31125ede75d92ef74cd15cea..2b642f8c9266ef21321f8276e6ccbd9a719170af 100644 (file)
@@ -34,7 +34,7 @@ static void wl18xx_adjust_channels(struct wl18xx_cmd_scan_params *cmd,
        memcpy(cmd->channels_2, cmd_channels->channels_2,
               sizeof(cmd->channels_2));
        memcpy(cmd->channels_5, cmd_channels->channels_5,
-              sizeof(cmd->channels_2));
+              sizeof(cmd->channels_5));
        /* channels_4 are not supported, so no need to copy them */
 }
 
index 953111a502ee83a0b8834e35cff965c0787666c5..796928ba875fda2aa75e0c2d809429251408a89b 100644 (file)
@@ -6018,6 +6018,15 @@ int wlcore_free_hw(struct wl1271 *wl)
 }
 EXPORT_SYMBOL_GPL(wlcore_free_hw);
 
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support wlcore_wowlan_support = {
+       .flags = WIPHY_WOWLAN_ANY,
+       .n_patterns = WL1271_MAX_RX_FILTERS,
+       .pattern_min_len = 1,
+       .pattern_max_len = WL1271_RX_FILTER_MAX_PATTERN_SIZE,
+};
+#endif
+
 static void wlcore_nvs_cb(const struct firmware *fw, void *context)
 {
        struct wl1271 *wl = context;
@@ -6071,14 +6080,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
        if (!ret) {
                wl->irq_wake_enabled = true;
                device_init_wakeup(wl->dev, 1);
-               if (pdata->pwr_in_suspend) {
-                       wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
-                       wl->hw->wiphy->wowlan.n_patterns =
-                               WL1271_MAX_RX_FILTERS;
-                       wl->hw->wiphy->wowlan.pattern_min_len = 1;
-                       wl->hw->wiphy->wowlan.pattern_max_len =
-                               WL1271_RX_FILTER_MAX_PATTERN_SIZE;
-               }
+               if (pdata->pwr_in_suspend)
+                       wl->hw->wiphy->wowlan = &wlcore_wowlan_support;
        }
 #endif
        disable_irq(wl->irq);
index 4775d4e61b881de43d93f1643b462e47e6cc52a4..74a852e4e41f0e11fbc8c891513648af6fcf9457 100644 (file)
@@ -28,7 +28,7 @@ config NFC_WILINK
 
 config NFC_MEI_PHY
        tristate "MEI bus NFC device support"
-       depends on INTEL_MEI_BUS_NFC && NFC_HCI
+       depends on INTEL_MEI && NFC_HCI
        help
          This adds support to use an mei bus nfc device. Select this if you
          will use an HCI NFC driver for an NFC chip connected behind an
index b8f8abc422f0f929d1b93e1500c5a595e2deea46..1201bdbfb7918175bc22ae2b1741174b7fbe977c 100644 (file)
@@ -64,6 +64,15 @@ int nfc_mei_phy_enable(void *phy_id)
                 return r;
        }
 
+       r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
+       if (r) {
+               pr_err("MEY_PHY: Event cb registration failed\n");
+               mei_cl_disable_device(phy->device);
+               phy->powered = 0;
+
+               return r;
+       }
+
        phy->powered = 1;
 
        return 0;
index 1ad044dce7b60acfa686d72d842670d64bd02efb..cdf1bc53b257f6ae34e3f2148de97b47f53521b7 100644 (file)
@@ -43,24 +43,16 @@ static int microread_mei_probe(struct mei_cl_device *device,
                return -ENOMEM;
        }
 
-       r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
-       if (r) {
-               pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
-               goto err_out;
-       }
-
        r = microread_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
                            MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
                            &phy->hdev);
-       if (r < 0)
-               goto err_out;
-
-       return 0;
+       if (r < 0) {
+               nfc_mei_phy_free(phy);
 
-err_out:
-       nfc_mei_phy_free(phy);
+               return r;
+       }
 
-       return r;
+       return 0;
 }
 
 static int microread_mei_remove(struct mei_cl_device *device)
@@ -71,8 +63,6 @@ static int microread_mei_remove(struct mei_cl_device *device)
 
        microread_remove(phy->hdev);
 
-       nfc_mei_phy_disable(phy);
-
        nfc_mei_phy_free(phy);
 
        return 0;
index 1eb48848a35ae0bc22683991d62537d67d33ba3f..b5d3d18179eb1da92d35700a8f06fd91ad6a7666 100644 (file)
@@ -43,24 +43,16 @@ static int pn544_mei_probe(struct mei_cl_device *device,
                return -ENOMEM;
        }
 
-       r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
-       if (r) {
-               pr_err(PN544_DRIVER_NAME ": event cb registration failed\n");
-               goto err_out;
-       }
-
        r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
                            MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
                            &phy->hdev);
-       if (r < 0)
-               goto err_out;
-
-       return 0;
+       if (r < 0) {
+               nfc_mei_phy_free(phy);
 
-err_out:
-       nfc_mei_phy_free(phy);
+               return r;
+       }
 
-       return r;
+       return 0;
 }
 
 static int pn544_mei_remove(struct mei_cl_device *device)
@@ -71,8 +63,6 @@ static int pn544_mei_remove(struct mei_cl_device *device)
 
        pn544_hci_remove(phy->hdev);
 
-       nfc_mei_phy_disable(phy);
-
        nfc_mei_phy_free(phy);
 
        return 0;
index f14a98a79c9d8b276d3407050d08f00b87c9c6be..2e34db82a6434d35d7f8c1b7b6b8385e08158bb2 100644 (file)
@@ -134,7 +134,10 @@ struct bcma_host_ops {
 #define BCMA_CORE_I2S                  0x834
 #define BCMA_CORE_SDR_DDR1_MEM_CTL     0x835   /* SDR/DDR1 memory controller core */
 #define BCMA_CORE_SHIM                 0x837   /* SHIM component in ubus/6362 */
-#define BCMA_CORE_ARM_CR4              0x83e
+#define BCMA_CORE_PHY_AC               0x83B
+#define BCMA_CORE_PCIE2                        0x83C   /* PCI Express Gen2 */
+#define BCMA_CORE_USB30_DEV            0x83D
+#define BCMA_CORE_ARM_CR4              0x83E
 #define BCMA_CORE_DEFAULT              0xFFF
 
 #define BCMA_MAX_NR_CORES              16
diff --git a/include/linux/cw1200_platform.h b/include/linux/cw1200_platform.h
deleted file mode 100644 (file)
index c168fa5..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef CW1200_PLAT_H_INCLUDED
-#define CW1200_PLAT_H_INCLUDED
-
-struct cw1200_platform_data_spi {
-       u8 spi_bits_per_word;           /* REQUIRED */
-       u16 ref_clk;                    /* REQUIRED (in KHz) */
-
-       /* All others are optional */
-       bool have_5ghz;
-       const struct resource *reset;   /* GPIO to RSTn signal */
-       const struct resource *powerup; /* GPIO to POWERUP signal */
-       int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata,
-                         bool enable); /* Control 3v3 / 1v8 supply */
-       int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata,
-                       bool enable); /* Control CLK32K */
-       const u8 *macaddr;  /* if NULL, use cw1200_mac_template module parameter */
-       const char *sdd_file;  /* if NULL, will use default for detected hw type */
-};
-
-struct cw1200_platform_data_sdio {
-       u16 ref_clk;                    /* REQUIRED (in KHz) */
-
-       /* All others are optional */
-       const struct resource *irq;     /* if using GPIO for IRQ */
-       bool have_5ghz;
-       bool no_nptb;                   /* SDIO hardware does not support non-power-of-2-blocksizes */
-       const struct resource *reset;   /* GPIO to RSTn signal */
-       const struct resource *powerup; /* GPIO to POWERUP signal */
-       int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata,
-                         bool enable); /* Control 3v3 / 1v8 supply */
-       int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata,
-                       bool enable); /* Control CLK32K */
-       const u8 *macaddr;  /* if NULL, use cw1200_mac_template module parameter */
-       const char *sdd_file;  /* if NULL, will use default for detected hw type */
-};
-
-const void *cw1200_get_platform_data(void);
-
-#endif /* CW1200_PLAT_H_INCLUDED */
index d826e5a84af09a2c3986c8b3e33d0fc19597b86a..b0dc87a2a376e2583d2d28363a0cdd13f859536c 100644 (file)
@@ -146,6 +146,7 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
 #define IEEE80211_MAX_RTS_THRESHOLD    2353
 #define IEEE80211_MAX_AID              2007
 #define IEEE80211_MAX_TIM_LEN          251
+#define IEEE80211_MAX_MESH_PEERINGS    63
 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
    6.2.1.1.2.
 
diff --git a/include/linux/platform_data/net-cw1200.h b/include/linux/platform_data/net-cw1200.h
new file mode 100644 (file)
index 0000000..c6fbc3c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CW1200_PLAT_H_INCLUDED
+#define CW1200_PLAT_H_INCLUDED
+
+struct cw1200_platform_data_spi {
+       u8 spi_bits_per_word;           /* REQUIRED */
+       u16 ref_clk;                    /* REQUIRED (in KHz) */
+
+       /* All others are optional */
+       bool have_5ghz;
+       int reset;                     /* GPIO to RSTn signal (0 disables) */
+       int powerup;                   /* GPIO to POWERUP signal (0 disables) */
+       int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata,
+                         bool enable); /* Control 3v3 / 1v8 supply */
+       int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata,
+                       bool enable); /* Control CLK32K */
+       const u8 *macaddr;  /* if NULL, use cw1200_mac_template module parameter */
+       const char *sdd_file;  /* if NULL, will use default for detected hw type */
+};
+
+struct cw1200_platform_data_sdio {
+       u16 ref_clk;                    /* REQUIRED (in KHz) */
+
+       /* All others are optional */
+       bool have_5ghz;
+       bool no_nptb;       /* SDIO hardware does not support non-power-of-2-blocksizes */
+       int reset;          /* GPIO to RSTn signal (0 disables) */
+       int powerup;        /* GPIO to POWERUP signal (0 disables) */
+       int irq;            /* IRQ line or 0 to use SDIO IRQ */
+       int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata,
+                         bool enable); /* Control 3v3 / 1v8 supply */
+       int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata,
+                       bool enable); /* Control CLK32K */
+       const u8 *macaddr;  /* if NULL, use cw1200_mac_template module parameter */
+       const char *sdd_file;  /* if NULL, will use default for detected hw type */
+};
+
+
+/* An example of SPI support in your board setup file:
+
+   static struct cw1200_platform_data_spi cw1200_platform_data = {
+       .ref_clk = 38400,
+       .spi_bits_per_word = 16,
+       .reset = GPIO_RF_RESET,
+       .powerup = GPIO_RF_POWERUP,
+       .macaddr = wifi_mac_addr,
+       .sdd_file = "sdd_sagrad_1091_1098.bin",
+  };
+  static struct spi_board_info myboard_spi_devices[] __initdata = {
+       {
+               .modalias = "cw1200_wlan_spi",
+               .max_speed_hz = 52000000,
+               .bus_num = 0,
+               .irq = WIFI_IRQ,
+               .platform_data = &cw1200_platform_data,
+               .chip_select = 0,
+       },
+  };
+
+ */
+
+/* An example of SDIO support in your board setup file:
+
+  static struct cw1200_platform_data_sdio my_cw1200_platform_data = {
+       .ref_clk = 38400,
+       .have_5ghz = false,
+       .sdd_file = "sdd_myplatform.bin",
+  };
+  cw1200_sdio_set_platform_data(&my_cw1200_platform_data);
+
+ */
+
+void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata);
+
+#endif /* CW1200_PLAT_H_INCLUDED */
index 35a57cd1704c30576a76fb9758855f6ba333abcc..7cb6d360d14702f04bebc0a2ad88a9466b33a607 100644 (file)
@@ -1117,6 +1117,7 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event);
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
 int mgmt_index_added(struct hci_dev *hdev);
 int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_set_powered_failed(struct hci_dev *hdev, int err);
 int mgmt_powered(struct hci_dev *hdev, u8 powered);
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
 int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
index 22980a7c38730f53305b181e338dc29009cf62d6..9944c3e68c5d1dd57f40f0b72012a0fbfcdf1a4b 100644 (file)
@@ -42,6 +42,7 @@
 #define MGMT_STATUS_NOT_POWERED                0x0f
 #define MGMT_STATUS_CANCELLED          0x10
 #define MGMT_STATUS_INVALID_INDEX      0x11
+#define MGMT_STATUS_RFKILLED           0x12
 
 struct mgmt_hdr {
        __le16  opcode;
index b3b076a46d5074ce9d4868968d2be1455b339c6f..6a43c34ce96f17e6ff2fceef2a8ffa6f69f8b79b 100644 (file)
@@ -961,6 +961,7 @@ struct station_info {
  * @MONITOR_FLAG_CONTROL: pass control frames
  * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
  * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
+ * @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
  */
 enum monitor_flags {
        MONITOR_FLAG_FCSFAIL            = 1<<NL80211_MNTR_FLAG_FCSFAIL,
@@ -968,6 +969,7 @@ enum monitor_flags {
        MONITOR_FLAG_CONTROL            = 1<<NL80211_MNTR_FLAG_CONTROL,
        MONITOR_FLAG_OTHER_BSS          = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
        MONITOR_FLAG_COOK_FRAMES        = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
+       MONITOR_FLAG_ACTIVE             = 1<<NL80211_MNTR_FLAG_ACTIVE,
 };
 
 /**
@@ -1122,6 +1124,9 @@ struct bss_parameters {
  *     setting for new peer links.
  * @dot11MeshAwakeWindowDuration: The duration in TUs the STA will remain awake
  *     after transmitting its beacon.
+ * @plink_timeout: If no tx activity is seen from a STA we've established
+ *     peering with for longer than this time (in seconds), then remove it
+ *     from the STA's list of peers.  Default is 30 minutes.
  */
 struct mesh_config {
        u16 dot11MeshRetryTimeout;
@@ -1151,6 +1156,7 @@ struct mesh_config {
        u16 dot11MeshHWMPconfirmationInterval;
        enum nl80211_mesh_power_mode power_mode;
        u16 dot11MeshAwakeWindowDuration;
+       u32 plink_timeout;
 };
 
 /**
@@ -1170,6 +1176,7 @@ struct mesh_config {
  * @dtim_period: DTIM period to use
  * @beacon_interval: beacon interval to use
  * @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
+ * @basic_rates: basic rates to use when creating the mesh
  *
  * These parameters are fixed when the mesh is created.
  */
@@ -1189,6 +1196,7 @@ struct mesh_setup {
        u8 dtim_period;
        u16 beacon_interval;
        int mcast_rate[IEEE80211_NUM_BANDS];
+       u32 basic_rates;
 };
 
 /**
@@ -2652,7 +2660,7 @@ struct wiphy {
        u32 hw_version;
 
 #ifdef CONFIG_PM
-       struct wiphy_wowlan_support wowlan;
+       const struct wiphy_wowlan_support *wowlan;
        struct cfg80211_wowlan *wowlan_config;
 #endif
 
@@ -2851,7 +2859,7 @@ struct cfg80211_cached_keys;
  * @current_bss: (private) Used by the internal configuration code
  * @channel: (private) Used by the internal configuration code to track
  *     the user-set AP, monitor and WDS channel
- * @preset_chan: (private) Used by the internal configuration code to
+ * @preset_chandef: (private) Used by the internal configuration code to
  *     track the channel to be used for AP later
  * @bssid: (private) Used by the internal configuration code
  * @ssid: (private) Used by the internal configuration code
@@ -2867,13 +2875,21 @@ struct cfg80211_cached_keys;
  * @mgmt_registrations_lock: lock for the list
  * @mtx: mutex used to lock data in this struct, may be used by drivers
  *     and some API functions require it held
- * @cleanup_work: work struct used for cleanup that can't be done directly
  * @beacon_interval: beacon interval used on this device for transmitting
  *     beacons, 0 when not valid
  * @address: The address for this device, valid only if @netdev is %NULL
  * @p2p_started: true if this is a P2P Device that has been started
  * @cac_started: true if DFS channel availability check has been started
  * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
+ * @ps: powersave mode is enabled
+ * @ps_timeout: dynamic powersave timeout
+ * @ap_unexpected_nlportid: (private) netlink port ID of application
+ *     registered for unexpected class 3 frames (AP mode)
+ * @conn: (private) cfg80211 software SME connection state machine data
+ * @connect_keys: (private) keys to set after connection is established
+ * @ibss_fixed: (private) IBSS is using fixed BSSID
+ * @event_list: (private) list for internal event processing
+ * @event_lock: (private) lock for event list
  */
 struct wireless_dev {
        struct wiphy *wiphy;
@@ -2897,11 +2913,6 @@ struct wireless_dev {
        /* currently used for IBSS and SME - might be rearranged later */
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        u8 ssid_len, mesh_id_len, mesh_id_up_len;
-       enum {
-               CFG80211_SME_IDLE,
-               CFG80211_SME_CONNECTING,
-               CFG80211_SME_CONNECTED,
-       } sme_state;
        struct cfg80211_conn *conn;
        struct cfg80211_cached_keys *connect_keys;
 
@@ -3431,59 +3442,66 @@ void cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
 void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
 
 /**
- * cfg80211_send_rx_auth - notification of processed authentication
+ * cfg80211_rx_mlme_mgmt - notification of processed MLME management frame
  * @dev: network device
  * @buf: authentication frame (header + body)
  * @len: length of the frame data
  *
- * This function is called whenever an authentication has been processed in
- * station mode. The driver is required to call either this function or
- * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth()
- * call. This function may sleep. The caller must hold the corresponding wdev's
- * mutex.
+ * This function is called whenever an authentication, disassociation or
+ * deauthentication frame has been received and processed in station mode.
+ * After being asked to authenticate via cfg80211_ops::auth() the driver must
+ * call either this function or cfg80211_auth_timeout().
+ * After being asked to associate via cfg80211_ops::assoc() the driver must
+ * call either this function or cfg80211_auth_timeout().
+ * While connected, the driver must calls this for received and processed
+ * disassociation and deauthentication frames. If the frame couldn't be used
+ * because it was unprotected, the driver must call the function
+ * cfg80211_rx_unprot_mlme_mgmt() instead.
+ *
+ * This function may sleep. The caller must hold the corresponding wdev's mutex.
  */
-void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
 
 /**
- * cfg80211_send_auth_timeout - notification of timed out authentication
+ * cfg80211_auth_timeout - notification of timed out authentication
  * @dev: network device
  * @addr: The MAC address of the device with which the authentication timed out
  *
  * This function may sleep. The caller must hold the corresponding wdev's
  * mutex.
  */
-void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
+void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
 
 /**
- * cfg80211_send_rx_assoc - notification of processed association
+ * cfg80211_rx_assoc_resp - notification of processed association response
  * @dev: network device
- * @bss: the BSS struct association was requested for, the struct reference
- *     is owned by cfg80211 after this call
- * @buf: (re)association response frame (header + body)
+ * @bss: the BSS that association was requested with, ownership of the pointer
+ *     moves to cfg80211 in this call
+ * @buf: authentication frame (header + body)
  * @len: length of the frame data
  *
- * This function is called whenever a (re)association response has been
- * processed in station mode. The driver is required to call either this
- * function or cfg80211_send_assoc_timeout() to indicate the result of
- * cfg80211_ops::assoc() call. This function may sleep. The caller must hold
- * the corresponding wdev's mutex.
+ * After being asked to associate via cfg80211_ops::assoc() the driver must
+ * call either this function or cfg80211_auth_timeout().
+ *
+ * This function may sleep. The caller must hold the corresponding wdev's mutex.
  */
-void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
+void cfg80211_rx_assoc_resp(struct net_device *dev,
+                           struct cfg80211_bss *bss,
                            const u8 *buf, size_t len);
 
 /**
- * cfg80211_send_assoc_timeout - notification of timed out association
+ * cfg80211_assoc_timeout - notification of timed out association
  * @dev: network device
  * @addr: The MAC address of the device with which the association timed out
  *
  * This function may sleep. The caller must hold the corresponding wdev's mutex.
  */
-void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
+void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr);
 
 /**
- * cfg80211_send_deauth - notification of processed deauthentication
+ * cfg80211_tx_mlme_mgmt - notification of transmitted deauth/disassoc frame
  * @dev: network device
- * @buf: deauthentication frame (header + body)
+ * @buf: 802.11 frame (header + body)
  * @len: length of the frame data
  *
  * This function is called whenever deauthentication has been processed in
@@ -3491,46 +3509,20 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
  * locally generated ones. This function may sleep. The caller must hold the
  * corresponding wdev's mutex.
  */
-void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len);
-
-/**
- * cfg80211_send_disassoc - notification of processed disassociation
- * @dev: network device
- * @buf: disassociation response frame (header + body)
- * @len: length of the frame data
- *
- * This function is called whenever disassociation has been processed in
- * station mode. This includes both received disassociation frames and locally
- * generated ones. This function may sleep. The caller must hold the
- * corresponding wdev's mutex.
- */
-void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len);
 
 /**
- * cfg80211_send_unprot_deauth - notification of unprotected deauthentication
+ * cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame
  * @dev: network device
  * @buf: deauthentication frame (header + body)
  * @len: length of the frame data
  *
- * This function is called whenever a received Deauthentication frame has been
- * dropped in station mode because of MFP being used but the Deauthentication
- * frame was not protected. This function may sleep.
- */
-void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
-                                size_t len);
-
-/**
- * cfg80211_send_unprot_disassoc - notification of unprotected disassociation
- * @dev: network device
- * @buf: disassociation frame (header + body)
- * @len: length of the frame data
- *
- * This function is called whenever a received Disassociation frame has been
- * dropped in station mode because of MFP being used but the Disassociation
+ * This function is called whenever a received deauthentication or dissassoc
+ * frame has been dropped in station mode because of MFP being used but the
  * frame was not protected. This function may sleep.
  */
-void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
-                                  size_t len);
+void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev,
+                                 const u8 *buf, size_t len);
 
 /**
  * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
index 1f0014bd4d8724082bcbff4838dd29e442773270..a405a7a9775cb0ad96f10cc0b683ac739de363cc 100644 (file)
@@ -217,8 +217,8 @@ struct ieee80211_chanctx_conf {
  * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
  * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
  *     changed (currently only in P2P client mode, GO mode will be later)
- * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when
- *     it becomes valid, managed mode only)
+ * @BSS_CHANGED_BEACON_INFO: Data from the AP's beacon became available:
+ *     currently dtim_period only is under consideration.
  * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed,
  *     note that this is only called when it changes after the channel
  *     context had been assigned.
@@ -244,7 +244,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_PS                  = 1<<17,
        BSS_CHANGED_TXPOWER             = 1<<18,
        BSS_CHANGED_P2P_PS              = 1<<19,
-       BSS_CHANGED_DTIM_PERIOD         = 1<<20,
+       BSS_CHANGED_BEACON_INFO         = 1<<20,
        BSS_CHANGED_BANDWIDTH           = 1<<21,
 
        /* when adding here, make sure to change ieee80211_reconfig */
@@ -288,7 +288,7 @@ enum ieee80211_rssi_event {
  *     IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
  * @dtim_period: num of beacons before the next DTIM, for beaconing,
  *     valid in station mode only if after the driver was notified
- *     with the %BSS_CHANGED_DTIM_PERIOD flag, will be non-zero then.
+ *     with the %BSS_CHANGED_BEACON_INFO flag, will be non-zero then.
  * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old
  *     as it may have been received during scanning long ago). If the
  *     HW flag %IEEE80211_HW_TIMING_BEACON_ONLY is set, then this can
@@ -460,6 +460,8 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
  *     would be fragmented by size (this is optional, only used for
  *     monitor injection).
+ * @IEEE80211_TX_CTL_PS_RESPONSE: This frame is a response to a poll
+ *     frame (PS-Poll or uAPSD).
  *
  * Note: If you have to add new flags to the enumeration, then don't
  *      forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -495,6 +497,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_STATUS_EOSP                = BIT(28),
        IEEE80211_TX_CTL_USE_MINRATE            = BIT(29),
        IEEE80211_TX_CTL_DONTFRAG               = BIT(30),
+       IEEE80211_TX_CTL_PS_RESPONSE            = BIT(31),
 };
 
 #define IEEE80211_TX_CTL_STBC_SHIFT            23
index 32b060ea526649ec76d26dd875b7ff7f1a476de5..ca6facf4df0cb063d8bdf4708b8a26526eacfa9d 100644 (file)
@@ -2428,6 +2428,8 @@ enum nl80211_survey_info {
  * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
  * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
  *     overrides all other flags.
+ * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
+ *     and ACK incoming unicast packets.
  *
  * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
  * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags {
        NL80211_MNTR_FLAG_CONTROL,
        NL80211_MNTR_FLAG_OTHER_BSS,
        NL80211_MNTR_FLAG_COOK_FRAMES,
+       NL80211_MNTR_FLAG_ACTIVE,
 
        /* keep last */
        __NL80211_MNTR_FLAG_AFTER_LAST,
@@ -2574,6 +2577,10 @@ enum nl80211_mesh_power_mode {
  *
  * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs)
  *
+ * @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
+ *     established peering with for longer than this time (in seconds), then
+ *     remove it from the STA's list of peers.  Default is 30 minutes.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -2605,6 +2612,7 @@ enum nl80211_meshconf_params {
        NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL,
        NL80211_MESHCONF_POWER_MODE,
        NL80211_MESHCONF_AWAKE_WINDOW,
+       NL80211_MESHCONF_PLINK_TIMEOUT,
 
        /* keep last */
        __NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -3576,6 +3584,10 @@ enum nl80211_ap_sme_features {
  *     Peering Management entity which may be implemented by registering for
  *     beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
  *     still generated by the driver.
+ * @NL80211_FEATURE_ACTIVE_MONITOR: This driver supports an active monitor
+ *     interface. An active monitor interface behaves like a normal monitor
+ *     interface, but gets added to the driver. It ensures that incoming
+ *     unicast packets directed at the configured interface address get ACKed.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3595,6 +3607,7 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_ADVERTISE_CHAN_LIMITS           = 1 << 14,
        NL80211_FEATURE_FULL_AP_CLIENT_STATE            = 1 << 15,
        NL80211_FEATURE_USERSPACE_MPM                   = 1 << 16,
+       NL80211_FEATURE_ACTIVE_MONITOR                  = 1 << 17,
 };
 
 /**
index 33843c5c49398f0e2a373de8919cde67a840451a..d817c932d634e6609081dbf8f492cf04463b867d 100644 (file)
@@ -1555,11 +1555,15 @@ static const struct rfkill_ops hci_rfkill_ops = {
 static void hci_power_on(struct work_struct *work)
 {
        struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
+       int err;
 
        BT_DBG("%s", hdev->name);
 
-       if (hci_dev_open(hdev->id) < 0)
+       err = hci_dev_open(hdev->id);
+       if (err < 0) {
+               mgmt_set_powered_failed(hdev, err);
                return;
+       }
 
        if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
index a76d1ac0321b40f48f6de231f31ff14e2af363df..24bee07ee4ce1a54a86f5d5bd535b13bd1e42c02 100644 (file)
@@ -3677,10 +3677,14 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
 }
 
 static inline int l2cap_command_rej(struct l2cap_conn *conn,
-                                   struct l2cap_cmd_hdr *cmd, u8 *data)
+                                   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                   u8 *data)
 {
        struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
 
+       if (cmd_len < sizeof(*rej))
+               return -EPROTO;
+
        if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
                return 0;
 
@@ -3829,11 +3833,14 @@ sendresp:
 }
 
 static int l2cap_connect_req(struct l2cap_conn *conn,
-                            struct l2cap_cmd_hdr *cmd, u8 *data)
+                            struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
 {
        struct hci_dev *hdev = conn->hcon->hdev;
        struct hci_conn *hcon = conn->hcon;
 
+       if (cmd_len < sizeof(struct l2cap_conn_req))
+               return -EPROTO;
+
        hci_dev_lock(hdev);
        if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
            !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
@@ -3847,7 +3854,8 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
 }
 
 static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
-                                   struct l2cap_cmd_hdr *cmd, u8 *data)
+                                   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                   u8 *data)
 {
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
        u16 scid, dcid, result, status;
@@ -3855,6 +3863,9 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
        u8 req[128];
        int err;
 
+       if (cmd_len < sizeof(*rsp))
+               return -EPROTO;
+
        scid   = __le16_to_cpu(rsp->scid);
        dcid   = __le16_to_cpu(rsp->dcid);
        result = __le16_to_cpu(rsp->result);
@@ -3952,6 +3963,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
        struct l2cap_chan *chan;
        int len, err = 0;
 
+       if (cmd_len < sizeof(*req))
+               return -EPROTO;
+
        dcid  = __le16_to_cpu(req->dcid);
        flags = __le16_to_cpu(req->flags);
 
@@ -3975,7 +3989,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
 
        /* Reject if config buffer is too small. */
        len = cmd_len - sizeof(*req);
-       if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
+       if (chan->conf_len + len > sizeof(chan->conf_req)) {
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                               l2cap_build_conf_rsp(chan, rsp,
                               L2CAP_CONF_REJECT, flags), rsp);
@@ -4053,14 +4067,18 @@ unlock:
 }
 
 static inline int l2cap_config_rsp(struct l2cap_conn *conn,
-                                  struct l2cap_cmd_hdr *cmd, u8 *data)
+                                  struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                  u8 *data)
 {
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
        struct l2cap_chan *chan;
-       int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
+       int len = cmd_len - sizeof(*rsp);
        int err = 0;
 
+       if (cmd_len < sizeof(*rsp))
+               return -EPROTO;
+
        scid   = __le16_to_cpu(rsp->scid);
        flags  = __le16_to_cpu(rsp->flags);
        result = __le16_to_cpu(rsp->result);
@@ -4161,7 +4179,8 @@ done:
 }
 
 static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
-                                      struct l2cap_cmd_hdr *cmd, u8 *data)
+                                      struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                      u8 *data)
 {
        struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
        struct l2cap_disconn_rsp rsp;
@@ -4169,6 +4188,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
        struct l2cap_chan *chan;
        struct sock *sk;
 
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
        scid = __le16_to_cpu(req->scid);
        dcid = __le16_to_cpu(req->dcid);
 
@@ -4208,12 +4230,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
-                                      struct l2cap_cmd_hdr *cmd, u8 *data)
+                                      struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                      u8 *data)
 {
        struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
        u16 dcid, scid;
        struct l2cap_chan *chan;
 
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
        scid = __le16_to_cpu(rsp->scid);
        dcid = __le16_to_cpu(rsp->dcid);
 
@@ -4243,11 +4269,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_information_req(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u8 *data)
+                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                       u8 *data)
 {
        struct l2cap_info_req *req = (struct l2cap_info_req *) data;
        u16 type;
 
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
        type = __le16_to_cpu(req->type);
 
        BT_DBG("type 0x%4.4x", type);
@@ -4294,11 +4324,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_information_rsp(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u8 *data)
+                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                       u8 *data)
 {
        struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
        u16 type, result;
 
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
        type   = __le16_to_cpu(rsp->type);
        result = __le16_to_cpu(rsp->result);
 
@@ -5164,16 +5198,16 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 
        switch (cmd->code) {
        case L2CAP_COMMAND_REJ:
-               l2cap_command_rej(conn, cmd, data);
+               l2cap_command_rej(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_CONN_REQ:
-               err = l2cap_connect_req(conn, cmd, data);
+               err = l2cap_connect_req(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_CONN_RSP:
        case L2CAP_CREATE_CHAN_RSP:
-               err = l2cap_connect_create_rsp(conn, cmd, data);
+               err = l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_CONF_REQ:
@@ -5181,15 +5215,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_CONF_RSP:
-               err = l2cap_config_rsp(conn, cmd, data);
+               err = l2cap_config_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_DISCONN_REQ:
-               err = l2cap_disconnect_req(conn, cmd, data);
+               err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_DISCONN_RSP:
-               err = l2cap_disconnect_rsp(conn, cmd, data);
+               err = l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_ECHO_REQ:
@@ -5200,11 +5234,11 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_INFO_REQ:
-               err = l2cap_information_req(conn, cmd, data);
+               err = l2cap_information_req(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_INFO_RSP:
-               err = l2cap_information_rsp(conn, cmd, data);
+               err = l2cap_information_rsp(conn, cmd, cmd_len, data);
                break;
 
        case L2CAP_CREATE_CHAN_REQ:
index 35fef22703e9dc3661c88d3adb5b5abc9532c463..f8ecbc70293d1d0c0b82101c4378a4e9ea8be1bd 100644 (file)
@@ -2700,7 +2700,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
                break;
 
        case DISCOV_TYPE_LE:
-               if (!lmp_host_le_capable(hdev)) {
+               if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
                        err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
                                         MGMT_STATUS_NOT_SUPPORTED);
                        mgmt_pending_remove(cmd);
@@ -3418,6 +3418,27 @@ new_settings:
        return err;
 }
 
+int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
+{
+       struct pending_cmd *cmd;
+       u8 status;
+
+       cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+       if (!cmd)
+               return -ENOENT;
+
+       if (err == -ERFKILL)
+               status = MGMT_STATUS_RFKILLED;
+       else
+               status = MGMT_STATUS_FAILED;
+
+       err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
+
+       mgmt_pending_remove(cmd);
+
+       return err;
+}
+
 int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
        struct cmd_lookup match = { NULL, hdev };
index b2296d3857a0f492fca46cd7de02119a194e863f..b5562abdd6e0c84e4a2f52f3175c8046ce70751c 100644 (file)
@@ -770,7 +770,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
 
        BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
 
-       if (!lmp_host_le_capable(hcon->hdev))
+       if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
                return 1;
 
        if (sec_level == BT_SECURITY_LOW)
@@ -851,7 +851,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
        __u8 reason;
        int err = 0;
 
-       if (!lmp_host_le_capable(conn->hcon->hdev)) {
+       if (!test_bit(HCI_LE_ENABLED, &conn->hcon->hdev->dev_flags)) {
                err = -ENOTSUPP;
                reason = SMP_PAIRING_NOTSUPP;
                goto done;
index 232edf78d5a9ff9807e21426cc289ad13191c0b3..64cf294c2b9680329f3925857305ca7843a6281b 100644 (file)
@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                struct ieee80211_local *local = sdata->local;
 
                if (ieee80211_sdata_running(sdata)) {
+                       u32 mask = MONITOR_FLAG_COOK_FRAMES |
+                                  MONITOR_FLAG_ACTIVE;
+
                        /*
-                        * Prohibit MONITOR_FLAG_COOK_FRAMES to be
-                        * changed while the interface is up.
+                        * Prohibit MONITOR_FLAG_COOK_FRAMES and
+                        * MONITOR_FLAG_ACTIVE to be changed while the
+                        * interface is up.
                         * Else we would need to add a lot of cruft
                         * to update everything:
                         *      cooked_mntrs, monitor and all fif_* counters
                         *      reconfigure hardware
                         */
-                       if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
-                           (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                       if ((*flags & mask) != (sdata->u.mntr_flags & mask))
                                return -EBUSY;
 
                        ieee80211_adjust_monitor_flags(sdata, -1);
@@ -1756,6 +1759,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
        /* mcast rate setting in Mesh Node */
        memcpy(sdata->vif.bss_conf.mcast_rate, setup->mcast_rate,
                                                sizeof(setup->mcast_rate));
+       sdata->vif.bss_conf.basic_rates = setup->basic_rates;
 
        sdata->vif.bss_conf.beacon_int = setup->beacon_interval;
        sdata->vif.bss_conf.dtim_period = setup->dtim_period;
@@ -1868,6 +1872,8 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
        if (_chg_mesh_attr(NL80211_MESHCONF_AWAKE_WINDOW, mask))
                conf->dot11MeshAwakeWindowDuration =
                        nconf->dot11MeshAwakeWindowDuration;
+       if (_chg_mesh_attr(NL80211_MESHCONF_PLINK_TIMEOUT, mask))
+               conf->plink_timeout = nconf->plink_timeout;
        ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON);
        return 0;
 }
@@ -2375,7 +2381,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        local->dynamic_ps_forced_timeout = timeout;
 
        /* no change, but if automatic follow powersave */
+       sdata_lock(sdata);
        __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
+       sdata_unlock(sdata);
 
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
@@ -2833,6 +2841,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                return -EOPNOTSUPP;
        }
 
+       /* configurations requiring offchan cannot work if no channel has been
+        * specified
+        */
+       if (need_offchan && !chan)
+               return -EINVAL;
+
        mutex_lock(&local->mtx);
 
        /* Check if the operating channel is the requested channel */
@@ -2842,10 +2856,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                rcu_read_lock();
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
-               if (chanctx_conf)
-                       need_offchan = chan != chanctx_conf->def.chan;
-               else
+               if (chanctx_conf) {
+                       need_offchan = chan && (chan != chanctx_conf->def.chan);
+               } else if (!chan) {
+                       ret = -EINVAL;
+                       rcu_read_unlock();
+                       goto out_unlock;
+               } else {
                        need_offchan = true;
+               }
                rcu_read_unlock();
        }
 
index 169664c122e23cbe80f89016714bdcdfec24dc6e..b931c96a596fb3e92e9effa845ab10f74144dfd1 100644 (file)
@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
 
        if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
                    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
-                    !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))))
+                    !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) &&
+                    !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
                return -EINVAL;
 
        trace_drv_add_interface(local, sdata);
index 9eed6f1d161406a37f0db7fb3ed73ee52dc61f5f..7a6f1a0207ec1dfc6fab981e8d23efd9f867b5b5 100644 (file)
@@ -366,7 +366,7 @@ struct ieee80211_mgd_assoc_data {
        u8 ssid_len;
        u8 supp_rates_len;
        bool wmm, uapsd;
-       bool have_beacon, need_beacon;
+       bool need_beacon;
        bool synced;
        bool timeout_started;
 
@@ -404,6 +404,7 @@ struct ieee80211_if_managed {
 
        bool powersave; /* powersave requested for this iface */
        bool broken_ap; /* AP is broken -- turn off powersave */
+       bool have_beacon;
        u8 dtim_period;
        enum ieee80211_smps_mode req_smps, /* requested smps mode */
                                 driver_smps_mode; /* smps mode request */
index ceef64426a8dbf3aff3edaec827d53ebb9ff0b29..a2a8250e2f845d6441f60e177357900d3d411155 100644 (file)
@@ -159,9 +159,11 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
+static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr,
+                               bool check_dup)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_sub_if_data *iter;
        u64 new, mask, tmp;
        u8 *m;
        int ret = 0;
@@ -179,13 +181,19 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
                ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
                ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
 
+       if (!check_dup)
+               return ret;
 
        mutex_lock(&local->iflist_mtx);
-       list_for_each_entry(sdata, &local->interfaces, list) {
-               if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+       list_for_each_entry(iter, &local->interfaces, list) {
+               if (iter == sdata)
                        continue;
 
-               m = sdata->vif.addr;
+               if (iter->vif.type == NL80211_IFTYPE_MONITOR &&
+                   !(iter->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+                       continue;
+
+               m = iter->vif.addr;
                tmp =   ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
                        ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
                        ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
@@ -204,12 +212,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sockaddr *sa = addr;
+       bool check_dup = true;
        int ret;
 
        if (ieee80211_sdata_running(sdata))
                return -EBUSY;
 
-       ret = ieee80211_verify_mac(sdata->local, sa->sa_data);
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+           !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+               check_dup = false;
+
+       ret = ieee80211_verify_mac(sdata, sa->sa_data, check_dup);
        if (ret)
                return ret;
 
@@ -541,7 +554,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                        break;
                }
 
-               if (local->monitors == 0 && local->open_count == 0) {
+               if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
+                       res = drv_add_interface(local, sdata);
+                       if (res)
+                               goto err_stop;
+               } else if (local->monitors == 0 && local->open_count == 0) {
                        res = ieee80211_add_virtual_monitor(local);
                        if (res)
                                goto err_stop;
@@ -919,7 +936,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                mutex_lock(&local->mtx);
                ieee80211_recalc_idle(local);
                mutex_unlock(&local->mtx);
-               break;
+
+               if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+                       break;
+
+               /* fall through */
        default:
                if (going_down)
                        drv_remove_interface(local, sdata);
@@ -1068,7 +1089,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
        .ndo_start_xmit         = ieee80211_monitor_start_xmit,
        .ndo_set_rx_mode        = ieee80211_set_multicast_list,
        .ndo_change_mtu         = ieee80211_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = ieee80211_change_mac,
        .ndo_select_queue       = ieee80211_monitor_select_queue,
 };
 
@@ -1486,7 +1507,17 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
                        break;
                }
 
+               /*
+                * Pick address of existing interface in case user changed
+                * MAC address manually, default to perm_addr.
+                */
                m = local->hw.wiphy->perm_addr;
+               list_for_each_entry(sdata, &local->interfaces, list) {
+                       if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+                               continue;
+                       m = sdata->vif.addr;
+                       break;
+               }
                start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
                        ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
                        ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
index 1998f147526791485405e4d6f79f55185a114e53..626c83c042d78b74df144c92bf83f0970214e46a 100644 (file)
@@ -686,8 +686,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                return -EINVAL;
 
 #ifdef CONFIG_PM
-       if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) &&
-           (!local->ops->suspend || !local->ops->resume))
+       if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
                return -EINVAL;
 #endif
 
index b3d1fdd463688a8a5c7de6a5df1c670b6d35ba0b..6c33af482df4e876925664a61afd80d6f5456267 100644 (file)
@@ -274,8 +274,7 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
        *pos++ = ifmsh->mesh_auth_id;
        /* Mesh Formation Info - number of neighbors */
        neighbors = atomic_read(&ifmsh->estab_plinks);
-       /* Number of neighbor mesh STAs or 15 whichever is smaller */
-       neighbors = (neighbors > 15) ? 15 : neighbors;
+       neighbors = min_t(int, neighbors, IEEE80211_MAX_MESH_PEERINGS);
        *pos++ = neighbors << 1;
        /* Mesh capability */
        *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
@@ -576,13 +575,11 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        u32 changed;
 
-       ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
+       ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
        mesh_path_expire(sdata);
 
        changed = mesh_accept_plinks_update(sdata);
-       sdata_lock(sdata);
        ieee80211_mbss_info_change_notify(sdata, changed);
-       sdata_unlock(sdata);
 
        mod_timer(&ifmsh->housekeeping_timer,
                  round_jiffies(jiffies +
@@ -741,9 +738,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
                      BSS_CHANGED_HT |
                      BSS_CHANGED_BASIC_RATES |
                      BSS_CHANGED_BEACON_INT;
-       enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
-       struct ieee80211_supported_band *sband =
-                                       sdata->local->hw.wiphy->bands[band];
 
        local->fif_other_bss++;
        /* mesh ifaces must set allmulti to forward mcast traffic */
@@ -761,7 +755,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
        sdata->vif.bss_conf.ht_operation_mode =
                                ifmsh->mshcfg.ht_opmode;
        sdata->vif.bss_conf.enable_beacon = true;
-       sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sband);
 
        changed |= ieee80211_mps_local_status_update(sdata);
 
@@ -789,12 +782,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        sdata->vif.bss_conf.enable_beacon = false;
        clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
-       sdata_lock(sdata);
        bcn = rcu_dereference_protected(ifmsh->beacon,
                                        lockdep_is_held(&sdata->wdev.mtx));
        rcu_assign_pointer(ifmsh->beacon, NULL);
        kfree_rcu(bcn, rcu_head);
-       sdata_unlock(sdata);
 
        /* flush STAs and mpaths on this iface */
        sta_info_flush(sdata);
@@ -807,14 +798,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        del_timer_sync(&sdata->u.mesh.housekeeping_timer);
        del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
        del_timer_sync(&sdata->u.mesh.mesh_path_timer);
-       /*
-        * If the timer fired while we waited for it, it will have
-        * requeued the work. Now the work will be running again
-        * but will not rearm the timer again because it checks
-        * whether the interface is running, which, at this point,
-        * it no longer is.
-        */
-       cancel_work_sync(&sdata->work);
 
        local->fif_other_bss--;
        atomic_dec(&local->iff_allmultis);
@@ -955,6 +938,12 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgmt *mgmt;
        u16 stype;
 
+       sdata_lock(sdata);
+
+       /* mesh already went down */
+       if (!sdata->wdev.mesh_id_len)
+               goto out;
+
        rx_status = IEEE80211_SKB_RXCB(skb);
        mgmt = (struct ieee80211_mgmt *) skb->data;
        stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
@@ -972,12 +961,20 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status);
                break;
        }
+out:
+       sdata_unlock(sdata);
 }
 
 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
+       sdata_lock(sdata);
+
+       /* mesh already went down */
+       if (!sdata->wdev.mesh_id_len)
+               goto out;
+
        if (ifmsh->preq_queue_len &&
            time_after(jiffies,
                       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
@@ -997,6 +994,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
 
        if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
                mesh_sync_adjust_tbtt(sdata);
+
+out:
+       sdata_unlock(sdata);
 }
 
 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
index da158774eebb69eac8abf0a23472f766532cf00a..01a28bca6e9b9fb896794ead6accf771bafded0b 100644 (file)
@@ -188,7 +188,6 @@ struct mesh_rmc {
        u32 idx_mask;
 };
 
-#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
 #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 
 #define MESH_PATH_EXPIRE (600 * HZ)
@@ -324,14 +323,14 @@ static inline
 u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
 {
        atomic_inc(&sdata->u.mesh.estab_plinks);
-       return mesh_accept_plinks_update(sdata);
+       return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON;
 }
 
 static inline
 u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
 {
        atomic_dec(&sdata->u.mesh.estab_plinks);
-       return mesh_accept_plinks_update(sdata);
+       return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON;
 }
 
 static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
index 6c4da99bc4fb392f610bf57b76865f1940cccb60..09bebed99416d1f848dd95f98cf488de20a36fdf 100644 (file)
@@ -517,9 +517,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
        ieee80211_mps_frame_release(sta, elems);
 out:
        rcu_read_unlock();
-       sdata_lock(sdata);
        ieee80211_mbss_info_change_notify(sdata, changed);
-       sdata_unlock(sdata);
 }
 
 static void mesh_plink_timer(unsigned long data)
@@ -1070,9 +1068,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
 
        rcu_read_unlock();
 
-       if (changed) {
-               sdata_lock(sdata);
+       if (changed)
                ieee80211_mbss_info_change_notify(sdata, changed);
-               sdata_unlock(sdata);
-       }
 }
index f44f4caa69ee15e6bb234fc94d3b273e39ae37e4..ad9bb9e10cbb04947cb3bcac1aa4c9674d2a186b 100644 (file)
@@ -880,6 +880,10 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
 
        IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
                                        IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+
+       if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
+               IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
                            IEEE80211_STA_CONNECTION_POLL))
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
@@ -1356,7 +1360,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
                          IEEE80211_STA_CONNECTION_POLL))
                return false;
 
-       if (!sdata->vif.bss_conf.dtim_period)
+       if (!mgd->have_beacon)
                return false;
 
        rcu_read_lock();
@@ -1767,7 +1771,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_led_assoc(local, 1);
 
-       if (sdata->u.mgd.assoc_data->have_beacon) {
+       if (sdata->u.mgd.have_beacon) {
                /*
                 * If the AP is buggy we may get here with no DTIM period
                 * known, so assume it's 1 which is the only safe assumption
@@ -1775,7 +1779,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
                 * probably just won't work at all.
                 */
                bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
-               bss_info_changed |= BSS_CHANGED_DTIM_PERIOD;
+               bss_info_changed |= BSS_CHANGED_BEACON_INFO;
        } else {
                bss_conf->dtim_period = 0;
        }
@@ -1899,6 +1903,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&sdata->u.mgd.chswitch_timer);
 
        sdata->vif.bss_conf.dtim_period = 0;
+       ifmgd->have_beacon = false;
 
        ifmgd->flags = 0;
        ieee80211_vif_release_channel(sdata);
@@ -2151,7 +2156,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
+       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                             IEEE80211_DEAUTH_FRAME_LEN);
        sdata_unlock(sdata);
 }
 
@@ -2298,7 +2304,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                sdata_info(sdata, "%pM denied authentication (status %d)\n",
                           mgmt->sa, status_code);
                ieee80211_destroy_auth_data(sdata, false);
-               cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len);
+               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
                return;
        }
 
@@ -2333,7 +2339,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                 * Report auth frame to user space for processing since another
                 * round of Authentication frames is still needed.
                 */
-               cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len);
+               cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
                return;
        }
 
@@ -2350,7 +2356,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        }
        mutex_unlock(&sdata->local->sta_mtx);
 
-       cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len);
+       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
        return;
  out_err:
        mutex_unlock(&sdata->local->sta_mtx);
@@ -2383,7 +2389,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-       cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, len);
+       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
 }
 
 
@@ -2409,7 +2415,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
 
-       cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, len);
+       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
 }
 
 static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@@ -2707,7 +2713,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                        /* oops -- internal error -- send timeout for now */
                        ieee80211_destroy_assoc_data(sdata, false);
                        cfg80211_put_bss(sdata->local->hw.wiphy, bss);
-                       cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid);
+                       cfg80211_assoc_timeout(sdata->dev, mgmt->bssid);
                        return;
                }
                sdata_info(sdata, "associated\n");
@@ -2720,7 +2726,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                ieee80211_destroy_assoc_data(sdata, true);
        }
 
-       cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, len);
+       cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len);
 }
 
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
@@ -2732,24 +2738,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        int freq;
        struct ieee80211_bss *bss;
        struct ieee80211_channel *channel;
-       bool need_ps = false;
 
        sdata_assert_lock(sdata);
 
-       if ((sdata->u.mgd.associated &&
-            ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
-           (sdata->u.mgd.assoc_data &&
-            ether_addr_equal(mgmt->bssid,
-                             sdata->u.mgd.assoc_data->bss->bssid))) {
-               /* not previously set so we may need to recalc */
-               need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period;
-
-               if (elems->tim && !elems->parse_error) {
-                       const struct ieee80211_tim_ie *tim_ie = elems->tim;
-                       sdata->u.mgd.dtim_period = tim_ie->dtim_period;
-               }
-       }
-
        if (elems->ds_params)
                freq = ieee80211_channel_to_frequency(elems->ds_params[0],
                                                      rx_status->band);
@@ -2770,12 +2761,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
            !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
                return;
 
-       if (need_ps) {
-               mutex_lock(&local->iflist_mtx);
-               ieee80211_recalc_ps(local, -1);
-               mutex_unlock(&local->iflist_mtx);
-       }
-
        ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
                                         elems, true);
 
@@ -2889,7 +2874,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                       len - baselen, false, &elems);
 
                ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
-               ifmgd->assoc_data->have_beacon = true;
+               if (elems.tim && !elems.parse_error) {
+                       const struct ieee80211_tim_ie *tim_ie = elems.tim;
+                       ifmgd->dtim_period = tim_ie->dtim_period;
+               }
+               ifmgd->have_beacon = true;
                ifmgd->assoc_data->need_beacon = false;
                if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
                        sdata->vif.bss_conf.sync_tsf =
@@ -3071,7 +3060,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
         * If we haven't had a beacon before, tell the driver about the
         * DTIM period (and beacon timing if desired) now.
         */
-       if (!bss_conf->dtim_period) {
+       if (!ifmgd->have_beacon) {
                /* a few bogus AP send dtim_period = 0 or no TIM IE */
                if (elems.tim)
                        bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
@@ -3090,7 +3079,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                sdata->vif.bss_conf.sync_dtim_count = 0;
                }
 
-               changed |= BSS_CHANGED_DTIM_PERIOD;
+               changed |= BSS_CHANGED_BEACON_INFO;
+               ifmgd->have_beacon = true;
+
+               mutex_lock(&local->iflist_mtx);
+               ieee80211_recalc_ps(local, -1);
+               mutex_unlock(&local->iflist_mtx);
+
                ieee80211_recalc_ps_vif(sdata);
        }
 
@@ -3113,8 +3108,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DEAUTH_LEAVING,
                                       true, deauth_buf);
-               cfg80211_send_deauth(sdata->dev, deauth_buf,
-                                    sizeof(deauth_buf));
+               cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf,
+                                     sizeof(deauth_buf));
                return;
        }
 
@@ -3232,7 +3227,8 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
                               tx, frame_buf);
 
-       cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN);
+       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                             IEEE80211_DEAUTH_FRAME_LEN);
 }
 
 static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
@@ -3423,15 +3419,14 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
                        ieee80211_destroy_auth_data(sdata, false);
 
-                       cfg80211_send_auth_timeout(sdata->dev, bssid);
+                       cfg80211_auth_timeout(sdata->dev, bssid);
                }
        } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started)
                run_again(sdata, ifmgd->auth_data->timeout);
 
        if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started &&
            time_after(jiffies, ifmgd->assoc_data->timeout)) {
-               if ((ifmgd->assoc_data->need_beacon &&
-                    !ifmgd->assoc_data->have_beacon) ||
+               if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
                    ieee80211_do_assoc(sdata)) {
                        u8 bssid[ETH_ALEN];
 
@@ -3439,7 +3434,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
                        ieee80211_destroy_assoc_data(sdata, false);
 
-                       cfg80211_send_assoc_timeout(sdata->dev, bssid);
+                       cfg80211_assoc_timeout(sdata->dev, bssid);
                }
        } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
                run_again(sdata, ifmgd->assoc_data->timeout);
@@ -3988,8 +3983,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
 
-               cfg80211_send_deauth(sdata->dev, frame_buf,
-                                    sizeof(frame_buf));
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     sizeof(frame_buf));
        }
 
        sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@@ -4051,8 +4046,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
 
-               cfg80211_send_deauth(sdata->dev, frame_buf,
-                                    sizeof(frame_buf));
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     sizeof(frame_buf));
        }
 
        if (ifmgd->auth_data && !ifmgd->auth_data->done) {
@@ -4199,6 +4194,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        ifmgd->assoc_data = assoc_data;
        ifmgd->dtim_period = 0;
+       ifmgd->have_beacon = false;
 
        err = ieee80211_prep_connection(sdata, req->bss, true);
        if (err)
@@ -4230,7 +4226,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                        ifmgd->dtim_period = tim->dtim_period;
                        dtim_count = tim->dtim_count;
                }
-               assoc_data->have_beacon = true;
+               ifmgd->have_beacon = true;
                assoc_data->timeout = jiffies;
                assoc_data->timeout_started = true;
 
@@ -4305,8 +4301,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
  out:
        if (report_frame)
-               cfg80211_send_deauth(sdata->dev, frame_buf,
-                                    IEEE80211_DEAUTH_FRAME_LEN);
+               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                                     IEEE80211_DEAUTH_FRAME_LEN);
 
        return 0;
 }
@@ -4336,8 +4332,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                               req->reason_code, !req->local_state_change,
                               frame_buf);
 
-       cfg80211_send_disassoc(sdata->dev, frame_buf,
-                              IEEE80211_DEAUTH_FRAME_LEN);
+       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
+                             IEEE80211_DEAUTH_FRAME_LEN);
 
        return 0;
 }
index bdd7b4a719e9524e02267b52002b02870a8becdd..23dbcfc69b3b7f09ffc35c81d03dddc38d36da5a 100644 (file)
@@ -1747,27 +1747,21 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
                if (unlikely(!ieee80211_has_protected(fc) &&
                             ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
                             rx->key)) {
-                       if (ieee80211_is_deauth(fc))
-                               cfg80211_send_unprot_deauth(rx->sdata->dev,
-                                                           rx->skb->data,
-                                                           rx->skb->len);
-                       else if (ieee80211_is_disassoc(fc))
-                               cfg80211_send_unprot_disassoc(rx->sdata->dev,
-                                                             rx->skb->data,
-                                                             rx->skb->len);
+                       if (ieee80211_is_deauth(fc) ||
+                           ieee80211_is_disassoc(fc))
+                               cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+                                                            rx->skb->data,
+                                                            rx->skb->len);
                        return -EACCES;
                }
                /* BIP does not use Protected field, so need to check MMIE */
                if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
                             ieee80211_get_mmie_keyidx(rx->skb) < 0)) {
-                       if (ieee80211_is_deauth(fc))
-                               cfg80211_send_unprot_deauth(rx->sdata->dev,
-                                                           rx->skb->data,
-                                                           rx->skb->len);
-                       else if (ieee80211_is_disassoc(fc))
-                               cfg80211_send_unprot_disassoc(rx->sdata->dev,
-                                                             rx->skb->data,
-                                                             rx->skb->len);
+                       if (ieee80211_is_deauth(fc) ||
+                           ieee80211_is_disassoc(fc))
+                               cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+                                                            rx->skb->data,
+                                                            rx->skb->len);
                        return -EACCES;
                }
                /*
index a04c5671d7fd94b331d9e5a105f5530065f68ec2..b4297982d34ad19adc9c815491c153964aecd7a1 100644 (file)
@@ -1132,6 +1132,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
         * ends the poll/service period.
         */
        info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
+                      IEEE80211_TX_CTL_PS_RESPONSE |
                       IEEE80211_TX_STATUS_EOSP |
                       IEEE80211_TX_CTL_REQ_TX_STATUS;
 
@@ -1269,7 +1270,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
                         * STA may still remain is PS mode after this frame
                         * exchange.
                         */
-                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
+                                      IEEE80211_TX_CTL_PS_RESPONSE;
 
                        /*
                         * Use MoreData flag to indicate whether there are
index 41c28b977f7ce3035f21764bf26497ae0136e7b9..bd12fc54266cf059094decb56dbbcf8ef4495bdf 100644 (file)
@@ -297,6 +297,9 @@ struct sta_ampdu_mlme {
  * @rcu_head: RCU head used for freeing this station struct
  * @cur_max_bandwidth: maximum bandwidth to use for TX to the station,
  *     taken from HT/VHT capabilities or VHT operating mode notification
+ * @chains: chains ever used for RX from this station
+ * @chain_signal_last: last signal (per chain)
+ * @chain_signal_avg: signal average (per chain)
  */
 struct sta_info {
        /* General information, mostly static */
index 9972e07a2f9650315521560cfb48267504476200..4105d0ca963e25dfdd558e30c48274277e5ad2df 100644 (file)
@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        if (ieee80211_has_order(hdr->frame_control))
                return TX_CONTINUE;
 
+       if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+               info->hw_queue = tx->sdata->vif.cab_queue;
+
        /* no stations in PS mode */
        if (!atomic_read(&ps->num_sta_ps))
                return TX_CONTINUE;
 
        info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
-       if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
-               info->hw_queue = tx->sdata->vif.cab_queue;
 
        /* device releases frame after DTIM beacon */
        if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
@@ -1789,12 +1790,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
-               if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
-                       /* Do not send frames with mesh_ttl == 0 */
-                       sdata->u.mesh.mshstats.dropped_frames_ttl++;
-                       goto fail_rcu;
-               }
-
                if (!is_multicast_ether_addr(skb->data)) {
                        struct sta_info *next_hop;
                        bool mpp_lookup = true;
index 2a8d759324c250dada9942c7f88643d02dc40baa..5a6c1351d1d33c639ad85424d9c16d73f661997c 100644 (file)
@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
        list_for_each_entry(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_MONITOR:
+                       if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+                               continue;
+                       break;
                case NL80211_IFTYPE_AP_VLAN:
                        continue;
                default:
@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_MONITOR:
+                       if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+                               continue;
+                       break;
                case NL80211_IFTYPE_AP_VLAN:
                        continue;
                default:
@@ -1578,8 +1584,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                   BSS_CHANGED_ARP_FILTER |
                                   BSS_CHANGED_PS;
 
-                       if (sdata->u.mgd.dtim_period)
-                               changed |= BSS_CHANGED_DTIM_PERIOD;
+                       /* Re-send beacon info report to the driver */
+                       if (sdata->u.mgd.have_beacon)
+                               changed |= BSS_CHANGED_BEACON_INFO;
 
                        sdata_lock(sdata);
                        ieee80211_bss_info_change_notify(sdata, changed);
index fb799deaed4f9d5b130e88ed5402190b33fea1f6..a76f4533cb6ce5a1b51e2199bbfd3c8bf91a86a4 100644 (file)
@@ -5,7 +5,6 @@
 obj-$(CONFIG_NFC) += nfc.o
 obj-$(CONFIG_NFC_NCI) += nci/
 obj-$(CONFIG_NFC_HCI) += hci/
-#obj-$(CONFIG_NFC_LLCP) += llcp/
 
 nfc-objs := core.o netlink.o af_nfc.o rawsock.o llcp_core.o llcp_commands.o \
                llcp_sock.o
index 41cec1776f4f1d63f3b629178aae025b511b01c6..4224e7554a769ed7a9e3d1ea9a7f6b7cb2a38d54 100644 (file)
@@ -301,6 +301,9 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
                return NULL;
        }
 
+       /* atomic_inc_return makes it start at 1, make it start at 0 */
+       rdev->wiphy_idx--;
+
        /* give it a proper name */
        dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
 
@@ -449,8 +452,13 @@ int wiphy_register(struct wiphy *wiphy)
        u16 ifmodes = wiphy->interface_modes;
 
 #ifdef CONFIG_PM
-       if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
-                   !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
+       if (WARN_ON(wiphy->wowlan &&
+                   (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+                   !(wiphy->wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
+               return -EINVAL;
+       if (WARN_ON(wiphy->wowlan &&
+                   !wiphy->wowlan->flags && !wiphy->wowlan->n_patterns &&
+                   !wiphy->wowlan->tcp))
                return -EINVAL;
 #endif
 
@@ -540,25 +548,28 @@ int wiphy_register(struct wiphy *wiphy)
        }
 
 #ifdef CONFIG_PM
-       if (rdev->wiphy.wowlan.n_patterns) {
-               if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
-                           rdev->wiphy.wowlan.pattern_min_len >
-                           rdev->wiphy.wowlan.pattern_max_len))
-                       return -EINVAL;
-       }
+       if (WARN_ON(rdev->wiphy.wowlan && rdev->wiphy.wowlan->n_patterns &&
+                   (!rdev->wiphy.wowlan->pattern_min_len ||
+                    rdev->wiphy.wowlan->pattern_min_len >
+                               rdev->wiphy.wowlan->pattern_max_len)))
+               return -EINVAL;
 #endif
 
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
-       rtnl_lock();
 
        res = device_add(&rdev->wiphy.dev);
+       if (res)
+               return res;
+
+       res = rfkill_register(rdev->rfkill);
        if (res) {
-               rtnl_unlock();
+               device_del(&rdev->wiphy.dev);
                return res;
        }
 
+       rtnl_lock();
        /* set up regulatory info */
        wiphy_regulatory_register(wiphy);
 
@@ -585,17 +596,6 @@ int wiphy_register(struct wiphy *wiphy)
 
        cfg80211_debugfs_rdev_add(rdev);
 
-       res = rfkill_register(rdev->rfkill);
-       if (res) {
-               device_del(&rdev->wiphy.dev);
-
-               debugfs_remove_recursive(rdev->wiphy.debugfsdir);
-               list_del_rcu(&rdev->list);
-               wiphy_regulatory_deregister(wiphy);
-               rtnl_unlock();
-               return res;
-       }
-
        rdev->wiphy.registered = true;
        rtnl_unlock();
        return 0;
@@ -632,11 +632,11 @@ void wiphy_unregister(struct wiphy *wiphy)
                rtnl_unlock();
                __count == 0; }));
 
+       rfkill_unregister(rdev->rfkill);
+
        rtnl_lock();
        rdev->wiphy.registered = false;
 
-       rfkill_unregister(rdev->rfkill);
-
        BUG_ON(!list_empty(&rdev->wdev_list));
 
        /*
@@ -817,7 +817,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        pr_err("failed to add phy80211 symlink to netdev!\n");
                }
                wdev->netdev = dev;
-               wdev->sme_state = CFG80211_SME_IDLE;
 #ifdef CONFIG_CFG80211_WEXT
                wdev->wext.default_key = -1;
                wdev->wext.default_mgmt_key = -1;
index a65eaf8a84c1eced7f773a8aaa944bd1ca760cd2..a6b45bf00f3357292a1ad6e3cc5a08fd6faf9a7a 100644 (file)
@@ -308,11 +308,6 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                           bool local_state_change);
 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                        struct net_device *dev);
-void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
-                              const u8 *req_ie, size_t req_ie_len,
-                              const u8 *resp_ie, size_t resp_ie_len,
-                              u16 status, bool wextev,
-                              struct cfg80211_bss *bss);
 int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
                                u16 frame_type, const u8 *match_data,
                                int match_len);
@@ -328,12 +323,19 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
 void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
                                const struct ieee80211_vht_cap *vht_capa_mask);
 
-/* SME */
+/* SME events */
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
                     struct net_device *dev,
                     struct cfg80211_connect_params *connect,
                     struct cfg80211_cached_keys *connkeys,
                     const u8 *prev_bssid);
+void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
+                              const u8 *req_ie, size_t req_ie_len,
+                              const u8 *resp_ie, size_t resp_ie_len,
+                              u16 status, bool wextev,
+                              struct cfg80211_bss *bss);
+void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
+                            size_t ie_len, u16 reason, bool from_ap);
 int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
                        struct net_device *dev, u16 reason,
                        bool wextev);
@@ -344,21 +346,21 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
 int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
                              struct wireless_dev *wdev);
 
+/* SME implementation */
 void cfg80211_conn_work(struct work_struct *work);
-void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
-bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
+void cfg80211_sme_scan_done(struct net_device *dev);
+bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status);
+void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len);
+void cfg80211_sme_disassoc(struct wireless_dev *wdev);
+void cfg80211_sme_deauth(struct wireless_dev *wdev);
+void cfg80211_sme_auth_timeout(struct wireless_dev *wdev);
+void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev);
 
 /* internal helpers */
 bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr);
-void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
-                            size_t ie_len, u16 reason, bool from_ap);
-void cfg80211_sme_scan_done(struct net_device *dev);
-void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
-void cfg80211_sme_disassoc(struct net_device *dev,
-                          struct cfg80211_internal_bss *bss);
 void __cfg80211_scan_done(struct work_struct *wk);
 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
 void __cfg80211_sched_scan_results(struct work_struct *wk);
index 5449c5a6de847ecee355238bc43ca7447179b50e..39bff7d367687fbdd4d220d76e34d66e4e586a9c 100644 (file)
@@ -43,7 +43,6 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
        cfg80211_hold_bss(bss_from_pub(bss));
        wdev->current_bss = bss_from_pub(bss);
 
-       wdev->sme_state = CFG80211_SME_CONNECTED;
        cfg80211_upload_connect_keys(wdev);
 
        nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
@@ -64,8 +63,6 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
 
        trace_cfg80211_ibss_joined(dev, bssid);
 
-       CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
-
        ev = kzalloc(sizeof(*ev), gfp);
        if (!ev)
                return;
@@ -120,7 +117,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 #ifdef CONFIG_CFG80211_WEXT
        wdev->wext.ibss.chandef = params->chandef;
 #endif
-       wdev->sme_state = CFG80211_SME_CONNECTING;
 
        err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
                                    params->channel_fixed
@@ -134,7 +130,6 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
        err = rdev_join_ibss(rdev, dev, params);
        if (err) {
                wdev->connect_keys = NULL;
-               wdev->sme_state = CFG80211_SME_IDLE;
                return err;
        }
 
@@ -186,7 +181,6 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
        }
 
        wdev->current_bss = NULL;
-       wdev->sme_state = CFG80211_SME_IDLE;
        wdev->ssid_len = 0;
 #ifdef CONFIG_CFG80211_WEXT
        if (!nowext)
index 5dfb289ab7617da781372916816d4ecf2e479f9c..30c49202ee4d12804b78bf4cc26e2766c4cc029e 100644 (file)
@@ -18,6 +18,7 @@
 #define MESH_PATH_TO_ROOT_TIMEOUT      6000
 #define MESH_ROOT_INTERVAL     5000
 #define MESH_ROOT_CONFIRMATION_INTERVAL 2000
+#define MESH_DEFAULT_PLINK_TIMEOUT     1800 /* timeout in seconds */
 
 /*
  * Minimum interval between two consecutive PREQs originated by the same
@@ -75,6 +76,7 @@ const struct mesh_config default_mesh_config = {
        .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL,
        .power_mode = NL80211_MESH_POWER_ACTIVE,
        .dot11MeshAwakeWindowDuration = MESH_DEFAULT_AWAKE_WINDOW,
+       .plink_timeout = MESH_DEFAULT_PLINK_TIMEOUT,
 };
 
 const struct mesh_setup default_mesh_setup = {
@@ -160,6 +162,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                setup->chandef.center_freq1 = setup->chandef.chan->center_freq;
        }
 
+       /*
+        * check if basic rates are available otherwise use mandatory rates as
+        * basic rates
+        */
+       if (!setup->basic_rates) {
+               struct ieee80211_supported_band *sband =
+                               rdev->wiphy.bands[setup->chandef.chan->band];
+               setup->basic_rates = ieee80211_mandatory_rates(sband);
+       }
+
        if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
                return -EINVAL;
 
index 7bde5d9c0003166d46e06b3d947e7e2455333eaa..a61a44bc6cf024cbd32e6da15e4df93d0067cabe 100644 (file)
 #include "rdev-ops.h"
 
 
-void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
-       trace_cfg80211_send_rx_auth(dev);
-
-       nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
-       cfg80211_sme_rx_auth(dev, buf, len);
-}
-EXPORT_SYMBOL(cfg80211_send_rx_auth);
-
-void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
+void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
                            const u8 *buf, size_t len)
 {
-       u16 status_code;
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        u8 *ie = mgmt->u.assoc_resp.variable;
        int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
+       u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
 
        trace_cfg80211_send_rx_assoc(dev, bss);
 
-       status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
-
        /*
         * This is a bit of a hack, we don't notify userspace of
         * a (re-)association reply if we tried to send a reassoc
         * and got a reject -- we only try again with an assoc
         * frame instead of reassoc.
         */
-       if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
-           cfg80211_sme_failed_reassoc(wdev)) {
+       if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
                cfg80211_put_bss(wiphy, bss);
                return;
        }
 
        nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
-
-       if (status_code != WLAN_STATUS_SUCCESS && wdev->conn) {
-               cfg80211_sme_failed_assoc(wdev);
-               /*
-                * do not call connect_result() now because the
-                * sme will schedule work that does it later.
-                */
-               cfg80211_put_bss(wiphy, bss);
-               return;
-       }
-
-       if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
-               /*
-                * This is for the userspace SME, the CONNECTING
-                * state will be changed to CONNECTED by
-                * __cfg80211_connect_result() below.
-                */
-               wdev->sme_state = CFG80211_SME_CONNECTING;
-       }
-
-       /* this consumes the bss reference */
+       /* update current_bss etc., consumes the bss reference */
        __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
                                  status_code,
                                  status_code == WLAN_STATUS_SUCCESS, bss);
 }
-EXPORT_SYMBOL(cfg80211_send_rx_assoc);
+EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
 
-void cfg80211_send_deauth(struct net_device *dev,
-                         const u8 *buf, size_t len)
+static void cfg80211_process_auth(struct wireless_dev *wdev,
+                                 const u8 *buf, size_t len)
 {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       nl80211_send_rx_auth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
+       cfg80211_sme_rx_auth(wdev, buf, len);
+}
+
+static void cfg80211_process_deauth(struct wireless_dev *wdev,
+                                   const u8 *buf, size_t len)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
        const u8 *bssid = mgmt->bssid;
-       bool was_current = false;
+       u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+       bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
 
-       trace_cfg80211_send_deauth(dev);
-       ASSERT_WDEV_LOCK(wdev);
+       nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL);
 
-       if (wdev->current_bss &&
-           ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
-               cfg80211_unhold_bss(wdev->current_bss);
-               cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
-               wdev->current_bss = NULL;
-               was_current = true;
-       }
+       if (!wdev->current_bss ||
+           !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
+               return;
+
+       __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
+       cfg80211_sme_deauth(wdev);
+}
 
-       nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
+static void cfg80211_process_disassoc(struct wireless_dev *wdev,
+                                     const u8 *buf, size_t len)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
+       const u8 *bssid = mgmt->bssid;
+       u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+       bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr);
 
-       if (wdev->sme_state == CFG80211_SME_CONNECTED && was_current) {
-               u16 reason_code;
-               bool from_ap;
+       nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL);
 
-               reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+       if (WARN_ON(!wdev->current_bss ||
+                   !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
+               return;
 
-               from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
-               __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
-       } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
-               __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
-                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                         false, NULL);
-       }
+       __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
+       cfg80211_sme_disassoc(wdev);
 }
-EXPORT_SYMBOL(cfg80211_send_deauth);
 
-void cfg80211_send_disassoc(struct net_device *dev,
-                           const u8 *buf, size_t len)
+void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
-       const u8 *bssid = mgmt->bssid;
-       u16 reason_code;
-       bool from_ap;
+       struct ieee80211_mgmt *mgmt = (void *)buf;
 
-       trace_cfg80211_send_disassoc(dev);
        ASSERT_WDEV_LOCK(wdev);
 
-       nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
+       trace_cfg80211_rx_mlme_mgmt(dev, buf, len);
 
-       if (wdev->sme_state != CFG80211_SME_CONNECTED)
+       if (WARN_ON(len < 2))
                return;
 
-       if (wdev->current_bss &&
-           ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
-               cfg80211_sme_disassoc(dev, wdev->current_bss);
-               cfg80211_unhold_bss(wdev->current_bss);
-               cfg80211_put_bss(wiphy, &wdev->current_bss->pub);
-               wdev->current_bss = NULL;
-       } else
-               WARN_ON(1);
-
-
-       reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
-
-       from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
-       __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
+       if (ieee80211_is_auth(mgmt->frame_control))
+               cfg80211_process_auth(wdev, buf, len);
+       else if (ieee80211_is_deauth(mgmt->frame_control))
+               cfg80211_process_deauth(wdev, buf, len);
+       else if (ieee80211_is_disassoc(mgmt->frame_control))
+               cfg80211_process_disassoc(wdev, buf, len);
 }
-EXPORT_SYMBOL(cfg80211_send_disassoc);
+EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt);
 
-void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
+void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -170,14 +127,11 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
        trace_cfg80211_send_auth_timeout(dev, addr);
 
        nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
-       if (wdev->sme_state == CFG80211_SME_CONNECTING)
-               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
-                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                         false, NULL);
+       cfg80211_sme_auth_timeout(wdev);
 }
-EXPORT_SYMBOL(cfg80211_send_auth_timeout);
+EXPORT_SYMBOL(cfg80211_auth_timeout);
 
-void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
+void cfg80211_assoc_timeout(struct net_device *dev, const u8 *addr)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
@@ -186,12 +140,28 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
        trace_cfg80211_send_assoc_timeout(dev, addr);
 
        nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
-       if (wdev->sme_state == CFG80211_SME_CONNECTING)
-               __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
-                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                         false, NULL);
+       cfg80211_sme_assoc_timeout(wdev);
 }
-EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
+EXPORT_SYMBOL(cfg80211_assoc_timeout);
+
+void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct ieee80211_mgmt *mgmt = (void *)buf;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       trace_cfg80211_tx_mlme_mgmt(dev, buf, len);
+
+       if (WARN_ON(len < 2))
+               return;
+
+       if (ieee80211_is_deauth(mgmt->frame_control))
+               cfg80211_process_deauth(wdev, buf, len);
+       else
+               cfg80211_process_disassoc(wdev, buf, len);
+}
+EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt);
 
 void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
                                  enum nl80211_key_type key_type, int key_id,
@@ -314,21 +284,12 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
-       bool was_connected = false;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       if (wdev->current_bss && req->prev_bssid &&
-           ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
-               /*
-                * Trying to reassociate: Allow this to proceed and let the old
-                * association to be dropped when the new one is completed.
-                */
-               if (wdev->sme_state == CFG80211_SME_CONNECTED) {
-                       was_connected = true;
-                       wdev->sme_state = CFG80211_SME_CONNECTING;
-               }
-       } else if (wdev->current_bss)
+       if (wdev->current_bss &&
+           (!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid,
+                                                  req->prev_bssid)))
                return -EALREADY;
 
        cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
@@ -338,11 +299,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 
        req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
                                    WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
-       if (!req->bss) {
-               if (was_connected)
-                       wdev->sme_state = CFG80211_SME_CONNECTED;
+       if (!req->bss)
                return -ENOENT;
-       }
 
        err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
        if (err)
@@ -351,11 +309,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
        err = rdev_assoc(rdev, dev, req);
 
 out:
-       if (err) {
-               if (was_connected)
-                       wdev->sme_state = CFG80211_SME_CONNECTED;
+       if (err)
                cfg80211_put_bss(&rdev->wiphy, req->bss);
-       }
 
        return err;
 }
@@ -376,8 +331,9 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
        ASSERT_WDEV_LOCK(wdev);
 
-       if (local_state_change && (!wdev->current_bss ||
-           !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
+       if (local_state_change &&
+           (!wdev->current_bss ||
+            !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
                return 0;
 
        return rdev_deauth(rdev, dev, &req);
@@ -395,13 +351,11 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                .ie = ie,
                .ie_len = ie_len,
        };
+       int err;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       if (wdev->sme_state != CFG80211_SME_CONNECTED)
-               return -ENOTCONN;
-
-       if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state))
+       if (!wdev->current_bss)
                return -ENOTCONN;
 
        if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
@@ -409,7 +363,13 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
        else
                return -ENOTCONN;
 
-       return rdev_disassoc(rdev, dev, &req);
+       err = rdev_disassoc(rdev, dev, &req);
+       if (err)
+               return err;
+
+       /* driver should have reported the disassoc */
+       WARN_ON(wdev->current_bss);
+       return 0;
 }
 
 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
@@ -417,10 +377,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        u8 bssid[ETH_ALEN];
-       struct cfg80211_deauth_request req = {
-               .reason_code = WLAN_REASON_DEAUTH_LEAVING,
-               .bssid = bssid,
-       };
 
        ASSERT_WDEV_LOCK(wdev);
 
@@ -431,13 +387,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                return;
 
        memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
-       rdev_deauth(rdev, dev, &req);
-
-       if (wdev->current_bss) {
-               cfg80211_unhold_bss(wdev->current_bss);
-               cfg80211_put_bss(&rdev->wiphy, &wdev->current_bss->pub);
-               wdev->current_bss = NULL;
-       }
+       cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
+                            WLAN_REASON_DEAUTH_LEAVING, false);
 }
 
 struct cfg80211_mgmt_registration {
index fb6abcb359a148677f61a1165289814e805cdda1..e4028197b75dcc28af9b0011a5052e2adeeb702e 100644 (file)
@@ -800,12 +800,9 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
        case NL80211_IFTYPE_MESH_POINT:
                break;
        case NL80211_IFTYPE_ADHOC:
-               if (!wdev->current_bss)
-                       return -ENOLINK;
-               break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
-               if (wdev->sme_state != CFG80211_SME_CONNECTED)
+               if (!wdev->current_bss)
                        return -ENOLINK;
                break;
        default:
@@ -908,7 +905,7 @@ nla_put_failure:
 static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
                                        struct sk_buff *msg)
 {
-       const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp;
+       const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
        struct nlattr *nl_tcp;
 
        if (!tcp)
@@ -951,37 +948,37 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
 {
        struct nlattr *nl_wowlan;
 
-       if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns)
+       if (!dev->wiphy.wowlan)
                return 0;
 
        nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
        if (!nl_wowlan)
                return -ENOBUFS;
 
-       if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
+       if (((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
-           ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
+           ((dev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
             nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
                return -ENOBUFS;
 
-       if (dev->wiphy.wowlan.n_patterns) {
+       if (dev->wiphy.wowlan->n_patterns) {
                struct nl80211_wowlan_pattern_support pat = {
-                       .max_patterns = dev->wiphy.wowlan.n_patterns,
-                       .min_pattern_len = dev->wiphy.wowlan.pattern_min_len,
-                       .max_pattern_len = dev->wiphy.wowlan.pattern_max_len,
-                       .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset,
+                       .max_patterns = dev->wiphy.wowlan->n_patterns,
+                       .min_pattern_len = dev->wiphy.wowlan->pattern_min_len,
+                       .max_pattern_len = dev->wiphy.wowlan->pattern_max_len,
+                       .max_pkt_offset = dev->wiphy.wowlan->max_pkt_offset,
                };
 
                if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
@@ -1544,8 +1541,10 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                        int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
                        netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
-                       if (!netdev)
+                       if (!netdev) {
+                               rtnl_unlock();
                                return -ENODEV;
+                       }
                        if (netdev->ieee80211_ptr) {
                                dev = wiphy_to_dev(
                                        netdev->ieee80211_ptr->wiphy);
@@ -1589,6 +1588,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                                    !skb->len &&
                                    cb->min_dump_alloc < 4096) {
                                        cb->min_dump_alloc = 4096;
+                                       rtnl_unlock();
                                        return 1;
                                }
                                idx--;
@@ -2227,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
        [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
        [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
        [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+       [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
 };
 
 static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
@@ -2338,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                change = true;
        }
 
+       if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) &&
+           !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
+               return -EOPNOTSUPP;
+
        if (change)
                err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
        else
@@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
+
+       if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
+           !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
+               return -EOPNOTSUPP;
+
        wdev = rdev_add_virtual_intf(rdev,
                                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
                                type, err ? NULL : &flags, &params);
@@ -3965,10 +3975,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
        params.listen_interval =
                nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
 
-       if (info->attrs[NL80211_ATTR_STA_AID])
-               params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
-       else
+       if (info->attrs[NL80211_ATTR_PEER_AID])
                params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]);
+       else
+               params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
        if (!params.aid || params.aid > IEEE80211_MAX_AID)
                return -EINVAL;
 
@@ -4020,7 +4030,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                        params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
 
                /* TDLS peers cannot be added */
-               if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+               if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
+                   info->attrs[NL80211_ATTR_PEER_AID])
                        return -EINVAL;
                /* but don't bother the driver with it */
                params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
@@ -4046,7 +4057,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
                        return -EINVAL;
                /* TDLS peers cannot be added */
-               if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+               if ((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) ||
+                   info->attrs[NL80211_ATTR_PEER_AID])
                        return -EINVAL;
                break;
        case NL80211_IFTYPE_STATION:
@@ -4568,7 +4580,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
            nla_put_u32(msg, NL80211_MESHCONF_POWER_MODE,
                        cur_params.power_mode) ||
            nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
-                       cur_params.dot11MeshAwakeWindowDuration))
+                       cur_params.dot11MeshAwakeWindowDuration) ||
+           nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
+                       cur_params.plink_timeout))
                goto nla_put_failure;
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
@@ -4609,6 +4623,7 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A
        [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 },
        [NL80211_MESHCONF_POWER_MODE] = { .type = NLA_U32 },
        [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
+       [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
 };
 
 static const struct nla_policy
@@ -4746,6 +4761,9 @@ do {                                                                          \
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
                                  0, 65535, mask,
                                  NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
+                                 mask, NL80211_MESHCONF_PLINK_TIMEOUT,
+                                 nla_get_u32);
        if (mask_out)
                *mask_out = mask;
 
@@ -7132,6 +7150,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                return -EOPNOTSUPP;
 
        switch (wdev->iftype) {
+       case NL80211_IFTYPE_P2P_DEVICE:
+               if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+                       return -EINVAL;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_P2P_CLIENT:
@@ -7139,7 +7160,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_MESH_POINT:
        case NL80211_IFTYPE_P2P_GO:
-       case NL80211_IFTYPE_P2P_DEVICE:
                break;
        default:
                return -EOPNOTSUPP;
@@ -7167,9 +7187,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
        no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
-       err = nl80211_parse_chandef(rdev, info, &chandef);
-       if (err)
-               return err;
+       /* get the channel if any has been specified, otherwise pass NULL to
+        * the driver. The latter will use the current one
+        */
+       chandef.chan = NULL;
+       if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+               err = nl80211_parse_chandef(rdev, info, &chandef);
+               if (err)
+                       return err;
+       }
+
+       if (!chandef.chan && offchan)
+               return -EINVAL;
 
        if (!dont_wait_for_ack) {
                msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -7474,6 +7503,23 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
                setup.chandef.chan = NULL;
        }
 
+       if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {
+               u8 *rates = nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+               int n_rates =
+                       nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
+               struct ieee80211_supported_band *sband;
+
+               if (!setup.chandef.chan)
+                       return -EINVAL;
+
+               sband = rdev->wiphy.bands[setup.chandef.chan->band];
+
+               err = ieee80211_get_ratemask(sband, rates, n_rates,
+                                            &setup.basic_rates);
+               if (err)
+                       return err;
+       }
+
        return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
 }
 
@@ -7570,8 +7616,7 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
        void *hdr;
        u32 size = NLMSG_DEFAULT_SIZE;
 
-       if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns &&
-           !rdev->wiphy.wowlan.tcp)
+       if (!rdev->wiphy.wowlan)
                return -EOPNOTSUPP;
 
        if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
@@ -7644,7 +7689,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
        u32 data_size, wake_size, tokens_size = 0, wake_mask_size;
        int err, port;
 
-       if (!rdev->wiphy.wowlan.tcp)
+       if (!rdev->wiphy.wowlan->tcp)
                return -EINVAL;
 
        err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP,
@@ -7664,16 +7709,16 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]);
-       if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max)
+       if (data_size > rdev->wiphy.wowlan->tcp->data_payload_max)
                return -EINVAL;
 
        if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
-                       rdev->wiphy.wowlan.tcp->data_interval_max ||
+                       rdev->wiphy.wowlan->tcp->data_interval_max ||
            nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
                return -EINVAL;
 
        wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
-       if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max)
+       if (wake_size > rdev->wiphy.wowlan->tcp->wake_payload_max)
                return -EINVAL;
 
        wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]);
@@ -7688,13 +7733,13 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
 
                if (!tok->len || tokens_size % tok->len)
                        return -EINVAL;
-               if (!rdev->wiphy.wowlan.tcp->tok)
+               if (!rdev->wiphy.wowlan->tcp->tok)
                        return -EINVAL;
-               if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len)
+               if (tok->len > rdev->wiphy.wowlan->tcp->tok->max_len)
                        return -EINVAL;
-               if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len)
+               if (tok->len < rdev->wiphy.wowlan->tcp->tok->min_len)
                        return -EINVAL;
-               if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize)
+               if (tokens_size > rdev->wiphy.wowlan->tcp->tok->bufsize)
                        return -EINVAL;
                if (tok->offset + tok->len > data_size)
                        return -EINVAL;
@@ -7702,7 +7747,7 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
 
        if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) {
                seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]);
-               if (!rdev->wiphy.wowlan.tcp->seq)
+               if (!rdev->wiphy.wowlan->tcp->seq)
                        return -EINVAL;
                if (seq->len == 0 || seq->len > 4)
                        return -EINVAL;
@@ -7783,12 +7828,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
        struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
        struct cfg80211_wowlan new_triggers = {};
        struct cfg80211_wowlan *ntrig;
-       struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
+       const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
        int err, i;
        bool prev_enabled = rdev->wiphy.wowlan_config;
 
-       if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns &&
-           !rdev->wiphy.wowlan.tcp)
+       if (!wowlan)
                return -EOPNOTSUPP;
 
        if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
@@ -9305,31 +9349,27 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
                                NL80211_CMD_DISASSOCIATE, gfp);
 }
 
-void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
-                                size_t len)
+void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf,
+                                 size_t len)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       const struct ieee80211_mgmt *mgmt = (void *)buf;
+       u32 cmd;
 
-       trace_cfg80211_send_unprot_deauth(dev);
-       nl80211_send_mlme_event(rdev, dev, buf, len,
-                               NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC);
-}
-EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
+       if (WARN_ON(len < 2))
+               return;
 
-void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
-                                  size_t len)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       if (ieee80211_is_deauth(mgmt->frame_control))
+               cmd = NL80211_CMD_UNPROT_DEAUTHENTICATE;
+       else
+               cmd = NL80211_CMD_UNPROT_DISASSOCIATE;
 
-       trace_cfg80211_send_unprot_disassoc(dev);
-       nl80211_send_mlme_event(rdev, dev, buf, len,
-                               NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC);
+       trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len);
+       nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC);
 }
-EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
+EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt);
 
 static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
                                      struct net_device *netdev, int cmd,
@@ -9840,7 +9880,6 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
-       int err;
        u32 nlportid = ACCESS_ONCE(wdev->ap_unexpected_nlportid);
 
        if (!nlportid)
@@ -9861,12 +9900,7 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
                goto nla_put_failure;
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return true;
-       }
-
+       genlmsg_end(msg, hdr);
        genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
        return true;
 
@@ -10309,10 +10343,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
        if (nl80211_send_chandef(msg, chandef))
                goto nla_put_failure;
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -10378,7 +10409,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
-       int err;
 
        trace_cfg80211_probe_status(dev, addr, cookie, acked);
 
@@ -10400,11 +10430,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
            (acked && nla_put_flag(msg, NL80211_ATTR_ACK)))
                goto nla_put_failure;
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -10470,7 +10496,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
-       int err, size = 200;
+       int size = 200;
 
        trace_cfg80211_report_wowlan_wakeup(wdev->wiphy, wdev, wakeup);
 
@@ -10556,9 +10582,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
                nla_nest_end(msg, reasons);
        }
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0)
-               goto free_msg;
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -10578,7 +10602,6 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
        struct sk_buff *msg;
        void *hdr;
-       int err;
 
        trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
                                         reason_code);
@@ -10601,11 +10624,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
             nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
                goto nla_put_failure;
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -10663,7 +10682,6 @@ void cfg80211_ft_event(struct net_device *netdev,
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        void *hdr;
-       int err;
 
        trace_cfg80211_ft_event(wiphy, netdev, ft_event);
 
@@ -10689,11 +10707,7 @@ void cfg80211_ft_event(struct net_device *netdev,
                nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
                        ft_event->ric_ies);
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, GFP_KERNEL);
index e1d6749234c6b48a2528a550089ee0acf113781b..5a24c986f34be27e61613f0deb421a35efc61533 100644 (file)
@@ -1345,7 +1345,7 @@ get_reg_request_treatment(struct wiphy *wiphy,
                                return REG_REQ_OK;
                        return REG_REQ_ALREADY_SET;
                }
-               return 0;
+               return REG_REQ_OK;
        case NL80211_REGDOM_SET_BY_DRIVER:
                if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
                        if (regdom_changes(pending_request->alpha2))
index 81be95f3be74352aa245c5bcdc64c496db7d5e52..ae7e2cbf45cbfe2cc22ac52eff9262833eca5861 100644 (file)
@@ -1,5 +1,7 @@
 /*
- * SME code for cfg80211's connect emulation.
+ * SME code for cfg80211
+ * both driver SME event handling and the SME implementation
+ * (for nl80211's connect() and wext)
  *
  * Copyright 2009      Johannes Berg <johannes@sipsolutions.net>
  * Copyright (C) 2009   Intel Corporation. All rights reserved.
 #include "reg.h"
 #include "rdev-ops.h"
 
+/*
+ * Software SME in cfg80211, using auth/assoc/deauth calls to the
+ * driver. This is is for implementing nl80211's connect/disconnect
+ * and wireless extensions (if configured.)
+ */
+
 struct cfg80211_conn {
        struct cfg80211_connect_params params;
        /* these are sub-states of the _CONNECTING sme_state */
        enum {
-               CFG80211_CONN_IDLE,
                CFG80211_CONN_SCANNING,
                CFG80211_CONN_SCAN_AGAIN,
                CFG80211_CONN_AUTHENTICATE_NEXT,
                CFG80211_CONN_AUTHENTICATING,
                CFG80211_CONN_ASSOCIATE_NEXT,
                CFG80211_CONN_ASSOCIATING,
-               CFG80211_CONN_DEAUTH_ASSOC_FAIL,
+               CFG80211_CONN_DEAUTH,
+               CFG80211_CONN_CONNECTED,
        } state;
        u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
        u8 *ie;
@@ -37,39 +45,16 @@ struct cfg80211_conn {
        bool auto_auth, prev_bssid_valid;
 };
 
-static bool cfg80211_is_all_idle(void)
+static void cfg80211_sme_free(struct wireless_dev *wdev)
 {
-       struct cfg80211_registered_device *rdev;
-       struct wireless_dev *wdev;
-       bool is_all_idle = true;
-
-       /*
-        * All devices must be idle as otherwise if you are actively
-        * scanning some new beacon hints could be learned and would
-        * count as new regulatory hints.
-        */
-       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
-               list_for_each_entry(wdev, &rdev->wdev_list, list) {
-                       wdev_lock(wdev);
-                       if (wdev->sme_state != CFG80211_SME_IDLE)
-                               is_all_idle = false;
-                       wdev_unlock(wdev);
-               }
-       }
-
-       return is_all_idle;
-}
+       if (!wdev->conn)
+               return;
 
-static void disconnect_work(struct work_struct *work)
-{
-       rtnl_lock();
-       if (cfg80211_is_all_idle())
-               regulatory_hint_disconnect();
-       rtnl_unlock();
+       kfree(wdev->conn->ie);
+       kfree(wdev->conn);
+       wdev->conn = NULL;
 }
 
-static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
-
 static int cfg80211_conn_scan(struct wireless_dev *wdev)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
@@ -164,6 +149,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
        params = &wdev->conn->params;
 
        switch (wdev->conn->state) {
+       case CFG80211_CONN_SCANNING:
+               /* didn't find it during scan ... */
+               return -ENOENT;
        case CFG80211_CONN_SCAN_AGAIN:
                return cfg80211_conn_scan(wdev);
        case CFG80211_CONN_AUTHENTICATE_NEXT:
@@ -200,12 +188,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                             WLAN_REASON_DEAUTH_LEAVING,
                                             false);
                return err;
-       case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
+       case CFG80211_CONN_DEAUTH:
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
                                     WLAN_REASON_DEAUTH_LEAVING, false);
-               /* return an error so that we call __cfg80211_connect_result() */
-               return -EINVAL;
+               return 0;
        default:
                return 0;
        }
@@ -229,7 +216,8 @@ void cfg80211_conn_work(struct work_struct *work)
                        wdev_unlock(wdev);
                        continue;
                }
-               if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) {
+               if (!wdev->conn ||
+                   wdev->conn->state == CFG80211_CONN_CONNECTED) {
                        wdev_unlock(wdev);
                        continue;
                }
@@ -237,12 +225,14 @@ void cfg80211_conn_work(struct work_struct *work)
                        memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
                        bssid = bssid_buf;
                }
-               if (cfg80211_conn_do_work(wdev))
+               if (cfg80211_conn_do_work(wdev)) {
                        __cfg80211_connect_result(
                                        wdev->netdev, bssid,
                                        NULL, 0, NULL, 0,
                                        WLAN_STATUS_UNSPECIFIED_FAILURE,
                                        false, NULL);
+                       cfg80211_sme_free(wdev);
+               }
                wdev_unlock(wdev);
        }
 
@@ -286,9 +276,6 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
 
        ASSERT_WDEV_LOCK(wdev);
 
-       if (wdev->sme_state != CFG80211_SME_CONNECTING)
-               return;
-
        if (!wdev->conn)
                return;
 
@@ -297,20 +284,10 @@ static void __cfg80211_sme_scan_done(struct net_device *dev)
                return;
 
        bss = cfg80211_get_conn_bss(wdev);
-       if (bss) {
+       if (bss)
                cfg80211_put_bss(&rdev->wiphy, bss);
-       } else {
-               /* not found */
-               if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)
-                       schedule_work(&rdev->conn_work);
-               else
-                       __cfg80211_connect_result(
-                                       wdev->netdev,
-                                       wdev->conn->params.bssid,
-                                       NULL, 0, NULL, 0,
-                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                       false, NULL);
-       }
+       else
+               schedule_work(&rdev->conn_work);
 }
 
 void cfg80211_sme_scan_done(struct net_device *dev)
@@ -322,10 +299,8 @@ void cfg80211_sme_scan_done(struct net_device *dev)
        wdev_unlock(wdev);
 }
 
-void cfg80211_sme_rx_auth(struct net_device *dev,
-                         const u8 *buf, size_t len)
+void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
 {
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
@@ -333,11 +308,7 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
 
        ASSERT_WDEV_LOCK(wdev);
 
-       /* should only RX auth frames when connecting */
-       if (wdev->sme_state != CFG80211_SME_CONNECTING)
-               return;
-
-       if (WARN_ON(!wdev->conn))
+       if (!wdev->conn || wdev->conn->state == CFG80211_CONN_CONNECTED)
                return;
 
        if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&
@@ -366,46 +337,226 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
                wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
                schedule_work(&rdev->conn_work);
        } else if (status_code != WLAN_STATUS_SUCCESS) {
-               __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
+               __cfg80211_connect_result(wdev->netdev, mgmt->bssid,
+                                         NULL, 0, NULL, 0,
                                          status_code, false, NULL);
-       } else if (wdev->sme_state == CFG80211_SME_CONNECTING &&
-                wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
+       } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
                wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
                schedule_work(&rdev->conn_work);
        }
 }
 
-bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev)
+bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
 {
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 
-       if (WARN_ON(!wdev->conn))
+       if (!wdev->conn)
                return false;
 
-       if (!wdev->conn->prev_bssid_valid)
+       if (status == WLAN_STATUS_SUCCESS) {
+               wdev->conn->state = CFG80211_CONN_CONNECTED;
                return false;
+       }
 
-       /*
-        * Some stupid APs don't accept reassoc, so we
-        * need to fall back to trying regular assoc.
-        */
-       wdev->conn->prev_bssid_valid = false;
-       wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
+       if (wdev->conn->prev_bssid_valid) {
+               /*
+                * Some stupid APs don't accept reassoc, so we
+                * need to fall back to trying regular assoc;
+                * return true so no event is sent to userspace.
+                */
+               wdev->conn->prev_bssid_valid = false;
+               wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
+               schedule_work(&rdev->conn_work);
+               return true;
+       }
+
+       wdev->conn->state = CFG80211_CONN_DEAUTH;
        schedule_work(&rdev->conn_work);
+       return false;
+}
 
-       return true;
+void cfg80211_sme_deauth(struct wireless_dev *wdev)
+{
+       cfg80211_sme_free(wdev);
 }
 
-void cfg80211_sme_failed_assoc(struct wireless_dev *wdev)
+void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 {
-       struct wiphy *wiphy = wdev->wiphy;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       cfg80211_sme_free(wdev);
+}
 
-       wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL;
+void cfg80211_sme_disassoc(struct wireless_dev *wdev)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_DEAUTH;
        schedule_work(&rdev->conn_work);
 }
 
+void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
+{
+       cfg80211_sme_disassoc(wdev);
+}
+
+static int cfg80211_sme_connect(struct wireless_dev *wdev,
+                               struct cfg80211_connect_params *connect,
+                               const u8 *prev_bssid)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_bss *bss;
+       int err;
+
+       if (!rdev->ops->auth || !rdev->ops->assoc)
+               return -EOPNOTSUPP;
+
+       if (wdev->current_bss)
+               return -EALREADY;
+
+       if (WARN_ON(wdev->conn))
+               return -EINPROGRESS;
+
+       wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
+       if (!wdev->conn)
+               return -ENOMEM;
+
+       /*
+        * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
+        */
+       memcpy(&wdev->conn->params, connect, sizeof(*connect));
+       if (connect->bssid) {
+               wdev->conn->params.bssid = wdev->conn->bssid;
+               memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
+       }
+
+       if (connect->ie) {
+               wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
+                                       GFP_KERNEL);
+               wdev->conn->params.ie = wdev->conn->ie;
+               if (!wdev->conn->ie) {
+                       kfree(wdev->conn);
+                       wdev->conn = NULL;
+                       return -ENOMEM;
+               }
+       }
+
+       if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
+               wdev->conn->auto_auth = true;
+               /* start with open system ... should mostly work */
+               wdev->conn->params.auth_type =
+                       NL80211_AUTHTYPE_OPEN_SYSTEM;
+       } else {
+               wdev->conn->auto_auth = false;
+       }
+
+       wdev->conn->params.ssid = wdev->ssid;
+       wdev->conn->params.ssid_len = connect->ssid_len;
+
+       /* see if we have the bss already */
+       bss = cfg80211_get_conn_bss(wdev);
+
+       if (prev_bssid) {
+               memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
+               wdev->conn->prev_bssid_valid = true;
+       }
+
+       /* we're good if we have a matching bss struct */
+       if (bss) {
+               wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
+               err = cfg80211_conn_do_work(wdev);
+               cfg80211_put_bss(wdev->wiphy, bss);
+       } else {
+               /* otherwise we'll need to scan for the AP first */
+               err = cfg80211_conn_scan(wdev);
+
+               /*
+                * If we can't scan right now, then we need to scan again
+                * after the current scan finished, since the parameters
+                * changed (unless we find a good AP anyway).
+                */
+               if (err == -EBUSY) {
+                       err = 0;
+                       wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
+               }
+       }
+
+       if (err)
+               cfg80211_sme_free(wdev);
+
+       return err;
+}
+
+static int cfg80211_sme_disconnect(struct wireless_dev *wdev, u16 reason)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       int err;
+
+       if (!wdev->conn)
+               return 0;
+
+       if (!rdev->ops->deauth)
+               return -EOPNOTSUPP;
+
+       if (wdev->conn->state == CFG80211_CONN_SCANNING ||
+           wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) {
+               err = 0;
+               goto out;
+       }
+
+       /* wdev->conn->params.bssid must be set if > SCANNING */
+       err = cfg80211_mlme_deauth(rdev, wdev->netdev,
+                                  wdev->conn->params.bssid,
+                                  NULL, 0, reason, false);
+ out:
+       cfg80211_sme_free(wdev);
+       return err;
+}
+
+/*
+ * code shared for in-device and software SME
+ */
+
+static bool cfg80211_is_all_idle(void)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       bool is_all_idle = true;
+
+       /*
+        * All devices must be idle as otherwise if you are actively
+        * scanning some new beacon hints could be learned and would
+        * count as new regulatory hints.
+        */
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               list_for_each_entry(wdev, &rdev->wdev_list, list) {
+                       wdev_lock(wdev);
+                       if (wdev->conn || wdev->current_bss)
+                               is_all_idle = false;
+                       wdev_unlock(wdev);
+               }
+       }
+
+       return is_all_idle;
+}
+
+static void disconnect_work(struct work_struct *work)
+{
+       rtnl_lock();
+       if (cfg80211_is_all_idle())
+               regulatory_hint_disconnect();
+       rtnl_unlock();
+}
+
+static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
+
+
+/*
+ * API calls for drivers implementing connect/disconnect and
+ * SME event handling
+ */
+
 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                               const u8 *req_ie, size_t req_ie_len,
                               const u8 *resp_ie, size_t resp_ie_len,
@@ -424,9 +575,6 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
                return;
 
-       if (wdev->sme_state != CFG80211_SME_CONNECTING)
-               return;
-
        nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev,
                                    bssid, req_ie, req_ie_len,
                                    resp_ie, resp_ie_len,
@@ -463,15 +611,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                wdev->current_bss = NULL;
        }
 
-       if (wdev->conn)
-               wdev->conn->state = CFG80211_CONN_IDLE;
-
        if (status != WLAN_STATUS_SUCCESS) {
-               wdev->sme_state = CFG80211_SME_IDLE;
-               if (wdev->conn)
-                       kfree(wdev->conn->ie);
-               kfree(wdev->conn);
-               wdev->conn = NULL;
                kfree(wdev->connect_keys);
                wdev->connect_keys = NULL;
                wdev->ssid_len = 0;
@@ -480,21 +620,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        }
 
        if (!bss)
-               bss = cfg80211_get_bss(wdev->wiphy,
-                                      wdev->conn ? wdev->conn->params.channel :
-                                      NULL,
-                                      bssid,
+               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
                                       wdev->ssid, wdev->ssid_len,
                                       WLAN_CAPABILITY_ESS,
                                       WLAN_CAPABILITY_ESS);
-
        if (WARN_ON(!bss))
                return;
 
        cfg80211_hold_bss(bss_from_pub(bss));
        wdev->current_bss = bss_from_pub(bss);
 
-       wdev->sme_state = CFG80211_SME_CONNECTED;
        cfg80211_upload_connect_keys(wdev);
 
        rcu_read_lock();
@@ -530,8 +665,6 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        struct cfg80211_event *ev;
        unsigned long flags;
 
-       CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING);
-
        ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
        if (!ev)
                return;
@@ -572,13 +705,8 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
                    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
                goto out;
 
-       if (wdev->sme_state != CFG80211_SME_CONNECTED)
-               goto out;
-
-       /* internal error -- how did we get to CONNECTED w/o BSS? */
-       if (WARN_ON(!wdev->current_bss)) {
+       if (WARN_ON(!wdev->current_bss))
                goto out;
-       }
 
        cfg80211_unhold_bss(wdev->current_bss);
        cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
@@ -628,8 +756,6 @@ void cfg80211_roamed(struct net_device *dev,
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_bss *bss;
 
-       CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
-
        bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
                               wdev->ssid_len, WLAN_CAPABILITY_ESS,
                               WLAN_CAPABILITY_ESS);
@@ -651,8 +777,6 @@ void cfg80211_roamed_bss(struct net_device *dev,
        struct cfg80211_event *ev;
        unsigned long flags;
 
-       CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
-
        if (WARN_ON(!bss))
                return;
 
@@ -694,25 +818,14 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
                return;
 
-       if (wdev->sme_state != CFG80211_SME_CONNECTED)
-               return;
-
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
                cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
        }
 
        wdev->current_bss = NULL;
-       wdev->sme_state = CFG80211_SME_IDLE;
        wdev->ssid_len = 0;
 
-       if (wdev->conn) {
-               kfree(wdev->conn->ie);
-               wdev->conn->ie = NULL;
-               kfree(wdev->conn);
-               wdev->conn = NULL;
-       }
-
        nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
        /*
@@ -741,8 +854,6 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
        struct cfg80211_event *ev;
        unsigned long flags;
 
-       CFG80211_DEV_WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED);
-
        ev = kzalloc(sizeof(*ev) + ie_len, gfp);
        if (!ev)
                return;
@@ -760,6 +871,9 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
 }
 EXPORT_SYMBOL(cfg80211_disconnected);
 
+/*
+ * API calls for nl80211/wext compatibility code
+ */
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
                     struct net_device *dev,
                     struct cfg80211_connect_params *connect,
@@ -767,14 +881,10 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
                     const u8 *prev_bssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_bss *bss = NULL;
        int err;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       if (wdev->sme_state != CFG80211_SME_IDLE)
-               return -EALREADY;
-
        if (WARN_ON(wdev->connect_keys)) {
                kfree(wdev->connect_keys);
                wdev->connect_keys = NULL;
@@ -810,105 +920,22 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
                }
        }
 
-       if (!rdev->ops->connect) {
-               if (!rdev->ops->auth || !rdev->ops->assoc)
-                       return -EOPNOTSUPP;
-
-               if (WARN_ON(wdev->conn))
-                       return -EINPROGRESS;
-
-               wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL);
-               if (!wdev->conn)
-                       return -ENOMEM;
-
-               /*
-                * Copy all parameters, and treat explicitly IEs, BSSID, SSID.
-                */
-               memcpy(&wdev->conn->params, connect, sizeof(*connect));
-               if (connect->bssid) {
-                       wdev->conn->params.bssid = wdev->conn->bssid;
-                       memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN);
-               }
+       wdev->connect_keys = connkeys;
+       memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
+       wdev->ssid_len = connect->ssid_len;
 
-               if (connect->ie) {
-                       wdev->conn->ie = kmemdup(connect->ie, connect->ie_len,
-                                               GFP_KERNEL);
-                       wdev->conn->params.ie = wdev->conn->ie;
-                       if (!wdev->conn->ie) {
-                               kfree(wdev->conn);
-                               wdev->conn = NULL;
-                               return -ENOMEM;
-                       }
-               }
-
-               if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) {
-                       wdev->conn->auto_auth = true;
-                       /* start with open system ... should mostly work */
-                       wdev->conn->params.auth_type =
-                               NL80211_AUTHTYPE_OPEN_SYSTEM;
-               } else {
-                       wdev->conn->auto_auth = false;
-               }
-
-               memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
-               wdev->ssid_len = connect->ssid_len;
-               wdev->conn->params.ssid = wdev->ssid;
-               wdev->conn->params.ssid_len = connect->ssid_len;
-
-               /* see if we have the bss already */
-               bss = cfg80211_get_conn_bss(wdev);
-
-               wdev->sme_state = CFG80211_SME_CONNECTING;
-               wdev->connect_keys = connkeys;
-
-               if (prev_bssid) {
-                       memcpy(wdev->conn->prev_bssid, prev_bssid, ETH_ALEN);
-                       wdev->conn->prev_bssid_valid = true;
-               }
-
-               /* we're good if we have a matching bss struct */
-               if (bss) {
-                       wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
-                       err = cfg80211_conn_do_work(wdev);
-                       cfg80211_put_bss(wdev->wiphy, bss);
-               } else {
-                       /* otherwise we'll need to scan for the AP first */
-                       err = cfg80211_conn_scan(wdev);
-                       /*
-                        * If we can't scan right now, then we need to scan again
-                        * after the current scan finished, since the parameters
-                        * changed (unless we find a good AP anyway).
-                        */
-                       if (err == -EBUSY) {
-                               err = 0;
-                               wdev->conn->state = CFG80211_CONN_SCAN_AGAIN;
-                       }
-               }
-               if (err) {
-                       kfree(wdev->conn->ie);
-                       kfree(wdev->conn);
-                       wdev->conn = NULL;
-                       wdev->sme_state = CFG80211_SME_IDLE;
-                       wdev->connect_keys = NULL;
-                       wdev->ssid_len = 0;
-               }
-
-               return err;
-       } else {
-               wdev->sme_state = CFG80211_SME_CONNECTING;
-               wdev->connect_keys = connkeys;
+       if (!rdev->ops->connect)
+               err = cfg80211_sme_connect(wdev, connect, prev_bssid);
+       else
                err = rdev_connect(rdev, dev, connect);
-               if (err) {
-                       wdev->connect_keys = NULL;
-                       wdev->sme_state = CFG80211_SME_IDLE;
-                       return err;
-               }
 
-               memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
-               wdev->ssid_len = connect->ssid_len;
-
-               return 0;
+       if (err) {
+               wdev->connect_keys = NULL;
+               wdev->ssid_len = 0;
+               return err;
        }
+
+       return 0;
 }
 
 int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
@@ -919,78 +946,17 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 
        ASSERT_WDEV_LOCK(wdev);
 
-       if (wdev->sme_state == CFG80211_SME_IDLE)
-               return -EINVAL;
-
        kfree(wdev->connect_keys);
        wdev->connect_keys = NULL;
 
-       if (!rdev->ops->disconnect) {
-               if (!rdev->ops->deauth)
-                       return -EOPNOTSUPP;
-
-               /* was it connected by userspace SME? */
-               if (!wdev->conn) {
-                       cfg80211_mlme_down(rdev, dev);
-                       goto disconnect;
-               }
-
-               if (wdev->sme_state == CFG80211_SME_CONNECTING &&
-                   (wdev->conn->state == CFG80211_CONN_SCANNING ||
-                    wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) {
-                       wdev->sme_state = CFG80211_SME_IDLE;
-                       kfree(wdev->conn->ie);
-                       kfree(wdev->conn);
-                       wdev->conn = NULL;
-                       wdev->ssid_len = 0;
-                       return 0;
-               }
-
-               /* wdev->conn->params.bssid must be set if > SCANNING */
-               err = cfg80211_mlme_deauth(rdev, dev,
-                                            wdev->conn->params.bssid,
-                                            NULL, 0, reason, false);
-               if (err)
-                       return err;
+       if (wdev->conn) {
+               err = cfg80211_sme_disconnect(wdev, reason);
+       } else if (!rdev->ops->disconnect) {
+               cfg80211_mlme_down(rdev, dev);
+               err = 0;
        } else {
                err = rdev_disconnect(rdev, dev, reason);
-               if (err)
-                       return err;
        }
 
- disconnect:
-       if (wdev->sme_state == CFG80211_SME_CONNECTED)
-               __cfg80211_disconnected(dev, NULL, 0, 0, false);
-       else if (wdev->sme_state == CFG80211_SME_CONNECTING)
-               __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
-                                         WLAN_STATUS_UNSPECIFIED_FAILURE,
-                                         wextev, NULL);
-
-       return 0;
-}
-
-void cfg80211_sme_disassoc(struct net_device *dev,
-                          struct cfg80211_internal_bss *bss)
-{
-       struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-       u8 bssid[ETH_ALEN];
-
-       ASSERT_WDEV_LOCK(wdev);
-
-       if (!wdev->conn)
-               return;
-
-       if (wdev->conn->state == CFG80211_CONN_IDLE)
-               return;
-
-       /*
-        * Ok, so the association was made by this SME -- we don't
-        * want it any more so deauthenticate too.
-        */
-
-       memcpy(bssid, bss->pub.bssid, ETH_ALEN);
-
-       cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
-                            WLAN_REASON_DEAUTH_LEAVING, false);
+       return err;
 }
index 23fafeae8a109e807aaf8456fcc044c449b46631..e1534baf2ebbe5d0fdc41d4e2d6ceb42fd9630f3 100644 (file)
@@ -1911,24 +1911,46 @@ TRACE_EVENT(cfg80211_send_rx_assoc,
                  NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
 );
 
-DEFINE_EVENT(netdev_evt_only, cfg80211_send_deauth,
-       TP_PROTO(struct net_device *netdev),
-       TP_ARGS(netdev)
+DECLARE_EVENT_CLASS(netdev_frame_event,
+       TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
+       TP_ARGS(netdev, buf, len),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               __dynamic_array(u8, frame, len)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               memcpy(__get_dynamic_array(frame), buf, len);
+       ),
+       TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x",
+                 NETDEV_PR_ARG,
+                 le16_to_cpup((__le16 *)__get_dynamic_array(frame)))
 );
 
-DEFINE_EVENT(netdev_evt_only, cfg80211_send_disassoc,
-       TP_PROTO(struct net_device *netdev),
-       TP_ARGS(netdev)
+DEFINE_EVENT(netdev_frame_event, cfg80211_rx_unprot_mlme_mgmt,
+       TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
+       TP_ARGS(netdev, buf, len)
 );
 
-DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_deauth,
-       TP_PROTO(struct net_device *netdev),
-       TP_ARGS(netdev)
+DEFINE_EVENT(netdev_frame_event, cfg80211_rx_mlme_mgmt,
+       TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
+       TP_ARGS(netdev, buf, len)
 );
 
-DEFINE_EVENT(netdev_evt_only, cfg80211_send_unprot_disassoc,
-       TP_PROTO(struct net_device *netdev),
-       TP_ARGS(netdev)
+TRACE_EVENT(cfg80211_tx_mlme_mgmt,
+       TP_PROTO(struct net_device *netdev, const u8 *buf, int len),
+       TP_ARGS(netdev, buf, len),
+       TP_STRUCT__entry(
+               NETDEV_ENTRY
+               __dynamic_array(u8, frame, len)
+       ),
+       TP_fast_assign(
+               NETDEV_ASSIGN;
+               memcpy(__get_dynamic_array(frame), buf, len);
+       ),
+       TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x",
+                 NETDEV_PR_ARG,
+                 le16_to_cpup((__le16 *)__get_dynamic_array(frame)))
 );
 
 DECLARE_EVENT_CLASS(netdev_mac_evt,
index a53f8404f45116119525af82d6409defbd2316b8..14c9a2583ba0926a2e14a777aaa5b69fd09f8963 100644 (file)
@@ -89,7 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
 
        wdev_lock(wdev);
 
-       if (wdev->sme_state != CFG80211_SME_IDLE) {
+       if (wdev->conn) {
                bool event = true;
 
                if (wdev->wext.connect.channel == chan) {
@@ -188,7 +188,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
 
        err = 0;
 
-       if (wdev->sme_state != CFG80211_SME_IDLE) {
+       if (wdev->conn) {
                bool event = true;
 
                if (wdev->wext.connect.ssid && len &&
@@ -277,7 +277,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
 
        wdev_lock(wdev);
 
-       if (wdev->sme_state != CFG80211_SME_IDLE) {
+       if (wdev->conn) {
                err = 0;
                /* both automatic */
                if (!bssid && !wdev->wext.connect.bssid)
@@ -364,7 +364,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
        wdev->wext.ie = ie;
        wdev->wext.ie_len = ie_len;
 
-       if (wdev->sme_state != CFG80211_SME_IDLE) {
+       if (wdev->conn) {
                err = cfg80211_disconnect(rdev, dev,
                                          WLAN_REASON_DEAUTH_LEAVING, false);
                if (err)