Merge tag 'iwlwifi-next-for-kalle-2016-07-01' of git://git.kernel.org/pub/scm/linux...
authorKalle Valo <kvalo@codeaurora.org>
Tue, 5 Jul 2016 12:59:54 +0000 (15:59 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 5 Jul 2016 12:59:54 +0000 (15:59 +0300)
* More work on the RX path for the 9000 device series
* Some more dynamic queue allocation work
* A few bugfixes and other improvements

25 files changed:
drivers/net/wireless/intel/iwlwifi/dvm/main.c
drivers/net/wireless/intel/iwlwifi/iwl-9000.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-fh.h
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/power.c
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c

index 37b32a6..5915914 100644 (file)
@@ -1317,6 +1317,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
 
        switch (iwlwifi_mod_params.amsdu_size) {
+       case IWL_AMSDU_DEF:
        case IWL_AMSDU_4K:
                trans_cfg.rx_buf_size = IWL_AMSDU_4K;
                break;
index 3ac298f..5c1e71f 100644 (file)
@@ -178,6 +178,7 @@ const struct iwl_cfg iwl5165_2ac_cfg = {
                .nvm_ver = IWL9000_NVM_VERSION,
                .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
                .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+               .integrated = true,
 };
 
 MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
index 4a0af7d..57b14f4 100644 (file)
@@ -319,6 +319,7 @@ struct iwl_pwr_tx_backoff {
  * @mq_rx_supported: multi-queue rx support
  * @vht_mu_mimo_supported: VHT MU-MIMO support
  * @rf_id: need to read rf_id to determine the firmware image
+ * @integrated: discrete or integrated
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -362,7 +363,8 @@ struct iwl_cfg {
            apmg_not_supported:1,
            mq_rx_supported:1,
            vht_mu_mimo_supported:1,
-           rf_id:1;
+           rf_id:1,
+           integrated:1;
        u8 valid_tx_ant;
        u8 valid_rx_ant;
        u8 non_shared_ant;
index b529134..871ad02 100644 (file)
 
 #define CSR_LED_REG             (CSR_BASE+0x094)
 #define CSR_DRAM_INT_TBL_REG   (CSR_BASE+0x0A0)
-#define CSR_MAC_SHADOW_REG_CTRL        (CSR_BASE+0x0A8) /* 6000 and up */
-
+#define CSR_MAC_SHADOW_REG_CTRL                (CSR_BASE + 0x0A8) /* 6000 and up */
+#define CSR_MAC_SHADOW_REG_CTRL_RX_WAKE        BIT(20)
+#define CSR_MAC_SHADOW_REG_CTL2                (CSR_BASE + 0x0AC)
+#define CSR_MAC_SHADOW_REG_CTL2_RX_WAKE        0xFFFF
 
 /* GIO Chicken Bits (PCI Express bus link power management) */
 #define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
index f52ff75..292fc8b 100644 (file)
@@ -1658,7 +1658,8 @@ MODULE_PARM_DESC(11n_disable,
        "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
 module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size,
                   int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size, "amsdu size 0:4K 1:8K 2:12K (default 0)");
+MODULE_PARM_DESC(amsdu_size,
+                "amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)");
 module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO);
 MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
 
index bf1b69a..3199d34 100644 (file)
@@ -766,7 +766,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
        if (cfg->ht_params->ldpc)
                ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
 
-       if (iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K)
+       if ((cfg->mq_rx_supported &&
+            iwlwifi_mod_params.amsdu_size != IWL_AMSDU_4K) ||
+            iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K)
                ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
 
        ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent;
index 270f39e..f08cdee 100644 (file)
@@ -384,7 +384,9 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define RFH_GEN_CFG    0xA09800
 #define RFH_GEN_CFG_SERVICE_DMA_SNOOP  BIT(0)
 #define RFH_GEN_CFG_RFH_DMA_SNOOP      BIT(1)
-#define RFH_GEN_CFG_RB_CHUNK_SIZE      BIT(4) /* 0 - 64B, 1- 128B */
+#define RFH_GEN_CFG_RB_CHUNK_SIZE_POS  4
+#define RFH_GEN_CFG_RB_CHUNK_SIZE_128  1
+#define RFH_GEN_CFG_RB_CHUNK_SIZE_64   0
 #define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00
 #define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8
 
index 37dc09e..4018e65 100644 (file)
@@ -301,7 +301,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
  * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
  * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload
  * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
- * @IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD
+ * @IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD: supports U-APSD on p2p interface when it
+ *     is standalone or with a BSS station interface in the same binding.
  * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
  * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
  *     sources for the MCC. This TLV bit is a future replacement to
@@ -312,6 +313,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
  * @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
  * @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
  * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
+ * @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA
+ *     countdown offloading. Beacon notifications are not sent to the host.
+ *     The fw also offloads TBTT alignment.
  * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
  *     antenna the beacon should be transmitted
  * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
@@ -347,7 +351,7 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT         = (__force iwl_ucode_tlv_capa_t)19,
        IWL_UCODE_TLV_CAPA_CSUM_SUPPORT                 = (__force iwl_ucode_tlv_capa_t)21,
        IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS           = (__force iwl_ucode_tlv_capa_t)22,
-       IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD         = (__force iwl_ucode_tlv_capa_t)26,
+       IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD                = (__force iwl_ucode_tlv_capa_t)26,
        IWL_UCODE_TLV_CAPA_BT_COEX_PLCR                 = (__force iwl_ucode_tlv_capa_t)28,
        IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC                = (__force iwl_ucode_tlv_capa_t)29,
        IWL_UCODE_TLV_CAPA_BT_COEX_RRC                  = (__force iwl_ucode_tlv_capa_t)30,
@@ -356,6 +360,7 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS            = (__force iwl_ucode_tlv_capa_t)65,
        IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT             = (__force iwl_ucode_tlv_capa_t)67,
        IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT       = (__force iwl_ucode_tlv_capa_t)68,
+       IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD         = (__force iwl_ucode_tlv_capa_t)70,
        IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION         = (__force iwl_ucode_tlv_capa_t)71,
        IWL_UCODE_TLV_CAPA_BEACON_STORING               = (__force iwl_ucode_tlv_capa_t)72,
        IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2               = (__force iwl_ucode_tlv_capa_t)73,
index 6c5c2f9..0379899 100644 (file)
@@ -87,9 +87,10 @@ enum iwl_disable_11n {
 };
 
 enum iwl_amsdu_size {
-       IWL_AMSDU_4K = 0,
-       IWL_AMSDU_8K = 1,
-       IWL_AMSDU_12K = 2,
+       IWL_AMSDU_DEF = 0,
+       IWL_AMSDU_4K = 1,
+       IWL_AMSDU_8K = 2,
+       IWL_AMSDU_12K = 3,
 };
 
 enum iwl_uapsd_disable {
@@ -105,7 +106,7 @@ enum iwl_uapsd_disable {
  * @sw_crypto: using hardware encryption, default = 0
  * @disable_11n: disable 11n capabilities, default = 0,
  *     use IWL_[DIS,EN]ABLE_HT_* constants
- * @amsdu_size: enable 8K amsdu size, default = 4K. enum iwl_amsdu_size.
+ * @amsdu_size: See &enum iwl_amsdu_size.
  * @restart_fw: restart firmware, default = 1
  * @bt_coex_active: enable bt coex, default = true
  * @led_mode: system default, default = 0
index 21653fe..43f8f7d 100644 (file)
@@ -397,6 +397,13 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
                vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
 
        switch (iwlwifi_mod_params.amsdu_size) {
+       case IWL_AMSDU_DEF:
+               if (cfg->mq_rx_supported)
+                       vht_cap->cap |=
+                               IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+               else
+                       vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
+               break;
        case IWL_AMSDU_4K:
                vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
                break;
index 8193d36..a45be1d 100644 (file)
@@ -211,6 +211,9 @@ struct iwl_cmd_header_wide {
 #define FH_RSCSR_FRAME_SIZE_MSK                0x00003FFF      /* bits 0-13 */
 #define FH_RSCSR_FRAME_INVALID         0x55550000
 #define FH_RSCSR_FRAME_ALIGN           0x40
+#define FH_RSCSR_RPA_EN                        BIT(25)
+#define FH_RSCSR_RXQ_POS               16
+#define FH_RSCSR_RXQ_MASK              0x3F0000
 
 struct iwl_rx_packet {
        /*
@@ -220,7 +223,13 @@ struct iwl_rx_packet {
         * 31:    flag flush RB request
         * 30:    flag ignore TC (terminal counter) request
         * 29:    flag fast IRQ request
-        * 28-14: Reserved
+        * 28-26: Reserved
+        * 25:    Offload enabled
+        * 24:    RPF enabled
+        * 23:    RSS enabled
+        * 22:    Checksum enabled
+        * 21-16: RX queue
+        * 15-14: Reserved
         * 13-00: RX frame size
         */
        __le32 len_n_flags;
index 1ca8e49..1994331 100644 (file)
@@ -336,6 +336,18 @@ enum iwl_rx_mpdu_reorder_data {
        IWL_RX_MPDU_REORDER_BA_OLD_SN           = 0x80000000,
 };
 
+enum iwl_rx_mpdu_phy_info {
+       IWL_RX_MPDU_PHY_AMPDU           = BIT(5),
+       IWL_RX_MPDU_PHY_AMPDU_TOGGLE    = BIT(6),
+       IWL_RX_MPDU_PHY_SHORT_PREAMBLE  = BIT(7),
+       IWL_RX_MPDU_PHY_TSF_OVERLOAD    = BIT(8),
+};
+
+enum iwl_rx_mpdu_mac_info {
+       IWL_RX_MPDU_PHY_MAC_INDEX_MASK          = 0x0f,
+       IWL_RX_MPDU_PHY_PHY_INDEX_MASK          = 0xf0,
+};
+
 struct iwl_rx_mpdu_desc {
        /* DW2 */
        __le16 mpdu_len;
@@ -343,9 +355,9 @@ struct iwl_rx_mpdu_desc {
        u8 mac_flags2;
        /* DW3 */
        u8 amsdu_info;
-       __le16 reserved_for_software;
+       __le16 phy_info;
        u8 mac_phy_idx;
-       /* DW4 */
+       /* DW4 - carries csum data only when rpa_en == 1 */
        __le16 raw_csum; /* alledgedly unreliable */
        __le16 l3l4_flags;
        /* DW5 */
@@ -354,17 +366,17 @@ struct iwl_rx_mpdu_desc {
        u8 sta_id_flags;
        /* DW6 */
        __le32 reorder_data;
-       /* DW7 */
+       /* DW7 - carries rss_hash only when rpa_en == 1 */
        __le32 rss_hash;
-       /* DW8 */
+       /* DW8 - carries filter_match only when rpa_en == 1 */
        __le32 filter_match;
        /* DW9 */
        __le32 rate_n_flags;
        /* DW10 */
-       u8 energy_a, energy_b, channel, reserved;
+       u8 energy_a, energy_b, channel, mac_context;
        /* DW11 */
        __le32 gp2_on_air_rise;
-       /* DW12 & DW13 */
+       /* DW12 & DW13 - carries TSF only TSF_OVERLOAD bit == 0 */
        __le64 tsf_on_air_rise;
 } __packed;
 
@@ -435,26 +447,26 @@ struct iwl_rxq_sync_notification {
 } __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
 
 /**
-* Internal message identifier
-*
-* @IWL_MVM_RXQ_EMPTY: empty sync notification
-* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
-*/
+ * Internal message identifier
+ *
+ * @IWL_MVM_RXQ_EMPTY: empty sync notification
+ * @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
+ */
 enum iwl_mvm_rxq_notif_type {
        IWL_MVM_RXQ_EMPTY,
        IWL_MVM_RXQ_NOTIF_DEL_BA,
 };
 
 /**
-* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
-* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
-* FW is agnostic to the payload, so there are no endianity requirements.
-*
-* @type: value from &iwl_mvm_rxq_notif_type
-* @sync: ctrl path is waiting for all notifications to be received
-* @cookie: internal cookie to identify old notifications
-* @data: payload
-*/
+ * struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
+ * in &iwl_rxq_sync_cmd. Should be DWORD aligned.
+ * FW is agnostic to the payload, so there are no endianity requirements.
+ *
+ * @type: value from &iwl_mvm_rxq_notif_type
+ * @sync: ctrl path is waiting for all notifications to be received
+ * @cookie: internal cookie to identify old notifications
+ * @data: payload
+ */
 struct iwl_mvm_internal_rxq_notif {
        u16 type;
        u16 sync;
index dadcccd..ee59511 100644 (file)
@@ -562,8 +562,8 @@ struct iwl_mvm_ba_notif {
        u8 reserved1;
 } __packed;
 
-/*
- * struct iwl_mac_beacon_cmd - beacon template command
+/**
+ * struct iwl_mac_beacon_cmd_v6 - beacon template command
  * @tx: the tx commands associated with the beacon frame
  * @template_id: currently equal to the mac context id of the coresponding
  *  mac.
@@ -571,13 +571,34 @@ struct iwl_mvm_ba_notif {
  * @tim_size: the length of the tim IE
  * @frame: the template of the beacon frame
  */
+struct iwl_mac_beacon_cmd_v6 {
+       struct iwl_tx_cmd tx;
+       __le32 template_id;
+       __le32 tim_idx;
+       __le32 tim_size;
+       struct ieee80211_hdr frame[0];
+} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_6 */
+
+/**
+ * struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA
+ * @tx: the tx commands associated with the beacon frame
+ * @template_id: currently equal to the mac context id of the coresponding
+ *  mac.
+ * @tim_idx: the offset of the tim IE in the beacon
+ * @tim_size: the length of the tim IE
+ * @ecsa_offset: offset to the ECSA IE if present
+ * @csa_offset: offset to the CSA IE if present
+ * @frame: the template of the beacon frame
+ */
 struct iwl_mac_beacon_cmd {
        struct iwl_tx_cmd tx;
        __le32 template_id;
        __le32 tim_idx;
        __le32 tim_size;
+       __le32 ecsa_offset;
+       __le32 csa_offset;
        struct ieee80211_hdr frame[0];
-} __packed;
+} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_7 */
 
 struct iwl_beacon_notif {
        struct iwl_mvm_tx_resp beacon_notify_hdr;
index 41b80ae..b06380d 100644 (file)
@@ -314,6 +314,7 @@ enum {
 enum iwl_mac_conf_subcmd_ids {
        LINK_QUALITY_MEASUREMENT_CMD = 0x1,
        LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE,
+       CHANNEL_SWITCH_NOA_NOTIF = 0xFF,
 };
 
 enum iwl_phy_ops_subcmd_ids {
@@ -732,7 +733,7 @@ enum iwl_time_event_type {
 
        /* P2P GO Events */
        TE_P2P_GO_ASSOC_PROT,
-       TE_P2P_GO_REPETITIVE_NOA,
+       TE_P2P_GO_REPETITIVET_NOA,
        TE_P2P_GO_CT_WINDOW,
 
        /* WiDi Sync Events */
@@ -2111,4 +2112,13 @@ struct iwl_link_qual_msrmnt_notif {
        __le32 reserved[3];
 } __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */
 
+/**
+ * Channel switch NOA notification
+ *
+ * @id_and_color: ID and color of the MAC
+ */
+struct iwl_channel_switch_noa_notif {
+       __le32 id_and_color;
+} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
+
 #endif /* __fw_api_h__ */
index 7aae068..69c42ce 100644 (file)
@@ -1006,7 +1006,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
 }
 
 static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
-                                    struct iwl_mac_beacon_cmd *beacon_cmd,
+                                    struct iwl_mac_beacon_cmd_v6 *beacon_cmd,
                                     u8 *beacon, u32 frame_size)
 {
        u32 tim_idx;
@@ -1030,6 +1030,23 @@ static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
        }
 }
 
+static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
+{
+       struct ieee80211_mgmt *mgmt = (void *)beacon;
+       const u8 *ie;
+
+       if (WARN_ON_ONCE(frame_size <= (mgmt->u.beacon.variable - beacon)))
+               return 0;
+
+       frame_size -= mgmt->u.beacon.variable - beacon;
+
+       ie = cfg80211_find_ie(eid, mgmt->u.beacon.variable, frame_size);
+       if (!ie)
+               return 0;
+
+       return ie - beacon;
+}
+
 static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif,
                                        struct sk_buff *beacon)
@@ -1039,7 +1056,10 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                .id = BEACON_TEMPLATE_CMD,
                .flags = CMD_ASYNC,
        };
-       struct iwl_mac_beacon_cmd beacon_cmd = {};
+       union {
+               struct iwl_mac_beacon_cmd_v6 beacon_cmd_v6;
+               struct iwl_mac_beacon_cmd beacon_cmd;
+       } u = {};
        struct ieee80211_tx_info *info;
        u32 beacon_skb_len;
        u32 rate, tx_flags;
@@ -1051,18 +1071,18 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
 
        /* TODO: for now the beacon template id is set to be the mac context id.
         * Might be better to handle it as another resource ... */
-       beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+       u.beacon_cmd_v6.template_id = cpu_to_le32((u32)mvmvif->id);
        info = IEEE80211_SKB_CB(beacon);
 
        /* Set up TX command fields */
-       beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
-       beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
-       beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
+       u.beacon_cmd_v6.tx.len = cpu_to_le16((u16)beacon_skb_len);
+       u.beacon_cmd_v6.tx.sta_id = mvmvif->bcast_sta.sta_id;
+       u.beacon_cmd_v6.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
        tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
        tx_flags |=
                iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) <<
                                                TX_CMD_FLG_BT_PRIO_POS;
-       beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
+       u.beacon_cmd_v6.tx.tx_flags = cpu_to_le32(tx_flags);
 
        if (!fw_has_capa(&mvm->fw->ucode_capa,
                         IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {
@@ -1071,7 +1091,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                                             mvm->mgmt_last_antenna_idx);
        }
 
-       beacon_cmd.tx.rate_n_flags =
+       u.beacon_cmd_v6.tx.rate_n_flags =
                cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
                            RATE_MCS_ANT_POS);
 
@@ -1079,20 +1099,37 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
                rate = IWL_FIRST_OFDM_RATE;
        } else {
                rate = IWL_FIRST_CCK_RATE;
-               beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK);
+               u.beacon_cmd_v6.tx.rate_n_flags |=
+                                       cpu_to_le32(RATE_MCS_CCK_MSK);
        }
-       beacon_cmd.tx.rate_n_flags |=
+       u.beacon_cmd_v6.tx.rate_n_flags |=
                cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate));
 
        /* Set up TX beacon command fields */
        if (vif->type == NL80211_IFTYPE_AP)
-               iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd,
+               iwl_mvm_mac_ctxt_set_tim(mvm, &u.beacon_cmd_v6,
                                         beacon->data,
                                         beacon_skb_len);
 
        /* Submit command */
-       cmd.len[0] = sizeof(beacon_cmd);
-       cmd.data[0] = &beacon_cmd;
+
+       if (fw_has_capa(&mvm->fw->ucode_capa,
+                       IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD)) {
+               u.beacon_cmd.csa_offset =
+                       cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data,
+                                                   WLAN_EID_CHANNEL_SWITCH,
+                                                   beacon_skb_len));
+               u.beacon_cmd.ecsa_offset =
+                       cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data,
+                                                   WLAN_EID_EXT_CHANSWITCH_ANN,
+                                                   beacon_skb_len));
+
+               cmd.len[0] = sizeof(u.beacon_cmd);
+       } else {
+               cmd.len[0] = sizeof(u.beacon_cmd_v6);
+       }
+
+       cmd.data[0] = &u;
        cmd.dataflags[0] = 0;
        cmd.len[1] = beacon_skb_len;
        cmd.data[1] = beacon->data;
@@ -1538,3 +1575,48 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
        /* pass it as regular rx to mac80211 */
        ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);
 }
+
+void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
+                                     struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data;
+       struct ieee80211_vif *csa_vif;
+       struct iwl_mvm_vif *mvmvif;
+       int len = iwl_rx_packet_payload_len(pkt);
+       u32 id_n_color;
+
+       if (WARN_ON_ONCE(len < sizeof(*notif)))
+               return;
+
+       rcu_read_lock();
+
+       csa_vif = rcu_dereference(mvm->csa_vif);
+       if (WARN_ON(!csa_vif || !csa_vif->csa_active))
+               goto out_unlock;
+
+       id_n_color = le32_to_cpu(notif->id_and_color);
+
+       mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
+       if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color,
+                "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
+                FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color))
+               goto out_unlock;
+
+       IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
+
+       queue_delayed_work(system_wq, &mvm->cs_tx_unblock_dwork,
+                          msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
+                                           csa_vif->bss_conf.beacon_int));
+
+       ieee80211_csa_finish(csa_vif);
+
+       rcu_read_unlock();
+
+       RCU_INIT_POINTER(mvm->csa_vif, NULL);
+
+       return;
+
+out_unlock:
+       rcu_read_unlock();
+}
index e5f267b..e5cb7db 100644 (file)
@@ -1199,6 +1199,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
        flush_work(&mvm->async_handlers_wk);
        flush_work(&mvm->add_stream_wk);
        cancel_delayed_work_sync(&mvm->fw_dump_wk);
+       cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);
        iwl_mvm_free_fw_dump_desc(mvm);
 
        mutex_lock(&mvm->mutex);
@@ -2360,7 +2361,7 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
                return;
 
-       if (vif->p2p && !iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) {
+       if (vif->p2p && !iwl_mvm_is_p2p_scm_uapsd_supported(mvm)) {
                vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
                return;
        }
@@ -3687,6 +3688,13 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
                        goto out_unlock;
                }
 
+               /* we still didn't unblock tx. prevent new CS meanwhile */
+               if (rcu_dereference_protected(mvm->csa_tx_blocked_vif,
+                                             lockdep_is_held(&mvm->mutex))) {
+                       ret = -EBUSY;
+                       goto out_unlock;
+               }
+
                rcu_assign_pointer(mvm->csa_vif, vif);
 
                if (WARN_ONCE(mvmvif->csa_countdown,
@@ -3695,6 +3703,8 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
                        goto out_unlock;
                }
 
+               mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;
+
                break;
        case NL80211_IFTYPE_STATION:
                if (mvmvif->lqm_active)
index ffbd41d..4b75b92 100644 (file)
@@ -452,6 +452,7 @@ struct iwl_mvm_vif {
        /* Indicates that CSA countdown may be started */
        bool csa_countdown;
        bool csa_failed;
+       u16 csa_target_freq;
 
        /* TCP Checksum Offload */
        netdev_features_t features;
@@ -731,6 +732,7 @@ struct iwl_mvm {
        struct iwl_sf_region sf_space;
 
        u32 ampdu_ref;
+       bool ampdu_toggle;
 
        struct iwl_notif_wait_data notif_wait;
 
@@ -1006,6 +1008,8 @@ struct iwl_mvm {
         * clients.
         */
        bool drop_bcn_ap_mode;
+
+       struct delayed_work cs_tx_unblock_dwork;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -1158,10 +1162,10 @@ static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
 }
 
 static inline
-bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm)
+bool iwl_mvm_is_p2p_scm_uapsd_supported(struct iwl_mvm *mvm)
 {
        return fw_has_capa(&mvm->fw->ucode_capa,
-                          IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD) &&
+                          IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD) &&
                !(iwlwifi_mod_params.uapsd_disable &
                  IWL_DISABLE_UAPSD_P2P_CLIENT);
 }
@@ -1321,7 +1325,6 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
 void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
                        struct iwl_rx_cmd_buffer *rxb);
-void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                        struct iwl_rx_cmd_buffer *rxb, int queue);
 void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
@@ -1381,6 +1384,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif);
 unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
                                         struct ieee80211_vif *exclude_vif);
+void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
+                                     struct iwl_rx_cmd_buffer *rxb);
 /* Bindings */
 int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
index a68054f..632b1dc 100644 (file)
@@ -431,6 +431,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
 static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
        HCMD_NAME(LINK_QUALITY_MEASUREMENT_CMD),
        HCMD_NAME(LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF),
+       HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
 };
 
 /* Please keep this array *SORTED* by hex value.
@@ -494,6 +495,29 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
 
 static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
 
+static void iwl_mvm_tx_unblock_dwork(struct work_struct *work)
+{
+       struct iwl_mvm *mvm =
+               container_of(work, struct iwl_mvm, cs_tx_unblock_dwork.work);
+       struct ieee80211_vif *tx_blocked_vif;
+       struct iwl_mvm_vif *mvmvif;
+
+       mutex_lock(&mvm->mutex);
+
+       tx_blocked_vif =
+               rcu_dereference_protected(mvm->csa_tx_blocked_vif,
+                                         lockdep_is_held(&mvm->mutex));
+
+       if (!tx_blocked_vif)
+               goto unlock;
+
+       mvmvif = iwl_mvm_vif_from_mac80211(tx_blocked_vif);
+       iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false);
+       RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);
+unlock:
+       mutex_unlock(&mvm->mutex);
+}
+
 static struct iwl_op_mode *
 iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                      const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -595,6 +619,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
 
+       INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork);
+
        /*
         * Populate the state variables that the transport layer needs
         * to know about.
@@ -603,6 +629,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
        trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
        switch (iwlwifi_mod_params.amsdu_size) {
+       case IWL_AMSDU_DEF:
        case IWL_AMSDU_4K:
                trans_cfg.rx_buf_size = IWL_AMSDU_4K;
                break;
@@ -617,6 +644,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                       iwlwifi_mod_params.amsdu_size);
                trans_cfg.rx_buf_size = IWL_AMSDU_4K;
        }
+
+       /* the hardware splits the A-MSDU */
+       if (mvm->cfg->mq_rx_supported)
+               trans_cfg.rx_buf_size = IWL_AMSDU_4K;
        trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
                                               IWL_UCODE_TLV_API_WIDE_CMD_HDR);
 
@@ -936,8 +967,6 @@ static void iwl_mvm_rx(struct iwl_op_mode *op_mode,
 
        if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
                iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
-       else if (pkt->hdr.cmd == FRAME_RELEASE)
-               iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
        else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
                iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
        else
@@ -953,11 +982,11 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
 
        if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
                iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
-       else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
-               iwl_mvm_rx_phy_cmd_mq(mvm, rxb);
        else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP &&
                          pkt->hdr.cmd == RX_QUEUES_NOTIFICATION))
                iwl_mvm_rx_queue_notif(mvm, rxb, 0);
+       else if (pkt->hdr.cmd == FRAME_RELEASE)
+               iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
        else
                iwl_mvm_rx_common(mvm, rxb, pkt);
 }
index 7b1f6ad..ff85865 100644 (file)
@@ -308,7 +308,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
                /* Allow U-APSD only if p2p is stand alone */
                bool is_p2p_standalone = true;
 
-               if (!iwl_mvm_is_p2p_standalone_uapsd_supported(mvm))
+               if (!iwl_mvm_is_p2p_scm_uapsd_supported(mvm))
                        return false;
 
                ieee80211_iterate_active_interfaces_atomic(mvm->hw,
index ab7f7ed..6d096b6 100644 (file)
@@ -354,13 +354,22 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
 
        if (sta) {
                struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+               struct ieee80211_vif *tx_blocked_vif =
+                       rcu_dereference(mvm->csa_tx_blocked_vif);
 
                /* We have tx blocked stations (with CS bit). If we heard
                 * frames from a blocked station on a new channel we can
                 * TX to it again.
                 */
-               if (unlikely(mvm->csa_tx_block_bcn_timeout))
-                       iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
+               if (unlikely(tx_blocked_vif) &&
+                   mvmsta->vif == tx_blocked_vif) {
+                       struct iwl_mvm_vif *mvmvif =
+                               iwl_mvm_vif_from_mac80211(tx_blocked_vif);
+
+                       if (mvmvif->csa_target_freq == rx_status->freq)
+                               iwl_mvm_sta_modify_disable_tx_ap(mvm, sta,
+                                                                false);
+               }
 
                rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
 
index ac2c571..d13397a 100644 (file)
 #include "fw-api.h"
 #include "fw-dbg.h"
 
-void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
-{
-       mvm->ampdu_ref++;
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
-               spin_lock(&mvm->drv_stats_lock);
-               mvm->drv_rx_stats.ampdu_count++;
-               spin_unlock(&mvm->drv_stats_lock);
-       }
-#endif
-}
-
 static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
                                   int queue, struct ieee80211_sta *sta)
 {
@@ -587,6 +574,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
        struct sk_buff *tail;
        u32 reorder = le32_to_cpu(desc->reorder_data);
        bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
+       bool last_subframe =
+               desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
        u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
        u8 sub_frame_idx = desc->amsdu_info &
                           IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
@@ -651,7 +640,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
        /* release immediately if allowed by nssn and no stored frames */
        if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
                if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
-                                      buffer->buf_size))
+                                      buffer->buf_size) &&
+                  (!amsdu || last_subframe))
                        buffer->head_sn = nssn;
                /* No need to update AMSDU last SN - we are moving the head */
                spin_unlock_bh(&buffer->lock);
@@ -685,7 +675,20 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
                buffer->last_sub_index = sub_frame_idx;
        }
 
-       iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
+       /*
+        * We cannot trust NSSN for AMSDU sub-frames that are not the last.
+        * The reason is that NSSN advances on the first sub-frame, and may
+        * cause the reorder buffer to advance before all the sub-frames arrive.
+        * Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with
+        * SN 1. NSSN for first sub frame will be 3 with the result of driver
+        * releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is
+        * already ahead and it will be dropped.
+        * If the last sub-frame is not on this queue - we will get frame
+        * release notification with up to date NSSN.
+        */
+       if (!amsdu || last_subframe)
+               iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
+
        spin_unlock_bh(&buffer->lock);
        return true;
 
@@ -734,6 +737,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
        struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc));
        u32 len = le16_to_cpu(desc->mpdu_len);
        u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
+       u16 phy_info = le16_to_cpu(desc->phy_info);
        struct ieee80211_sta *sta = NULL;
        struct sk_buff *skb;
        u8 crypt_len = 0;
@@ -764,16 +768,34 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                             le16_to_cpu(desc->status));
                rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
        }
-
-       rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
+       /* set the preamble flag if appropriate */
+       if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
+               rx_status->flag |= RX_FLAG_SHORTPRE;
+
+       if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {
+               rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
+               /* TSF as indicated by the firmware is at INA time */
+               rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
+       }
        rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise);
        rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ :
                                               NL80211_BAND_2GHZ;
        rx_status->freq = ieee80211_channel_to_frequency(desc->channel,
                                                         rx_status->band);
        iwl_mvm_get_signal_strength(mvm, desc, rx_status);
-       /* TSF as indicated by the firmware is at INA time */
-       rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
+
+       /* update aggregation data for monitor sake on default queue */
+       if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
+               bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
+
+               rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
+               rx_status->ampdu_reference = mvm->ampdu_ref;
+               /* toggle is switched whenever new aggregation starts */
+               if (toggle_bit != mvm->ampdu_toggle) {
+                       mvm->ampdu_ref++;
+                       mvm->ampdu_toggle = toggle_bit;
+               }
+       }
 
        rcu_read_lock();
 
@@ -795,6 +817,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
 
        if (sta) {
                struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+               struct ieee80211_vif *tx_blocked_vif =
+                       rcu_dereference(mvm->csa_tx_blocked_vif);
                u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
                               IWL_RX_MPDU_REORDER_BAID_MASK) >>
                               IWL_RX_MPDU_REORDER_BAID_SHIFT);
@@ -804,8 +828,15 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                 * frames from a blocked station on a new channel we can
                 * TX to it again.
                 */
-               if (unlikely(mvm->csa_tx_block_bcn_timeout))
-                       iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
+               if (unlikely(tx_blocked_vif) &&
+                   tx_blocked_vif == mvmsta->vif) {
+                       struct iwl_mvm_vif *mvmvif =
+                               iwl_mvm_vif_from_mac80211(tx_blocked_vif);
+
+                       if (mvmvif->csa_target_freq == rx_status->freq)
+                               iwl_mvm_sta_modify_disable_tx_ap(mvm, sta,
+                                                                false);
+               }
 
                rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
 
@@ -828,8 +859,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                                iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL);
                }
 
-               /* TODO: multi queue TCM */
-
                if (ieee80211_is_data(hdr->frame_control))
                        iwl_mvm_rx_csum(sta, skb, desc);
 
@@ -854,14 +883,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                        iwl_mvm_agg_rx_received(mvm, baid);
        }
 
-       /*
-        * TODO: PHY info.
-        * Verify we don't have the information in the MPDU descriptor and
-        * that it is not needed.
-        * Make sure for monitor mode that we are on default queue, update
-        * ampdu_ref and the rest of phy info then
-        */
-
        /* Set up the HT phy flags */
        switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
        case RATE_MCS_CHAN_WIDTH_20:
@@ -905,8 +926,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                                                            rx_status->band);
        }
 
-       /* TODO: PHY info - update ampdu queue statistics (for debugfs) */
-       /* TODO: PHY info - gscan */
+       /* management stuff on default queue */
+       if (!queue) {
+               if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
+                             ieee80211_is_probe_resp(hdr->frame_control)) &&
+                            mvm->sched_scan_pass_all ==
+                            SCHED_SCAN_PASS_ALL_ENABLED))
+                       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
+
+               if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
+                            ieee80211_is_probe_resp(hdr->frame_control)))
+                       rx_status->boottime_ns = ktime_get_boot_ns();
+       }
 
        iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
        if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
index fea4d34..64b07b1 100644 (file)
@@ -819,8 +819,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
        if (iwl_mvm_has_new_rx_api(mvm))
                kfree(mvm_sta->dup_data);
 
-       if (vif->type == NL80211_IFTYPE_STATION &&
-           mvmvif->ap_sta_id == mvm_sta->sta_id) {
+       if ((vif->type == NL80211_IFTYPE_STATION &&
+            mvmvif->ap_sta_id == mvm_sta->sta_id) ||
+           iwl_mvm_is_dqa_supported(mvm)){
                ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
                if (ret)
                        return ret;
index de6974f..482836e 100644 (file)
@@ -673,4 +673,6 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
 int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans);
 int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans);
 
+void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable);
+
 #endif /* __iwl_trans_int_pcie_h__ */
index 0a4a3c5..70e39e4 100644 (file)
@@ -211,12 +211,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
        if (trans->cfg->mq_rx_supported)
                iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id),
                            rxq->write_actual);
-       /*
-        * write to FH_RSCSR_CHNL0_WPTR register even in MQ as a W/A to
-        * hardware shadow registers bug - writing to RFH_Q_FRBDCB_WIDX will
-        * not wake the NIC.
-        */
-       iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
+       else
+               iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
 }
 
 static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
@@ -764,6 +760,23 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
                iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE);
 }
 
+void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable)
+{
+       /*
+        * Turn on the chicken-bits that cause MAC wakeup for RX-related
+        * values.
+        * This costs some power, but needed for W/A 9000 integrated A-step
+        * bug where shadow registers are not in the retention list and their
+        * value is lost when NIC powers down
+        */
+       if (trans->cfg->integrated) {
+               iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
+                           CSR_MAC_SHADOW_REG_CTRL_RX_WAKE);
+               iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2,
+                           CSR_MAC_SHADOW_REG_CTL2_RX_WAKE);
+       }
+}
+
 static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -820,28 +833,30 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
 
        /*
         * Enable Rx DMA
-        * Single frame mode
         * Rx buffer size 4 or 8k or 12k
         * Min RB size 4 or 8
         * Drop frames that exceed RB size
         * 512 RBDs
         */
        iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG,
-                              RFH_DMA_EN_ENABLE_VAL |
-                              rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK |
+                              RFH_DMA_EN_ENABLE_VAL | rb_size |
                               RFH_RXF_DMA_MIN_RB_4_8 |
                               RFH_RXF_DMA_DROP_TOO_LARGE_MASK |
                               RFH_RXF_DMA_RBDCB_SIZE_512);
 
        /*
         * Activate DMA snooping.
-        * Set RX DMA chunk size to 64B
+        * Set RX DMA chunk size to 64B for IOSF and 128B for PCIe
         * Default queue is 0
         */
        iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
                               (DEFAULT_RXQ_NUM <<
                                RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
-                              RFH_GEN_CFG_SERVICE_DMA_SNOOP);
+                              RFH_GEN_CFG_SERVICE_DMA_SNOOP |
+                              (trans->cfg->integrated ?
+                               RFH_GEN_CFG_RB_CHUNK_SIZE_64 :
+                               RFH_GEN_CFG_RB_CHUNK_SIZE_128) <<
+                              RFH_GEN_CFG_RB_CHUNK_SIZE_POS);
        /* Enable the relevant rx queues */
        iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled);
 
@@ -849,6 +864,8 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
 
        /* Set interrupt coalescing timer to default (2048 usecs) */
        iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+
+       iwl_pcie_enable_rx_wake(trans, true);
 }
 
 static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
@@ -1087,6 +1104,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
                        break;
 
+               WARN_ON((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >>
+                       FH_RSCSR_RXQ_POS != rxq->id);
+
                IWL_DEBUG_RX(trans,
                             "cmd at offset %d: %s (0x%.2x, seq 0x%x)\n",
                             rxcb._offset,
index f603d78..33fd217 100644 (file)
@@ -1286,6 +1286,8 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test,
        iwl_clear_bit(trans, CSR_GP_CNTRL,
                      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
+       iwl_pcie_enable_rx_wake(trans, false);
+
        if (reset) {
                /*
                 * reset TX queues -- some of their registers reset during S3
@@ -1311,6 +1313,8 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                return 0;
        }
 
+       iwl_pcie_enable_rx_wake(trans, true);
+
        /*
         * Also enables interrupts - none will happen as the device doesn't
         * know we're waking it up, only when the opmode actually tells it