Merge tag 'iwlwifi-next-for-kalle-2015-12-21' of https://git.kernel.org/pub/scm/linux...
authorKalle Valo <kvalo@codeaurora.org>
Tue, 29 Dec 2015 16:44:19 +0000 (18:44 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 29 Dec 2015 16:44:19 +0000 (18:44 +0200)
* Make scan parameters low latency aware (Avi Stern)
* Fix in the NL80211_FEATURE_FULL_AP_CLIENT_STATE state case (Ayala)
* Fix enable injection mode (Chaya Rachel)
* Various cleanups (Dan / Julia / myself)
* Allow to stay more time on popular channels (David Spinadel)
* Bug fixes for D0i3 (Eliad / Luca)
* Fixes for GO uAPSD (myself)
* Start of TSO support (myself)
* Rate control bug fixes (Eyal / Gregory)
* Start the work on 9000 devices (Johannes / Sara / Oren)
* Start the work on a new Tx queue allocation model (Liad)
* Debug infrastructure enhancements (Golan)

82 files changed:
drivers/net/wireless/intel/iwlwifi/dvm/agn.h
drivers/net/wireless/intel/iwlwifi/dvm/calib.c
drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/dvm/dev.h
drivers/net/wireless/intel/iwlwifi/dvm/led.h
drivers/net/wireless/intel/iwlwifi/dvm/lib.c
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/dvm/main.c
drivers/net/wireless/intel/iwlwifi/dvm/rs.c
drivers/net/wireless/intel/iwlwifi/dvm/rs.h
drivers/net/wireless/intel/iwlwifi/dvm/rx.c
drivers/net/wireless/intel/iwlwifi/dvm/rxon.c
drivers/net/wireless/intel/iwlwifi/dvm/scan.c
drivers/net/wireless/intel/iwlwifi/dvm/sta.c
drivers/net/wireless/intel/iwlwifi/dvm/tt.c
drivers/net/wireless/intel/iwlwifi/dvm/tt.h
drivers/net/wireless/intel/iwlwifi/dvm/tx.c
drivers/net/wireless/intel/iwlwifi/iwl-7000.c
drivers/net/wireless/intel/iwlwifi/iwl-8000.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-debug.c
drivers/net/wireless/intel/iwlwifi/iwl-debug.h
drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.h
drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
drivers/net/wireless/intel/iwlwifi/iwl-io.c
drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
drivers/net/wireless/intel/iwlwifi/iwl-phy-db.c
drivers/net/wireless/intel/iwlwifi/iwl-phy-db.h
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/Makefile
drivers/net/wireless/intel/iwlwifi/mvm/coex.c
drivers/net/wireless/intel/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/intel/iwlwifi/mvm/constants.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
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/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/power.c
drivers/net/wireless/intel/iwlwifi/mvm/quota.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.h
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c [new file with mode: 0644]
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/intel/iwlwifi/mvm/time-event.h
drivers/net/wireless/intel/iwlwifi/mvm/tof.c
drivers/net/wireless/intel/iwlwifi/mvm/tof.h
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/mvm/utils.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.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
drivers/net/wireless/intel/iwlwifi/pcie/tx.c

index 991def8..9de277c 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -473,13 +473,4 @@ do {                                                                       \
 } while (0)
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
-extern const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1];
-
-static inline const char *iwl_dvm_get_cmd_string(u8 cmd)
-{
-       const char *s = iwl_dvm_cmd_strings[cmd];
-       if (s)
-               return s;
-       return "UNKNOWN";
-}
 #endif /* __iwl_agn_h__ */
index 9be6362..07a4c64 100644 (file)
@@ -311,7 +311,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
                /* If previous beacon had too many false alarms,
                 *   give it some extra margin by reducing sensitivity again
                 *   (but don't go below measured energy of desired Rx) */
-               if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+               if (data->nrg_prev_state == IWL_FA_TOO_MANY) {
                        IWL_DEBUG_CALIB(priv, "... increasing margin\n");
                        if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
                                data->nrg_th_cck -= NRG_MARGIN;
index b15e44f..74c5161 100644 (file)
@@ -22,7 +22,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 
@@ -32,7 +32,9 @@
 #include <linux/debugfs.h>
 #include <linux/ieee80211.h>
 #include <net/mac80211.h>
+
 #include "iwl-debug.h"
+#include "iwl-trans.h"
 #include "iwl-io.h"
 #include "dev.h"
 #include "agn.h"
@@ -438,7 +440,7 @@ static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file,
                if (priv->rx_handlers_stats[cnt] > 0)
                        pos += scnprintf(buf + pos, bufsz - pos,
                                "\tRx handler[%36s]:\t\t %u\n",
-                               iwl_dvm_get_cmd_string(cnt),
+                               iwl_get_cmd_string(priv->trans, (u32)cnt),
                                priv->rx_handlers_stats[cnt]);
        }
 
index 0ba3e56..1a7ead7 100644 (file)
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index 1c6b225..75f74ed 100644 (file)
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index a612fbe..bee1c03 100644 (file)
@@ -1262,7 +1262,7 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
        if (test_bit(STATUS_FW_ERROR, &priv->status)) {
                IWL_ERR(priv, "Command %s failed: FW Error\n",
-                       iwl_dvm_get_cmd_string(cmd->id));
+                       iwl_get_cmd_string(priv->trans, cmd->id));
                return -EIO;
        }
 
index a9d8b51..29ea1c6 100644 (file)
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -115,6 +115,9 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
        ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
        ieee80211_hw_set(hw, WANT_MONITOR_VIF);
 
+       if (priv->trans->max_skb_frags)
+               hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
+
        hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
        hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FMT;
 
index 41f3aa1..f62c2d7 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -22,7 +23,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -69,6 +70,93 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search.
+ * A warning will be triggered on violation.
+ */
+static const struct iwl_hcmd_names iwl_dvm_cmd_names[] = {
+       HCMD_NAME(REPLY_ALIVE),
+       HCMD_NAME(REPLY_ERROR),
+       HCMD_NAME(REPLY_ECHO),
+       HCMD_NAME(REPLY_RXON),
+       HCMD_NAME(REPLY_RXON_ASSOC),
+       HCMD_NAME(REPLY_QOS_PARAM),
+       HCMD_NAME(REPLY_RXON_TIMING),
+       HCMD_NAME(REPLY_ADD_STA),
+       HCMD_NAME(REPLY_REMOVE_STA),
+       HCMD_NAME(REPLY_REMOVE_ALL_STA),
+       HCMD_NAME(REPLY_TX),
+       HCMD_NAME(REPLY_TXFIFO_FLUSH),
+       HCMD_NAME(REPLY_WEPKEY),
+       HCMD_NAME(REPLY_LEDS_CMD),
+       HCMD_NAME(REPLY_TX_LINK_QUALITY_CMD),
+       HCMD_NAME(COEX_PRIORITY_TABLE_CMD),
+       HCMD_NAME(COEX_MEDIUM_NOTIFICATION),
+       HCMD_NAME(COEX_EVENT_CMD),
+       HCMD_NAME(TEMPERATURE_NOTIFICATION),
+       HCMD_NAME(CALIBRATION_CFG_CMD),
+       HCMD_NAME(CALIBRATION_RES_NOTIFICATION),
+       HCMD_NAME(CALIBRATION_COMPLETE_NOTIFICATION),
+       HCMD_NAME(REPLY_QUIET_CMD),
+       HCMD_NAME(REPLY_CHANNEL_SWITCH),
+       HCMD_NAME(CHANNEL_SWITCH_NOTIFICATION),
+       HCMD_NAME(REPLY_SPECTRUM_MEASUREMENT_CMD),
+       HCMD_NAME(SPECTRUM_MEASURE_NOTIFICATION),
+       HCMD_NAME(POWER_TABLE_CMD),
+       HCMD_NAME(PM_SLEEP_NOTIFICATION),
+       HCMD_NAME(PM_DEBUG_STATISTIC_NOTIFIC),
+       HCMD_NAME(REPLY_SCAN_CMD),
+       HCMD_NAME(REPLY_SCAN_ABORT_CMD),
+       HCMD_NAME(SCAN_START_NOTIFICATION),
+       HCMD_NAME(SCAN_RESULTS_NOTIFICATION),
+       HCMD_NAME(SCAN_COMPLETE_NOTIFICATION),
+       HCMD_NAME(BEACON_NOTIFICATION),
+       HCMD_NAME(REPLY_TX_BEACON),
+       HCMD_NAME(WHO_IS_AWAKE_NOTIFICATION),
+       HCMD_NAME(REPLY_TX_POWER_DBM_CMD),
+       HCMD_NAME(QUIET_NOTIFICATION),
+       HCMD_NAME(REPLY_TX_PWR_TABLE_CMD),
+       HCMD_NAME(REPLY_TX_POWER_DBM_CMD_V1),
+       HCMD_NAME(TX_ANT_CONFIGURATION_CMD),
+       HCMD_NAME(MEASURE_ABORT_NOTIFICATION),
+       HCMD_NAME(REPLY_BT_CONFIG),
+       HCMD_NAME(REPLY_STATISTICS_CMD),
+       HCMD_NAME(STATISTICS_NOTIFICATION),
+       HCMD_NAME(REPLY_CARD_STATE_CMD),
+       HCMD_NAME(CARD_STATE_NOTIFICATION),
+       HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
+       HCMD_NAME(REPLY_CT_KILL_CONFIG_CMD),
+       HCMD_NAME(SENSITIVITY_CMD),
+       HCMD_NAME(REPLY_PHY_CALIBRATION_CMD),
+       HCMD_NAME(REPLY_WIPAN_PARAMS),
+       HCMD_NAME(REPLY_WIPAN_RXON),
+       HCMD_NAME(REPLY_WIPAN_RXON_TIMING),
+       HCMD_NAME(REPLY_WIPAN_RXON_ASSOC),
+       HCMD_NAME(REPLY_WIPAN_QOS_PARAM),
+       HCMD_NAME(REPLY_WIPAN_WEPKEY),
+       HCMD_NAME(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
+       HCMD_NAME(REPLY_WIPAN_NOA_NOTIFICATION),
+       HCMD_NAME(REPLY_WIPAN_DEACTIVATION_COMPLETE),
+       HCMD_NAME(REPLY_RX_PHY_CMD),
+       HCMD_NAME(REPLY_RX_MPDU_CMD),
+       HCMD_NAME(REPLY_RX),
+       HCMD_NAME(REPLY_COMPRESSED_BA),
+       HCMD_NAME(REPLY_BT_COEX_PRIO_TABLE),
+       HCMD_NAME(REPLY_BT_COEX_PROT_ENV),
+       HCMD_NAME(REPLY_BT_COEX_PROFILE_NOTIF),
+       HCMD_NAME(REPLY_D3_CONFIG),
+       HCMD_NAME(REPLY_WOWLAN_PATTERNS),
+       HCMD_NAME(REPLY_WOWLAN_WAKEUP_FILTER),
+       HCMD_NAME(REPLY_WOWLAN_TSC_RSC_PARAMS),
+       HCMD_NAME(REPLY_WOWLAN_TKIP_PARAMS),
+       HCMD_NAME(REPLY_WOWLAN_KEK_KCK_MATERIAL),
+       HCMD_NAME(REPLY_WOWLAN_GET_STATUS),
+};
+
+static const struct iwl_hcmd_arr iwl_dvm_groups[] = {
+       [0x0] = HCMD_ARR(iwl_dvm_cmd_names),
+};
+
 static const struct iwl_op_mode_ops iwl_dvm_ops;
 
 void iwl_update_chain_flags(struct iwl_priv *priv)
@@ -341,7 +429,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
                ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32));
 
        /* Make sure device is powered up for SRAM reads */
-       if (!iwl_trans_grab_nic_access(priv->trans, false, &reg_flags))
+       if (!iwl_trans_grab_nic_access(priv->trans, &reg_flags))
                return;
 
        /* Set starting address; reads will auto-increment */
@@ -1244,7 +1332,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
 
        trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED;
 
-       trans_cfg.command_names = iwl_dvm_cmd_strings;
+       trans_cfg.command_groups = iwl_dvm_groups;
+       trans_cfg.command_groups_size = ARRAY_SIZE(iwl_dvm_groups);
+
        trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM;
 
        WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE <
@@ -1265,6 +1355,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
 
        trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
        trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
+       trans->command_groups = trans_cfg.command_groups;
+       trans->command_groups_size = trans_cfg.command_groups_size;
 
        /* At this point both hw and priv are allocated. */
 
@@ -1639,7 +1731,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
        ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
 
        /* Make sure device is powered up for SRAM reads */
-       if (!iwl_trans_grab_nic_access(trans, false, &reg_flags))
+       if (!iwl_trans_grab_nic_access(trans, &reg_flags))
                return pos;
 
        /* Set starting address; reads will auto-increment */
index cef921c..ee75055 100644 (file)
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index f6bd25c..c5fe445 100644 (file)
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index 4a45b0b..52ab1e0 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portionhelp of the ieee80211 subsystem header files.
@@ -22,7 +23,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
 #include <linux/sched.h>
 #include <net/mac80211.h>
 #include <asm/unaligned.h>
+
+#include "iwl-trans.h"
 #include "iwl-io.h"
 #include "dev.h"
 #include "calib.h"
 #include "agn.h"
 
-#define IWL_CMD_ENTRY(x) [x] = #x
-
-const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1] = {
-       IWL_CMD_ENTRY(REPLY_ALIVE),
-       IWL_CMD_ENTRY(REPLY_ERROR),
-       IWL_CMD_ENTRY(REPLY_ECHO),
-       IWL_CMD_ENTRY(REPLY_RXON),
-       IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
-       IWL_CMD_ENTRY(REPLY_QOS_PARAM),
-       IWL_CMD_ENTRY(REPLY_RXON_TIMING),
-       IWL_CMD_ENTRY(REPLY_ADD_STA),
-       IWL_CMD_ENTRY(REPLY_REMOVE_STA),
-       IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
-       IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
-       IWL_CMD_ENTRY(REPLY_WEPKEY),
-       IWL_CMD_ENTRY(REPLY_TX),
-       IWL_CMD_ENTRY(REPLY_LEDS_CMD),
-       IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
-       IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
-       IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
-       IWL_CMD_ENTRY(COEX_EVENT_CMD),
-       IWL_CMD_ENTRY(REPLY_QUIET_CMD),
-       IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
-       IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
-       IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
-       IWL_CMD_ENTRY(POWER_TABLE_CMD),
-       IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
-       IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
-       IWL_CMD_ENTRY(REPLY_SCAN_CMD),
-       IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
-       IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
-       IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
-       IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
-       IWL_CMD_ENTRY(BEACON_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_TX_BEACON),
-       IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
-       IWL_CMD_ENTRY(QUIET_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
-       IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_BT_CONFIG),
-       IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
-       IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
-       IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
-       IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
-       IWL_CMD_ENTRY(SENSITIVITY_CMD),
-       IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
-       IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
-       IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
-       IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
-       IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
-       IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
-       IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
-       IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
-       IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
-       IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
-       IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
-       IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
-       IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
-       IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
-       IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
-       IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
-       IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
-       IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
-       IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
-       IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
-       IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
-       IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
-       IWL_CMD_ENTRY(REPLY_D3_CONFIG),
-};
-#undef IWL_CMD_ENTRY
-
 /******************************************************************************
  *
  * Generic RX handler implementations
@@ -1095,7 +1018,9 @@ void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct napi_struct *napi,
        } else {
                /* No handling needed */
                IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
-                            iwl_dvm_get_cmd_string(pkt->hdr.cmd),
+                            iwl_get_cmd_string(priv->trans,
+                                               iwl_cmd_id(pkt->hdr.cmd,
+                                                          0, 0)),
                             pkt->hdr.cmd);
        }
 }
index 85ceceb..2d47cb2 100644 (file)
@@ -20,7 +20,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index 6481594..81a2ddb 100644 (file)
@@ -22,7 +22,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 #include <linux/slab.h>
index 0fa67d3..8e9768a 100644 (file)
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index c4736c8..5b73492 100644 (file)
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 
@@ -184,7 +184,7 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data)
                        priv->thermal_throttle.ct_kill_toggle = true;
                }
                iwl_read32(priv->trans, CSR_UCODE_DRV_GP1);
-               if (iwl_trans_grab_nic_access(priv->trans, false, &flags))
+               if (iwl_trans_grab_nic_access(priv->trans, &flags))
                        iwl_trans_release_nic_access(priv->trans, &flags);
 
                /* Reschedule the ct_kill timer to occur in
index 5077265..d324e9b 100644 (file)
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *****************************************************************************/
 #ifndef __iwl_tt_setting_h__
index bddd197..59e2001 100644 (file)
@@ -22,7 +22,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -383,6 +383,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
        iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, sta, fc);
 
        memset(&info->status, 0, sizeof(info->status));
+       memset(info->driver_data, 0, sizeof(info->driver_data));
 
        info->driver_data[0] = ctx;
        info->driver_data[1] = dev_cmd;
index 51fec20..fd9064b 100644 (file)
@@ -27,7 +27,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX  19
+#define IWL7260_UCODE_API_MAX  17
+#define IWL7265_UCODE_API_MAX  19
+#define IWL7265D_UCODE_API_MAX 19
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   13
+#define IWL7265_UCODE_API_OK   13
+#define IWL7265D_UCODE_API_OK  13
 
 /* Lowest firmware API version supported */
 #define IWL7260_UCODE_API_MIN  13
+#define IWL7265_UCODE_API_MIN  13
+#define IWL7265D_UCODE_API_MIN 13
 
 /* NVM versions */
 #define IWL7260_NVM_VERSION            0x0a1d
@@ -151,10 +157,7 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
 
-#define IWL_DEVICE_7000                                                \
-       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
-       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
-       .ucode_api_min = IWL7260_UCODE_API_MIN,                 \
+#define IWL_DEVICE_7000_COMMON                                 \
        .device_family = IWL_DEVICE_FAMILY_7000,                \
        .max_inst_size = IWL60_RTC_INST_SIZE,                   \
        .max_data_size = IWL60_RTC_DATA_SIZE,                   \
@@ -165,6 +168,24 @@ static const struct iwl_ht_params iwl7000_ht_params = {
        .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,    \
        .dccm_offset = IWL7000_DCCM_OFFSET
 
+#define IWL_DEVICE_7000                                                \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7260_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7260_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7260_UCODE_API_MIN
+
+#define IWL_DEVICE_7005                                                \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7265_UCODE_API_MAX,                 \
+       .ucode_api_ok = IWL7265_UCODE_API_OK,                   \
+       .ucode_api_min = IWL7265_UCODE_API_MIN
+
+#define IWL_DEVICE_7005D                                       \
+       IWL_DEVICE_7000_COMMON,                                 \
+       .ucode_api_max = IWL7265D_UCODE_API_MAX,                \
+       .ucode_api_ok = IWL7265D_UCODE_API_OK,                  \
+       .ucode_api_min = IWL7265D_UCODE_API_MIN
+
 const struct iwl_cfg iwl7260_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7260",
        .fw_name_pre = IWL7260_FW_PRE,
@@ -268,7 +289,7 @@ static const struct iwl_ht_params iwl7265_ht_params = {
 const struct iwl_cfg iwl3165_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 3165",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7000_ht_params,
        .nvm_ver = IWL3165_NVM_VERSION,
        .nvm_calib_ver = IWL3165_TX_POWER_VERSION,
@@ -290,7 +311,7 @@ const struct iwl_cfg iwl3168_2ac_cfg = {
 const struct iwl_cfg iwl7265_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -301,7 +322,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
 const struct iwl_cfg iwl7265_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -312,7 +333,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
 const struct iwl_cfg iwl7265_n_cfg = {
        .name = "Intel(R) Wireless N 7265",
        .fw_name_pre = IWL7265_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -323,7 +344,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
 const struct iwl_cfg iwl7265d_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -334,7 +355,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = {
 const struct iwl_cfg iwl7265d_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -345,7 +366,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = {
 const struct iwl_cfg iwl7265d_n_cfg = {
        .name = "Intel(R) Wireless N 7265",
        .fw_name_pre = IWL7265D_FW_PRE,
-       IWL_DEVICE_7000,
+       IWL_DEVICE_7005D,
        .ht_params = &iwl7265_ht_params,
        .nvm_ver = IWL7265D_NVM_VERSION,
        .nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -355,5 +376,5 @@ const struct iwl_cfg iwl7265d_n_cfg = {
 
 MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
 MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_OK));
index 89a25cf..dee4458 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index a784bb6..0d2aa1d 100644 (file)
@@ -83,7 +83,7 @@
 
 static const struct iwl_base_params iwl9000_base_params = {
        .eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_9000,
-       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_queues = 31,
        .pll_cfg_val = 0,
        .shadow_ram_support = true,
        .led_compensation = 57,
index 6a4c0c2..f990481 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 543abea..163b21b 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 09feff4..b1c3b0d 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index e8dbb24..1103332 100644 (file)
@@ -21,7 +21,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index bde0233..d80312b 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -51,6 +52,22 @@ TRACE_EVENT(iwlwifi_dev_tx_data,
        TP_printk("[%s] TX frame data", __get_str(dev))
 );
 
+TRACE_EVENT(iwlwifi_dev_tx_tso_chunk,
+       TP_PROTO(const struct device *dev,
+                u8 *data_src, size_t data_len),
+       TP_ARGS(dev, data_src, data_len),
+       TP_STRUCT__entry(
+               DEV_ENTRY
+
+               __dynamic_array(u8, data, data_len)
+       ),
+       TP_fast_assign(
+               DEV_ASSIGN;
+               memcpy(__get_dynamic_array(data), data_src, data_len);
+       ),
+       TP_printk("[%s] TX frame data", __get_str(dev))
+);
+
 TRACE_EVENT(iwlwifi_dev_rx_data,
        TP_PROTO(const struct device *dev,
                 const struct iwl_trans *trans,
index eb4b99a..22786d7 100644 (file)
@@ -20,7 +20,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index 90987d6..1d9dd15 100644 (file)
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index b87acd6..f4d3cd0 100644 (file)
@@ -19,7 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index 16756f0..7acb490 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -594,7 +594,8 @@ static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv,
 static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                                const struct firmware *ucode_raw,
                                struct iwl_firmware_pieces *pieces,
-                               struct iwl_ucode_capabilities *capa)
+                               struct iwl_ucode_capabilities *capa,
+                               bool *usniffer_images)
 {
        struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
        struct iwl_ucode_tlv *tlv;
@@ -607,7 +608,6 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
        char buildstr[25];
        u32 build, paging_mem_size;
        int num_of_cpus;
-       bool usniffer_images = false;
        bool usniffer_req = false;
        bool gscan_capa = false;
 
@@ -980,7 +980,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                        break;
                        }
                case IWL_UCODE_TLV_SEC_RT_USNIFFER:
-                       usniffer_images = true;
+                       *usniffer_images = true;
                        iwl_store_ucode_sec(pieces, tlv_data,
                                            IWL_UCODE_REGULAR_USNIFFER,
                                            tlv_len);
@@ -1031,7 +1031,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                }
        }
 
-       if (usniffer_req && !usniffer_images) {
+       if (usniffer_req && !*usniffer_images) {
                IWL_ERR(drv,
                        "user selected to work with usniffer but usniffer image isn't available in ucode package\n");
                return -EINVAL;
@@ -1192,6 +1192,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
        u32 api_ver;
        int i;
        bool load_module = false;
+       bool usniffer_images = false;
 
        fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH;
        fw->ucode_capa.standard_phy_calibration_size =
@@ -1229,7 +1230,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                err = iwl_parse_v1_v2_firmware(drv, ucode_raw, pieces);
        else
                err = iwl_parse_tlv_firmware(drv, ucode_raw, pieces,
-                                            &fw->ucode_capa);
+                                            &fw->ucode_capa, &usniffer_images);
 
        if (err)
                goto try_again;
index cda746b..f6eacfd 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -69,7 +69,7 @@
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
 #define DRV_COPYRIGHT  "Copyright(c) 2003- 2015 Intel Corporation"
-#define DRV_AUTHOR     "<ilw@linux.intel.com>"
+#define DRV_AUTHOR     "<linuxwifi@intel.com>"
 
 /* radio config bits (actual values from NVM definition) */
 #define NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
index b395854..c15f5be 100644 (file)
@@ -454,11 +454,11 @@ static void iwl_eeprom_enhanced_txpower(struct device *dev,
                                 TXP_CHECK_AND_PRINT(COMMON_TYPE),
                                 txp->flags);
                IWL_DEBUG_EEPROM(dev,
-                                "\t\t chain_A: 0x%02x chain_B: 0X%02x chain_C: 0X%02x\n",
+                                "\t\t chain_A: %d chain_B: %d chain_C: %d\n",
                                 txp->chain_a_max, txp->chain_b_max,
                                 txp->chain_c_max);
                IWL_DEBUG_EEPROM(dev,
-                                "\t\t MIMO2: 0x%02x MIMO3: 0x%02x High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n",
+                                "\t\t MIMO2: %d MIMO3: %d High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n",
                                 txp->mimo2_max, txp->mimo3_max,
                                 ((txp->delta_20_in_40 & 0xf0) >> 4),
                                 (txp->delta_20_in_40 & 0x0f));
index e08319a..d2294ad 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 603c894..32c8f84 100644 (file)
@@ -22,7 +22,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -82,7 +82,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
 {
        u32 value = 0x5a5a5a5a;
        unsigned long flags;
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                value = iwl_read32(trans, reg);
                iwl_trans_release_nic_access(trans, &flags);
        }
@@ -95,7 +95,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
 {
        unsigned long flags;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                iwl_write32(trans, reg, value);
                iwl_trans_release_nic_access(trans, &flags);
        }
@@ -138,7 +138,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
        unsigned long flags;
        u32 val = 0x5a5a5a5a;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                val = iwl_read_prph_no_grab(trans, ofs);
                iwl_trans_release_nic_access(trans, &flags);
        }
@@ -150,7 +150,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
 {
        unsigned long flags;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                iwl_write_prph_no_grab(trans, ofs, val);
                iwl_trans_release_nic_access(trans, &flags);
        }
@@ -176,7 +176,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
 {
        unsigned long flags;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                iwl_write_prph_no_grab(trans, ofs,
                                       iwl_read_prph_no_grab(trans, ofs) |
                                       mask);
@@ -190,7 +190,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
 {
        unsigned long flags;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                iwl_write_prph_no_grab(trans, ofs,
                                       (iwl_read_prph_no_grab(trans, ofs) &
                                        mask) | bits);
@@ -204,7 +204,7 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
        unsigned long flags;
        u32 val;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                val = iwl_read_prph_no_grab(trans, ofs);
                iwl_write_prph_no_grab(trans, ofs, (val & ~mask));
                iwl_trans_release_nic_access(trans, &flags);
index 9baf9ef..fd42f63 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 2a58d68..b49eda8 100644 (file)
@@ -27,7 +27,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -123,6 +123,8 @@ struct iwl_cfg;
  *     received on the RSS queue(s). The queue parameter indicates which of the
  *     RSS queues received this frame; it will always be non-zero.
  *     This method must not sleep.
+ * @async_cb: called when an ASYNC command with CMD_WANT_ASYNC_CALLBACK set
+ *     completes. Must be atomic.
  * @queue_full: notifies that a HW queue is full.
  *     Must be atomic and called with BH disabled.
  * @queue_not_full: notifies that a HW queue is not full any more.
@@ -155,6 +157,8 @@ struct iwl_op_mode_ops {
                   struct iwl_rx_cmd_buffer *rxb);
        void (*rx_rss)(struct iwl_op_mode *op_mode, struct napi_struct *napi,
                       struct iwl_rx_cmd_buffer *rxb, unsigned int queue);
+       void (*async_cb)(struct iwl_op_mode *op_mode,
+                        const struct iwl_device_cmd *cmd);
        void (*queue_full)(struct iwl_op_mode *op_mode, int queue);
        void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue);
        bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
@@ -203,6 +207,13 @@ static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode,
        op_mode->ops->rx_rss(op_mode, napi, rxb, queue);
 }
 
+static inline void iwl_op_mode_async_cb(struct iwl_op_mode *op_mode,
+                                       const struct iwl_device_cmd *cmd)
+{
+       if (op_mode->ops->async_cb)
+               op_mode->ops->async_cb(op_mode, cmd);
+}
+
 static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode,
                                          int queue)
 {
index a105455..4a4dea0 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 9ee18d0..2410387 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 3ab777f..9da7dc4 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index ccd317b..6069a9f 100644 (file)
  *
  *****************************************************************************/
 #include <linux/kernel.h>
+#include <linux/bsearch.h>
+
 #include "iwl-trans.h"
+#include "iwl-drv.h"
 
 struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
                                  struct device *dev,
@@ -112,3 +115,91 @@ void iwl_trans_free(struct iwl_trans *trans)
        kmem_cache_destroy(trans->dev_cmd_pool);
        kfree(trans);
 }
+
+int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+{
+       int ret;
+
+       if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
+                    test_bit(STATUS_RFKILL, &trans->status)))
+               return -ERFKILL;
+
+       if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
+               return -EIO;
+
+       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
+               IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return -EIO;
+       }
+
+       if (WARN_ON((cmd->flags & CMD_WANT_ASYNC_CALLBACK) &&
+                   !(cmd->flags & CMD_ASYNC)))
+               return -EINVAL;
+
+       if (!(cmd->flags & CMD_ASYNC))
+               lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
+
+       ret = trans->ops->send_cmd(trans, cmd);
+
+       if (!(cmd->flags & CMD_ASYNC))
+               lock_map_release(&trans->sync_cmd_lockdep_map);
+
+       return ret;
+}
+IWL_EXPORT_SYMBOL(iwl_trans_send_cmd);
+
+/* Comparator for struct iwl_hcmd_names.
+ * Used in the binary search over a list of host commands.
+ *
+ * @key: command_id that we're looking for.
+ * @elt: struct iwl_hcmd_names candidate for match.
+ *
+ * @return 0 iff equal.
+ */
+static int iwl_hcmd_names_cmp(const void *key, const void *elt)
+{
+       const struct iwl_hcmd_names *name = elt;
+       u8 cmd1 = *(u8 *)key;
+       u8 cmd2 = name->cmd_id;
+
+       return (cmd1 - cmd2);
+}
+
+const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id)
+{
+       u8 grp, cmd;
+       struct iwl_hcmd_names *ret;
+       const struct iwl_hcmd_arr *arr;
+       size_t size = sizeof(struct iwl_hcmd_names);
+
+       grp = iwl_cmd_groupid(id);
+       cmd = iwl_cmd_opcode(id);
+
+       if (!trans->command_groups || grp >= trans->command_groups_size ||
+           !trans->command_groups[grp].arr)
+               return "UNKNOWN";
+
+       arr = &trans->command_groups[grp];
+       ret = bsearch(&cmd, arr->arr, arr->size, size, iwl_hcmd_names_cmp);
+       if (!ret)
+               return "UNKNOWN";
+       return ret->cmd_name;
+}
+IWL_EXPORT_SYMBOL(iwl_get_cmd_string);
+
+int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans)
+{
+       int i, j;
+       const struct iwl_hcmd_arr *arr;
+
+       for (i = 0; i < trans->command_groups_size; i++) {
+               arr = &trans->command_groups[i];
+               if (!arr->arr)
+                       continue;
+               for (j = 0; j < arr->size - 1; j++)
+                       if (arr->arr[j].cmd_id > arr->arr[j + 1].cmd_id)
+                               return -1;
+       }
+       return 0;
+}
+IWL_EXPORT_SYMBOL(iwl_cmd_groups_verify_sorted);
index 3d089ae..81b7cb7 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -68,6 +68,7 @@
 #include <linux/ieee80211.h>
 #include <linux/mm.h> /* for page_address */
 #include <linux/lockdep.h>
+#include <linux/kernel.h>
 
 #include "iwl-debug.h"
 #include "iwl-config.h"
@@ -248,6 +249,8 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)
  * @CMD_MAKE_TRANS_IDLE: The command response should mark the trans as idle.
  * @CMD_WAKE_UP_TRANS: The command response should wake up the trans
  *     (i.e. mark it as non-idle).
+ * @CMD_WANT_ASYNC_CALLBACK: the op_mode's async callback function must be
+ *     called after this command completes. Valid only with CMD_ASYNC.
  * @CMD_TB_BITMAP_POS: Position of the first bit for the TB bitmap. We need to
  *     check that we leave enough room for the TBs bitmap which needs 20 bits.
  */
@@ -259,6 +262,7 @@ enum CMD_MODE {
        CMD_SEND_IN_IDLE        = BIT(4),
        CMD_MAKE_TRANS_IDLE     = BIT(5),
        CMD_WAKE_UP_TRANS       = BIT(6),
+       CMD_WANT_ASYNC_CALLBACK = BIT(7),
 
        CMD_TB_BITMAP_POS       = 11,
 };
@@ -377,6 +381,11 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
 
 #define MAX_NO_RECLAIM_CMDS    6
 
+/*
+ * The first entry in driver_data array in ieee80211_tx_info
+ * that can be used by the transport.
+ */
+#define IWL_TRANS_FIRST_DRIVER_DATA 2
 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
 
 /*
@@ -439,6 +448,22 @@ iwl_trans_get_rb_size_order(enum iwl_amsdu_size rb_size)
        }
 }
 
+struct iwl_hcmd_names {
+       u8 cmd_id;
+       const char *const cmd_name;
+};
+
+#define HCMD_NAME(x)   \
+       { .cmd_id = x, .cmd_name = #x }
+
+struct iwl_hcmd_arr {
+       const struct iwl_hcmd_names *arr;
+       int size;
+};
+
+#define HCMD_ARR(x)    \
+       { .arr = x, .size = ARRAY_SIZE(x) }
+
 /**
  * struct iwl_trans_config - transport configuration
  *
@@ -458,8 +483,10 @@ iwl_trans_get_rb_size_order(enum iwl_amsdu_size rb_size)
  *     in DWORD (as opposed to bytes)
  * @scd_set_active: should the transport configure the SCD for HCMD queue
  * @wide_cmd_header: firmware supports wide host command header
- * @command_names: array of command names, must be 256 entries
- *     (one for each command); for debugging only
+ * @sw_csum_tx: transport should compute the TCP checksum
+ * @command_groups: array of command groups, each member is an array of the
+ *     commands in the group; for debugging only
+ * @command_groups_size: number of command groups, to avoid illegal access
  * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
  *     we get the ALIVE from the uCode
  */
@@ -476,8 +503,10 @@ struct iwl_trans_config {
        bool bc_table_dword;
        bool scd_set_active;
        bool wide_cmd_header;
-       const char *const *command_names;
-
+       bool sw_csum_tx;
+       const struct iwl_hcmd_arr *command_groups;
+       int command_groups_size;
        u32 sdio_adma_addr;
 };
 
@@ -528,7 +557,11 @@ struct iwl_trans_txq_scd_cfg {
  *     If RFkill is asserted in the middle of a SYNC host command, it must
  *     return -ERFKILL straight away.
  *     May sleep only if CMD_ASYNC is not set
- * @tx: send an skb
+ * @tx: send an skb. The transport relies on the op_mode to zero the
+ *     the ieee80211_tx_info->driver_data. If the MPDU is an A-MSDU, all
+ *     the CSUM will be taken care of (TCP CSUM and IP header in case of
+ *     IPv4). If the MPDU is a single MSDU, the op_mode must compute the IP
+ *     header if it is IPv4.
  *     Must be atomic
  * @reclaim: free packet until ssn. Returns a list of freed packets.
  *     Must be atomic
@@ -542,6 +575,11 @@ struct iwl_trans_txq_scd_cfg {
  * @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
  * @freeze_txq_timer: prevents the timer of the queue from firing until the
  *     queue is set to awake. Must be atomic.
+ * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note
+ *     that the transport needs to refcount the calls since this function
+ *     will be called several times with block = true, and then the queues
+ *     need to be unblocked only after the same number of calls with
+ *     block = false.
  * @write8: write a u8 to a register at offset ofs from the BAR
  * @write32: write a u32 to a register at offset ofs from the BAR
  * @read32: read a u32 register at offset ofs from the BAR
@@ -600,6 +638,7 @@ struct iwl_trans_ops {
        int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
        void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs,
                                 bool freeze);
+       void (*block_txq_ptrs)(struct iwl_trans *trans, bool block);
 
        void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val);
        void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val);
@@ -613,8 +652,7 @@ struct iwl_trans_ops {
        void (*configure)(struct iwl_trans *trans,
                          const struct iwl_trans_config *trans_cfg);
        void (*set_pmi)(struct iwl_trans *trans, bool state);
-       bool (*grab_nic_access)(struct iwl_trans *trans, bool silent,
-                               unsigned long *flags);
+       bool (*grab_nic_access)(struct iwl_trans *trans, unsigned long *flags);
        void (*release_nic_access)(struct iwl_trans *trans,
                                   unsigned long *flags);
        void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask,
@@ -641,18 +679,61 @@ enum iwl_trans_state {
 };
 
 /**
- * enum iwl_d0i3_mode - d0i3 mode
+ * DOC: Platform power management
+ *
+ * There are two types of platform power management: system-wide
+ * (WoWLAN) and runtime.
+ *
+ * In system-wide power management the entire platform goes into a low
+ * power state (e.g. idle or suspend to RAM) at the same time and the
+ * device is configured as a wakeup source for the entire platform.
+ * This is usually triggered by userspace activity (e.g. the user
+ * presses the suspend button or a power management daemon decides to
+ * put the platform in low power mode).  The device's behavior in this
+ * mode is dictated by the wake-on-WLAN configuration.
+ *
+ * In runtime power management, only the devices which are themselves
+ * idle enter a low power state.  This is done at runtime, which means
+ * that the entire system is still running normally.  This mode is
+ * usually triggered automatically by the device driver and requires
+ * the ability to enter and exit the low power modes in a very short
+ * time, so there is not much impact in usability.
+ *
+ * The terms used for the device's behavior are as follows:
+ *
+ *     - D0: the device is fully powered and the host is awake;
+ *     - D3: the device is in low power mode and only reacts to
+ *             specific events (e.g. magic-packet received or scan
+ *             results found);
+ *     - D0I3: the device is in low power mode and reacts to any
+ *             activity (e.g. RX);
+ *
+ * These terms reflect the power modes in the firmware and are not to
+ * be confused with the physical device power state.  The NIC can be
+ * in D0I3 mode even if, for instance, the PCI device is in D3 state.
+ */
+
+/**
+ * enum iwl_plat_pm_mode - platform power management mode
  *
- * @IWL_D0I3_MODE_OFF - d0i3 is disabled
- * @IWL_D0I3_MODE_ON_IDLE - enter d0i3 when device is idle
- *     (e.g. no active references)
- * @IWL_D0I3_MODE_ON_SUSPEND - enter d0i3 only on suspend
- *     (in case of 'any' trigger)
+ * This enumeration describes the device's platform power management
+ * behavior when in idle mode (i.e. runtime power management) or when
+ * in system-wide suspend (i.e WoWLAN).
+ *
+ * @IWL_PLAT_PM_MODE_DISABLED: power management is disabled for this
+ *     device.  At runtime, this means that nothing happens and the
+ *     device always remains in active.  In system-wide suspend mode,
+ *     it means that the all connections will be closed automatically
+ *     by mac80211 before the platform is suspended.
+ * @IWL_PLAT_PM_MODE_D3: the device goes into D3 mode (i.e. WoWLAN).
+ *     For runtime power management, this mode is not officially
+ *     supported.
+ * @IWL_PLAT_PM_MODE_D0I3: the device goes into D0I3 mode.
  */
-enum iwl_d0i3_mode {
-       IWL_D0I3_MODE_OFF = 0,
-       IWL_D0I3_MODE_ON_IDLE,
-       IWL_D0I3_MODE_ON_SUSPEND,
+enum iwl_plat_pm_mode {
+       IWL_PLAT_PM_MODE_DISABLED,
+       IWL_PLAT_PM_MODE_D3,
+       IWL_PLAT_PM_MODE_D0I3,
 };
 
 /**
@@ -692,6 +773,12 @@ enum iwl_d0i3_mode {
  *     the opmode.
  * @paging_download_buf: Buffer used for copying all of the pages before
  *     downloading them to the FW. The buffer is allocated in the opmode
+ * @system_pm_mode: the system-wide power management mode in use.
+ *     This mode is set dynamically, depending on the WoWLAN values
+ *     configured from the userspace at runtime.
+ * @runtime_pm_mode: the runtime power management mode in use.  This
+ *     mode is set during the initialization phase and is not
+ *     supposed to change during runtime.
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
@@ -711,6 +798,9 @@ struct iwl_trans {
        bool pm_support;
        bool ltr_enabled;
 
+       const struct iwl_hcmd_arr *command_groups;
+       int command_groups_size;
+
        u8 num_rx_queues;
 
        /* The following fields are internal only */
@@ -739,21 +829,24 @@ struct iwl_trans {
        struct iwl_fw_paging *paging_db;
        void *paging_download_buf;
 
-       enum iwl_d0i3_mode d0i3_mode;
-
-       bool wowlan_d0i3;
+       enum iwl_plat_pm_mode system_pm_mode;
+       enum iwl_plat_pm_mode runtime_pm_mode;
 
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __aligned(sizeof(void *));
 };
 
+const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id);
+int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans);
+
 static inline void iwl_trans_configure(struct iwl_trans *trans,
                                       const struct iwl_trans_config *trans_cfg)
 {
        trans->op_mode = trans_cfg->op_mode;
 
        trans->ops->configure(trans, trans_cfg);
+       WARN_ON(iwl_cmd_groups_verify_sorted(trans_cfg));
 }
 
 static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power)
@@ -880,34 +973,6 @@ iwl_trans_dump_data(struct iwl_trans *trans,
        return trans->ops->dump_data(trans, trigger);
 }
 
-static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
-                                    struct iwl_host_cmd *cmd)
-{
-       int ret;
-
-       if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
-                    test_bit(STATUS_RFKILL, &trans->status)))
-               return -ERFKILL;
-
-       if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
-               return -EIO;
-
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
-               IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
-               return -EIO;
-       }
-
-       if (!(cmd->flags & CMD_ASYNC))
-               lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
-
-       ret = trans->ops->send_cmd(trans, cmd);
-
-       if (!(cmd->flags & CMD_ASYNC))
-               lock_map_release(&trans->sync_cmd_lockdep_map);
-
-       return ret;
-}
-
 static inline struct iwl_device_cmd *
 iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
 {
@@ -920,6 +985,8 @@ iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
                        (dev_cmd_ptr + trans->dev_cmd_headroom);
 }
 
+int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
+
 static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans,
                                         struct iwl_device_cmd *dev_cmd)
 {
@@ -934,8 +1001,10 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
        if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
                return -EIO;
 
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+       if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return -EIO;
+       }
 
        return trans->ops->tx(trans, skb, dev_cmd, queue);
 }
@@ -943,8 +1012,10 @@ static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
 static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
                                     int ssn, struct sk_buff_head *skbs)
 {
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+       if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return;
+       }
 
        trans->ops->reclaim(trans, queue, ssn, skbs);
 }
@@ -962,8 +1033,10 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
 {
        might_sleep();
 
-       if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
+       if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return;
+       }
 
        trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout);
 }
@@ -1003,18 +1076,34 @@ static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans,
                                              unsigned long txqs,
                                              bool freeze)
 {
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+       if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return;
+       }
 
        if (trans->ops->freeze_txq_timer)
                trans->ops->freeze_txq_timer(trans, txqs, freeze);
 }
 
+static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans,
+                                           bool block)
+{
+       if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
+               IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return;
+       }
+
+       if (trans->ops->block_txq_ptrs)
+               trans->ops->block_txq_ptrs(trans, block);
+}
+
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
                                                u32 txqs)
 {
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
+       if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
+               return -EIO;
+       }
 
        return trans->ops->wait_tx_queue_empty(trans, txqs);
 }
@@ -1092,9 +1181,9 @@ iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
        trans->ops->set_bits_mask(trans, reg, mask, value);
 }
 
-#define iwl_trans_grab_nic_access(trans, silent, flags)        \
+#define iwl_trans_grab_nic_access(trans, flags)        \
        __cond_lock(nic_access,                         \
-                   likely((trans)->ops->grab_nic_access(trans, silent, flags)))
+                   likely((trans)->ops->grab_nic_access(trans, flags)))
 
 static inline void __releases(nic_access)
 iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags)
index 2c0d20f..23e7e29 100644 (file)
@@ -1,12 +1,12 @@
 obj-$(CONFIG_IWLMVM)   += iwlmvm.o
 iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
-iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o sf.o
+iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o
 iwlmvm-y += scan.o time-event.o rs.o
 iwlmvm-y += power.o coex.o coex_legacy.o
 iwlmvm-y += tt.o offloading.o tdls.o
 iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
 iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
 iwlmvm-y += tof.o fw-dbg.o
-iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
+iwlmvm-$(CONFIG_PM) += d3.o
 
 ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../
index c9ca029..2e098f8 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 61c07b0..0150457 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 5c21231..b00c03f 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0
 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK       1
 #define IWL_MVM_TOF_IS_RESPONDER               0
+#define IWL_MVM_SW_TX_CSUM_OFFLOAD             0
 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE    1
 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE      2
 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW   1
index 9e51843..6ac4072 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -104,9 +104,13 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
        struct inet6_ifaddr *ifa;
        int idx = 0;
 
+       memset(mvmvif->tentative_addrs, 0, sizeof(mvmvif->tentative_addrs));
+
        read_lock_bh(&idev->lock);
        list_for_each_entry(ifa, &idev->addr_list, if_list) {
                mvmvif->target_ipv6_addrs[idx] = ifa->addr;
+               if (ifa->flags & IFA_F_TENTATIVE)
+                       __set_bit(idx, mvmvif->tentative_addrs);
                idx++;
                if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX)
                        break;
@@ -775,6 +779,9 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
         */
        set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
 
+       /* the fw is reset, so all the keys are cleared */
+       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+
        mvm->ptk_ivlen = 0;
        mvm->ptk_icvlen = 0;
        mvm->ptk_ivlen = 0;
@@ -797,6 +804,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
 
        wowlan_config_cmd->is_11n_connection =
                                        ap_sta->ht_cap.ht_supported;
+       wowlan_config_cmd->flags = ENABLE_L3_FILTERING |
+               ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING;
 
        /* Query the last used seqno and set it */
        ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
@@ -846,15 +855,38 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
        return 0;
 }
 
+static void
+iwl_mvm_iter_d0i3_ap_keys(struct iwl_mvm *mvm,
+                         struct ieee80211_vif *vif,
+                         void (*iter)(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_sta *sta,
+                                      struct ieee80211_key_conf *key,
+                                      void *data),
+                         void *data)
+{
+       struct ieee80211_sta *ap_sta;
+
+       rcu_read_lock();
+
+       ap_sta = rcu_dereference(mvm->fw_id_to_mac_id[mvm->d0i3_ap_sta_id]);
+       if (IS_ERR_OR_NULL(ap_sta))
+               goto out;
+
+       ieee80211_iter_keys_rcu(mvm->hw, vif, iter, data);
+out:
+       rcu_read_unlock();
+}
+
 int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
                                     struct ieee80211_vif *vif,
-                                    bool configure_keys,
+                                    bool d0i3,
                                     u32 cmd_flags)
 {
        struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
        struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
        struct wowlan_key_data key_data = {
-               .configure_keys = configure_keys,
+               .configure_keys = !d0i3,
                .use_rsc_tsc = false,
                .tkip = &tkip_cmd,
                .use_tkip = false,
@@ -867,15 +899,28 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
                return -ENOMEM;
 
        /*
-        * Note that currently we don't propagate cmd_flags
-        * to the iterator. In case of key_data.configure_keys,
-        * all the configured commands are SYNC, and
-        * iwl_mvm_wowlan_program_keys() will take care of
-        * locking/unlocking mvm->mutex.
+        * if we have to configure keys, call ieee80211_iter_keys(),
+        * as we need non-atomic context in order to take the
+        * required locks.
+        * for the d0i3 we can't use ieee80211_iter_keys(), as
+        * taking (almost) any mutex might result in deadlock.
         */
-       ieee80211_iter_keys(mvm->hw, vif,
-                           iwl_mvm_wowlan_program_keys,
-                           &key_data);
+       if (!d0i3) {
+               /*
+                * Note that currently we don't propagate cmd_flags
+                * to the iterator. In case of key_data.configure_keys,
+                * all the configured commands are SYNC, and
+                * iwl_mvm_wowlan_program_keys() will take care of
+                * locking/unlocking mvm->mutex.
+                */
+               ieee80211_iter_keys(mvm->hw, vif,
+                                   iwl_mvm_wowlan_program_keys,
+                                   &key_data);
+       } else {
+               iwl_mvm_iter_d0i3_ap_keys(mvm, vif,
+                                         iwl_mvm_wowlan_program_keys,
+                                         &key_data);
+       }
 
        if (key_data.error) {
                ret = -EIO;
@@ -900,7 +945,8 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
                        goto out;
        }
 
-       if (mvmvif->rekey_data.valid) {
+       /* configure rekey data only if offloaded rekey is supported (d3) */
+       if (mvmvif->rekey_data.valid && !d0i3) {
                memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
                memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
                       NL80211_KCK_LEN);
@@ -917,6 +963,7 @@ int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
                if (ret)
                        goto out;
        }
+       ret = 0;
 out:
        kfree(key_data.rsc_tsc);
        return ret;
@@ -946,8 +993,11 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
                 * that isn't really a problem though.
                 */
                mutex_unlock(&mvm->mutex);
-               iwl_mvm_wowlan_config_key_params(mvm, vif, true, CMD_ASYNC);
+               ret = iwl_mvm_wowlan_config_key_params(mvm, vif, false,
+                                                      CMD_ASYNC);
                mutex_lock(&mvm->mutex);
+               if (ret)
+                       return ret;
        }
 
        ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
@@ -960,7 +1010,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
        if (ret)
                return ret;
 
-       ret = iwl_mvm_send_proto_offload(mvm, vif, false, 0);
+       ret = iwl_mvm_send_proto_offload(mvm, vif, false, true, 0);
        if (ret)
                return ret;
 
@@ -1179,19 +1229,20 @@ remove_notif:
 int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct iwl_trans *trans = mvm->trans;
        int ret;
 
        /* make sure the d0i3 exit work is not pending */
        flush_work(&mvm->d0i3_exit_work);
 
-       ret = iwl_trans_suspend(mvm->trans);
+       ret = iwl_trans_suspend(trans);
        if (ret)
                return ret;
 
-       mvm->trans->wowlan_d0i3 = wowlan->any;
-       if (mvm->trans->wowlan_d0i3) {
-               /* 'any' trigger means d0i3 usage */
-               if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
+       if (wowlan->any) {
+               trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+
+               if (iwl_mvm_enter_d0i3_on_suspend(mvm)) {
                        ret = iwl_mvm_enter_d0i3_sync(mvm);
 
                        if (ret)
@@ -1202,11 +1253,13 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
                mutex_unlock(&mvm->d0i3_suspend_mutex);
 
-               iwl_trans_d3_suspend(mvm->trans, false);
+               iwl_trans_d3_suspend(trans, false);
 
                return 0;
        }
 
+       trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
+
        return __iwl_mvm_suspend(hw, wowlan, false);
 }
 
@@ -1711,6 +1764,29 @@ out_unlock:
        return false;
 }
 
+void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
+                             struct ieee80211_vif *vif,
+                             struct iwl_wowlan_status *status)
+{
+       struct iwl_mvm_d3_gtk_iter_data gtkdata = {
+               .status = status,
+       };
+
+       /*
+        * rekey handling requires taking locks that can't be taken now.
+        * however, d0i3 doesn't offload rekey, so we're fine.
+        */
+       if (WARN_ON_ONCE(status->num_of_gtk_rekeys))
+               return;
+
+       /* find last GTK that we used initially, if any */
+       gtkdata.find_phase = true;
+       iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, &gtkdata);
+
+       gtkdata.find_phase = false;
+       iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, &gtkdata);
+}
+
 struct iwl_mvm_nd_query_results {
        u32 matched_profiles;
        struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES];
@@ -1969,8 +2045,9 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm)
 {
        bool exit_now;
        enum iwl_d3_status d3_status;
+       struct iwl_trans *trans = mvm->trans;
 
-       iwl_trans_d3_resume(mvm->trans, &d3_status, false);
+       iwl_trans_d3_resume(trans, &d3_status, false);
 
        /*
         * make sure to clear D0I3_DEFER_WAKEUP before
@@ -1987,9 +2064,9 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm)
                _iwl_mvm_exit_d0i3(mvm);
        }
 
-       iwl_trans_resume(mvm->trans);
+       iwl_trans_resume(trans);
 
-       if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
+       if (iwl_mvm_enter_d0i3_on_suspend(mvm)) {
                int ret = iwl_mvm_exit_d0i3(mvm->hw->priv);
 
                if (ret)
@@ -2005,12 +2082,16 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm)
 int iwl_mvm_resume(struct ieee80211_hw *hw)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       int ret;
 
-       /* 'any' trigger means d0i3 was used */
-       if (hw->wiphy->wowlan_config->any)
-               return iwl_mvm_resume_d0i3(mvm);
+       if (mvm->trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+               ret = iwl_mvm_resume_d0i3(mvm);
        else
-               return iwl_mvm_resume_d3(mvm);
+               ret = iwl_mvm_resume_d3(mvm);
+
+       mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+
+       return ret;
 }
 
 void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled)
@@ -2034,6 +2115,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
        ieee80211_stop_queues(mvm->hw);
        synchronize_net();
 
+       mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
+
        /* start pseudo D3 */
        rtnl_lock();
        err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
@@ -2088,9 +2171,13 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
        int remaining_time = 10;
 
        mvm->d3_test_active = false;
+
        rtnl_lock();
        __iwl_mvm_resume(mvm, true);
        rtnl_unlock();
+
+       mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+
        iwl_abort_notification_waits(&mvm->notif_wait);
        ieee80211_restart_hw(mvm->hw);
 
index 7904b41..9e0d463 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 7e2a814..90500e2 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -1029,7 +1029,8 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
        if (ret)
                return ret;
 
-       iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, NULL);
+       iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf,
+                              (count - 1), NULL);
 
        iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
 
@@ -1316,6 +1317,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
        PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
        PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
        PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
+       PRINT_MVM_REF(IWL_MVM_REF_INIT_UCODE);
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
@@ -1450,7 +1452,7 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
-MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
 MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
index d398a61..2a33b69 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 228684c..62b9a0a 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -94,10 +95,14 @@ struct iwl_d3_manager_config {
  * enum iwl_d3_proto_offloads - enabled protocol offloads
  * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled
  * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled
+ * @IWL_D3_PROTO_IPV4_VALID: IPv4 data is valid
+ * @IWL_D3_PROTO_IPV6_VALID: IPv6 data is valid
  */
 enum iwl_proto_offloads {
        IWL_D3_PROTO_OFFLOAD_ARP = BIT(0),
        IWL_D3_PROTO_OFFLOAD_NS = BIT(1),
+       IWL_D3_PROTO_IPV4_VALID = BIT(2),
+       IWL_D3_PROTO_IPV6_VALID = BIT(3),
 };
 
 #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1    2
@@ -241,6 +246,13 @@ enum iwl_wowlan_wakeup_filters {
        IWL_WOWLAN_WAKEUP_BCN_FILTERING                 = BIT(16),
 }; /* WOWLAN_WAKEUP_FILTER_API_E_VER_4 */
 
+enum iwl_wowlan_flags {
+       IS_11W_ASSOC            = BIT(0),
+       ENABLE_L3_FILTERING     = BIT(1),
+       ENABLE_NBNS_FILTERING   = BIT(2),
+       ENABLE_DHCP_FILTERING   = BIT(3),
+};
+
 struct iwl_wowlan_config_cmd {
        __le32 wakeup_filter;
        __le16 non_qos_seq;
@@ -248,8 +260,9 @@ struct iwl_wowlan_config_cmd {
        u8 wowlan_ba_teardown_tids;
        u8 is_11n_connection;
        u8 offloading_tid;
-       u8 reserved[3];
-} __packed; /* WOWLAN_CONFIG_API_S_VER_3 */
+       u8 flags;
+       u8 reserved[2];
+} __packed; /* WOWLAN_CONFIG_API_S_VER_4 */
 
 /*
  * WOWLAN_TSC_RSC_PARAMS
index 9a8a37f..fb6d341 100644 (file)
@@ -27,7 +27,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
 #define IWL_RX_INFO_ENERGY_ANT_B_POS 8
 #define IWL_RX_INFO_ENERGY_ANT_C_POS 16
 
+enum iwl_mac_context_info {
+       MAC_CONTEXT_INFO_NONE,
+       MAC_CONTEXT_INFO_GSCAN,
+};
+
 /**
  * struct iwl_rx_phy_info - phy info
  * (REPLY_RX_PHY_CMD = 0xc0)
  * @frame_time: frame's time on the air, based on byte count and frame rate
  *     calculation
  * @mac_active_msk: what MACs were active when the frame was received
+ * @mac_context_info: additional info on the context in which the frame was
+ *     received as defined in &enum iwl_mac_context_info
  *
  * Before each Rx, the device sends this data. It contains PHY information
  * about the reception of the packet.
@@ -114,7 +121,8 @@ struct iwl_rx_phy_info {
        __le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT];
        __le32 rate_n_flags;
        __le32 byte_count;
-       __le16 mac_active_msk;
+       u8 mac_active_msk;
+       u8 mac_context_info;
        __le16 frame_time;
 } __packed;
 
@@ -279,11 +287,17 @@ enum iwl_rx_mpdu_status {
        IWL_RX_MPDU_STATUS_KEY_ERROR            = BIT(4),
        IWL_RX_MPDU_STATUS_ICV_OK               = BIT(5),
        IWL_RX_MPDU_STATUS_MIC_OK               = BIT(6),
+       /* TODO - verify this is the correct value */
+       IWL_RX_MPDU_RES_STATUS_TTAK_OK          = BIT(7),
        IWL_RX_MPDU_STATUS_SEC_MASK             = 0x7 << 8,
        IWL_RX_MPDU_STATUS_SEC_NONE             = 0x0 << 8,
        IWL_RX_MPDU_STATUS_SEC_WEP              = 0x1 << 8,
        IWL_RX_MPDU_STATUS_SEC_CCM              = 0x2 << 8,
        IWL_RX_MPDU_STATUS_SEC_TKIP             = 0x3 << 8,
+       /* TODO - define IWL_RX_MPDU_STATUS_SEC_EXT_ENC - this is a stub */
+       IWL_RX_MPDU_STATUS_SEC_EXT_ENC          = 0x4 << 8,
+       /* TODO - define IWL_RX_MPDU_STATUS_SEC_GCM - this is a stub */
+       IWL_RX_MPDU_STATUS_SEC_GCM              = 0x5 << 8,
        IWL_RX_MPDU_STATUS_DECRYPTED            = BIT(11),
        IWL_RX_MPDU_STATUS_WEP_MATCH            = BIT(12),
        IWL_RX_MPDU_STATUS_EXT_IV_MATCH         = BIT(13),
@@ -302,6 +316,8 @@ enum iwl_rx_mpdu_sta_id_flags {
        IWL_RX_MPDU_SIF_FILTER_STATUS_MASK      = 0xc0,
 };
 
+#define IWL_RX_REORDER_DATA_INVALID_BAID 0x7f
+
 enum iwl_rx_mpdu_reorder_data {
        IWL_RX_MPDU_REORDER_NSSN_MASK           = 0x00000fff,
        IWL_RX_MPDU_REORDER_SN_MASK             = 0x00fff000,
index 3a657e4..f01dab0 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -285,6 +285,8 @@ struct iwl_scan_channel_opt {
  * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented
  * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report
  *     and DS parameter set IEs into probe requests.
+ * @IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL: use extended dwell time on channels
+ *     1, 6 and 11.
  * @IWL_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches
  */
 enum iwl_mvm_lmac_scan_flags {
@@ -295,6 +297,7 @@ enum iwl_mvm_lmac_scan_flags {
        IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS   = BIT(4),
        IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED       = BIT(5),
        IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED     = BIT(6),
+       IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL   = BIT(7),
        IWL_MVM_LMAC_SCAN_FLAG_MATCH            = BIT(9),
 };
 
@@ -322,6 +325,7 @@ enum iwl_scan_priority_ext {
  * @active-dwell: dwell time for active channels
  * @passive-dwell: dwell time for passive channels
  * @fragmented-dwell: dwell time for fragmented passive scan
+ * @extended_dwell: dwell time for channels 1, 6 and 11 (in certain cases)
  * @reserved2: for alignment and future use
  * @rx_chain_selct: PHY_RX_CHAIN_* flags
  * @scan_flags: &enum iwl_mvm_lmac_scan_flags
@@ -346,7 +350,8 @@ struct iwl_scan_req_lmac {
        u8 active_dwell;
        u8 passive_dwell;
        u8 fragmented_dwell;
-       __le16 reserved2;
+       u8 extended_dwell;
+       u8 reserved2;
        __le16 rx_chain_select;
        __le32 scan_flags;
        __le32 max_out_time;
@@ -490,7 +495,7 @@ enum iwl_channel_flags {
  * @dwell_active:              default dwell time for active scan
  * @dwell_passive:             default dwell time for passive scan
  * @dwell_fragmented:          default dwell time for fragmented scan
- * @reserved:                  for future use and alignment
+ * @dwell_extended:            default dwell time for channels 1, 6 and 11
  * @mac_addr:                  default mac address to be used in probes
  * @bcast_sta_id:              the index of the station in the fw
  * @channel_flags:             default channel flags - enum iwl_channel_flags
@@ -507,7 +512,7 @@ struct iwl_scan_config {
        u8 dwell_active;
        u8 dwell_passive;
        u8 dwell_fragmented;
-       u8 reserved;
+       u8 dwell_extended;
        u8 mac_addr[ETH_ALEN];
        u8 bcast_sta_id;
        u8 channel_flags;
@@ -543,7 +548,8 @@ enum iwl_umac_scan_general_flags {
        IWL_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID   = BIT(6),
        IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED      = BIT(7),
        IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED     = BIT(8),
-       IWL_UMAC_SCAN_GEN_FLAGS_MATCH           = BIT(9)
+       IWL_UMAC_SCAN_GEN_FLAGS_MATCH           = BIT(9),
+       IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL  = BIT(10),
 };
 
 /**
@@ -597,7 +603,7 @@ struct iwl_scan_req_umac_tail {
  * @uid: scan id, &enum iwl_umac_scan_uid_offsets
  * @ooc_priority: out of channel priority - &enum iwl_scan_priority
  * @general_flags: &enum iwl_umac_scan_general_flags
- * @reserved1: for future use and alignment
+ * @extended_dwell: dwell time for channels 1, 6 and 11
  * @active_dwell: dwell time for active scan
  * @passive_dwell: dwell time for passive scan
  * @fragmented_dwell: dwell time for fragmented passive scan
@@ -606,7 +612,7 @@ struct iwl_scan_req_umac_tail {
  * @scan_priority: scan internal prioritization &enum iwl_scan_priority
  * @channel_flags: &enum iwl_scan_channel_flags
  * @n_channels: num of channels in scan request
- * @reserved2: for future use and alignment
+ * @reserved: for future use and alignment
  * @data: &struct iwl_scan_channel_cfg_umac and
  *     &struct iwl_scan_req_umac_tail
  */
@@ -616,7 +622,7 @@ struct iwl_scan_req_umac {
        __le32 ooc_priority;
        /* SCAN_GENERAL_PARAMS_API_S_VER_1 */
        __le32 general_flags;
-       u8 reserved1;
+       u8 extended_dwell;
        u8 active_dwell;
        u8 passive_dwell;
        u8 fragmented_dwell;
@@ -626,7 +632,7 @@ struct iwl_scan_req_umac {
        /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
        u8 channel_flags;
        u8 n_channels;
-       __le16 reserved2;
+       __le16 reserved;
        u8 data[];
 } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */
 
index 9436798..995898c 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -270,6 +270,9 @@ enum {
        REPLY_MAX = 0xff,
 };
 
+/* Please keep this enum *SORTED* by hex value.
+ * Needed for binary search, otherwise a warning will be triggered.
+ */
 enum iwl_phy_ops_subcmd_ids {
        CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0,
        DTS_MEASUREMENT_NOTIF_WIDE = 0xFF,
@@ -277,6 +280,8 @@ enum iwl_phy_ops_subcmd_ids {
 
 /* command groups */
 enum {
+       LEGACY_GROUP = 0x0,
+       LONG_GROUP = 0x1,
        PHY_OPS_GROUP = 0x4,
 };
 
index 9fcabc5..f406c76 100644 (file)
@@ -122,7 +122,7 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
        unsigned long flags;
        int i, j;
 
-       if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags))
+       if (!iwl_trans_grab_nic_access(mvm->trans, &flags))
                return;
 
        /* Pull RXF data from all RXFs */
@@ -349,6 +349,7 @@ static const struct {
        { .start = 0x00a04560, .end = 0x00a0457c },
        { .start = 0x00a04590, .end = 0x00a04598 },
        { .start = 0x00a045c0, .end = 0x00a045f4 },
+       { .start = 0x00a44000, .end = 0x00a7bf80 },
 };
 
 static u32 iwl_dump_prph(struct iwl_trans *trans,
@@ -358,7 +359,7 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,
        unsigned long flags;
        u32 prph_len = 0, i;
 
-       if (!iwl_trans_grab_nic_access(trans, false, &flags))
+       if (!iwl_trans_grab_nic_access(trans, &flags))
                return 0;
 
        for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
@@ -383,7 +384,7 @@ static u32 iwl_dump_prph(struct iwl_trans *trans,
                        *val++ = cpu_to_le32(iwl_read_prph_no_grab(trans,
                                                                   reg));
 
-                       *data = iwl_fw_error_next_data(*data);
+               *data = iwl_fw_error_next_data(*data);
        }
 
        iwl_trans_release_nic_access(trans, &flags);
@@ -400,7 +401,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        struct iwl_fw_error_dump_trigger_desc *dump_trig;
        struct iwl_mvm_dump_ptrs *fw_error_dump;
        u32 sram_len, sram_ofs;
-       u32 file_len, fifo_data_len = 0;
+       u32 file_len, fifo_data_len = 0, prph_len = 0;
        u32 smem_len = mvm->cfg->smem_len;
        u32 sram2_len = mvm->cfg->dccm2_len;
        bool monitor_dump_only = false;
@@ -460,12 +461,24 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                                         sizeof(*dump_data) +
                                         sizeof(struct iwl_fw_error_dump_fifo);
                }
+
+               /* Make room for PRPH registers */
+               for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
+                       /* The range includes both boundaries */
+                       int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
+                               iwl_prph_dump_addr[i].start + 4;
+
+                       prph_len += sizeof(*dump_data) +
+                               sizeof(struct iwl_fw_error_dump_prph) +
+                               num_bytes_in_chunk;
+               }
        }
 
        file_len = sizeof(*dump_file) +
                   sizeof(*dump_data) * 2 +
                   sram_len + sizeof(*dump_mem) +
                   fifo_data_len +
+                  prph_len +
                   sizeof(*dump_info);
 
        /* Make room for the SMEM, if it exists */
@@ -489,17 +502,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                           sizeof(*dump_info);
        }
 
-       /* Make room for PRPH registers */
-       for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) {
-               /* The range includes both boundaries */
-               int num_bytes_in_chunk = iwl_prph_dump_addr[i].end -
-                       iwl_prph_dump_addr[i].start + 4;
-
-               file_len += sizeof(*dump_data) +
-                       sizeof(struct iwl_fw_error_dump_prph) +
-                       num_bytes_in_chunk;
-       }
-
        /*
         * In 8000 HW family B-step include the ICCM (which resides separately)
         */
@@ -625,7 +627,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        }
 
        dump_data = iwl_fw_error_next_data(dump_data);
-       iwl_dump_prph(mvm->trans, &dump_data);
+       if (prph_len)
+               iwl_dump_prph(mvm->trans, &dump_data);
 
 dump_trans_data:
        fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans,
index 05c9333..e6e8088 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index ee511aa..5e3a758 100644 (file)
@@ -27,7 +27,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -855,11 +855,17 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
                                         u32 action)
 {
        struct iwl_mac_ctx_cmd cmd = {};
+       u32 tfd_queue_msk = 0;
+       int ret, i;
 
        WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
 
        iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
+       for (i = 0; i < IEEE80211_NUM_ACS; i++)
+               if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
+                       tfd_queue_msk |= BIT(vif->hw_queue[i]);
+
        cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
                                       MAC_FILTER_IN_CONTROL_AND_MGMT |
                                       MAC_FILTER_IN_BEACON |
@@ -867,6 +873,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
                                       MAC_FILTER_IN_CRC32);
        ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
 
+       /* Allocate sniffer station */
+       ret = iwl_mvm_allocate_int_sta(mvm, &mvm->snif_sta, tfd_queue_msk,
+                                      vif->type);
+       if (ret)
+               return ret;
+
        return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
 }
 
@@ -1289,8 +1301,10 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
        mvmvif->uploaded = false;
 
-       if (vif->type == NL80211_IFTYPE_MONITOR)
+       if (vif->type == NL80211_IFTYPE_MONITOR) {
                __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);
+               iwl_mvm_dealloc_snif_sta(mvm);
+       }
 
        return 0;
 }
index a90f1ee..296b9c5 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -439,6 +439,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
        ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
 
+       if (mvm->trans->max_skb_frags)
+               hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;
+
        hw->queues = mvm->first_agg_queue;
        hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
        hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
@@ -664,6 +667,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (!iwl_mvm_is_csum_supported(mvm))
                hw->netdev_features &= ~NETIF_F_RXCSUM;
 
+       if (IWL_MVM_SW_TX_CSUM_OFFLOAD)
+               hw->netdev_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                       NETIF_F_TSO | NETIF_F_TSO6;
+
        ret = ieee80211_register_hw(mvm->hw);
        if (ret)
                iwl_mvm_leds_exit(mvm);
@@ -964,6 +971,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        mvm->calibrating = false;
 
        /* just in case one was running */
+       iwl_mvm_cleanup_roc_te(mvm);
        ieee80211_remain_on_channel_expired(mvm->hw);
 
        /*
@@ -976,6 +984,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
 
        iwl_mvm_reset_phy_ctxts(mvm);
+       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
        memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
        memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
        memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
@@ -993,6 +1002,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        mvm->vif_count = 0;
        mvm->rx_ba_sessions = 0;
        mvm->fw_dbg_conf = FW_DBG_INVALID;
+       mvm->scan_type = IWL_SCAN_TYPE_NOT_SET;
 
        /* keep statistics ticking */
        iwl_mvm_accu_radio_stats(mvm);
@@ -1004,10 +1014,18 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       /* Clean up some internal and mac80211 state on restart */
-       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+               /* Clean up some internal and mac80211 state on restart */
                iwl_mvm_restart_cleanup(mvm);
-
+       } else {
+               /* Hold the reference to prevent runtime suspend while
+                * the start procedure runs.  It's a bit confusing
+                * that the UCODE_DOWN reference is taken, but it just
+                * means "UCODE is not UP yet". ( TODO: rename this
+                * reference).
+                */
+               iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+       }
        ret = iwl_mvm_up(mvm);
 
        if (ret && test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
@@ -1074,15 +1092,13 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
 
 static void iwl_mvm_resume_complete(struct iwl_mvm *mvm)
 {
-       if (!iwl_mvm_is_d0i3_supported(mvm))
-               return;
-
-       if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND)
-               if (!wait_event_timeout(mvm->d0i3_exit_waitq,
-                                       !test_bit(IWL_MVM_STATUS_IN_D0I3,
-                                                 &mvm->status),
-                                       HZ))
-                       WARN_ONCE(1, "D0i3 exit on resume timed out\n");
+       if (iwl_mvm_is_d0i3_supported(mvm) &&
+           iwl_mvm_enter_d0i3_on_suspend(mvm))
+               WARN_ONCE(!wait_event_timeout(mvm->d0i3_exit_waitq,
+                                             !test_bit(IWL_MVM_STATUS_IN_D0I3,
+                                                       &mvm->status),
+                                             HZ),
+                         "D0i3 exit on resume timed out\n");
 }
 
 static void
@@ -1110,14 +1126,6 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
         */
        memset(&mvm->accu_radio_stats, 0, sizeof(mvm->accu_radio_stats));
 
-       /*
-        * Disallow low power states when the FW is down by taking
-        * the UCODE_DOWN ref. in case of ongoing hw restart the
-        * ref is already taken, so don't take it again.
-        */
-       if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
-               iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
-
        /* async_handlers_wk is now blocked */
 
        /*
@@ -1729,8 +1737,8 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
 
        return true;
 }
-static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
-                                         struct ieee80211_vif *vif)
+
+static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
 {
        struct iwl_bcast_filter_cmd cmd;
 
@@ -1744,8 +1752,7 @@ static int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
                                    sizeof(cmd), &cmd);
 }
 #else
-static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
-                                                struct ieee80211_vif *vif)
+static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
 {
        return 0;
 }
@@ -1860,7 +1867,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                }
 
                iwl_mvm_recalc_multicast(mvm);
-               iwl_mvm_configure_bcast_filter(mvm, vif);
+               iwl_mvm_configure_bcast_filter(mvm);
 
                /* reset rssi values */
                mvmvif->bf_data.ave_beacon_signal = 0;
@@ -1868,6 +1875,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                iwl_mvm_bt_coex_vif_change(mvm);
                iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT,
                                    IEEE80211_SMPS_AUTOMATIC);
+               if (fw_has_capa(&mvm->fw->ucode_capa,
+                               IWL_UCODE_TLV_CAPA_UMAC_SCAN))
+                       iwl_mvm_config_scan(mvm);
        } else if (changes & BSS_CHANGED_BEACON_INFO) {
                /*
                 * We received a beacon _after_ association so
@@ -1908,7 +1918,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
 
        if (changes & BSS_CHANGED_ARP_FILTER) {
                IWL_DEBUG_MAC80211(mvm, "arp filter changed\n");
-               iwl_mvm_configure_bcast_filter(mvm, vif);
+               iwl_mvm_configure_bcast_filter(mvm);
        }
 }
 
@@ -2238,7 +2248,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
                                       struct ieee80211_sta *sta)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
 
        /*
@@ -2254,11 +2263,6 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
                rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
                                   ERR_PTR(-ENOENT));
 
-       if (mvm_sta->vif->type == NL80211_IFTYPE_AP) {
-               mvmvif->ap_assoc_sta_count--;
-               iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
-       }
-
        mutex_unlock(&mvm->mutex);
 }
 
@@ -2370,6 +2374,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC) {
+               if (vif->type == NL80211_IFTYPE_AP) {
+                       mvmvif->ap_assoc_sta_count++;
+                       iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+               }
                ret = iwl_mvm_update_sta(mvm, vif, sta);
                if (ret == 0)
                        iwl_mvm_rs_rate_init(mvm, sta,
@@ -2396,6 +2404,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
                ret = 0;
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH) {
+               if (vif->type == NL80211_IFTYPE_AP) {
+                       mvmvif->ap_assoc_sta_count--;
+                       iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+               }
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_NONE) {
@@ -3116,6 +3128,11 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
                ret = iwl_mvm_update_quotas(mvm, false, NULL);
                if (ret)
                        goto out_remove_binding;
+
+               ret = iwl_mvm_add_snif_sta(mvm, vif);
+               if (ret)
+                       goto out_remove_binding;
+
        }
 
        /* Handle binding during CSA */
@@ -3189,6 +3206,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
        case NL80211_IFTYPE_MONITOR:
                mvmvif->monitor_active = false;
                mvmvif->ps_disabled = false;
+               iwl_mvm_rm_snif_sta(mvm, vif);
                break;
        case NL80211_IFTYPE_AP:
                /* This part is triggered only during CSA */
index 7dc3af6..287c162 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -294,6 +294,7 @@ enum iwl_mvm_ref_type {
        IWL_MVM_REF_EXIT_WORK,
        IWL_MVM_REF_PROTECT_CSA,
        IWL_MVM_REF_FW_DBG_COLLECT,
+       IWL_MVM_REF_INIT_UCODE,
 
        /* update debugfs.c when changing this */
 
@@ -404,7 +405,7 @@ struct iwl_mvm_vif {
         */
        struct iwl_mvm_phy_ctxt *phy_ctxt;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
        /* WoWLAN GTK rekey data */
        struct {
                u8 kck[NL80211_KCK_LEN], kek[NL80211_KEK_LEN];
@@ -421,6 +422,7 @@ struct iwl_mvm_vif {
 #if IS_ENABLED(CONFIG_IPV6)
        /* IPv6 addresses for WoWLAN */
        struct in6_addr target_ipv6_addrs[IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX];
+       unsigned long tentative_addrs[BITS_TO_LONGS(IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_MAX)];
        int num_target_ipv6_addrs;
 #endif
 
@@ -475,6 +477,14 @@ enum iwl_scan_status {
        IWL_MVM_SCAN_MASK               = 0xff,
 };
 
+enum iwl_mvm_scan_type {
+       IWL_SCAN_TYPE_NOT_SET,
+       IWL_SCAN_TYPE_UNASSOC,
+       IWL_SCAN_TYPE_WILD,
+       IWL_SCAN_TYPE_MILD,
+       IWL_SCAN_TYPE_FRAGMENTED,
+};
+
 /**
  * struct iwl_nvm_section - describes an NVM section in memory.
  *
@@ -643,7 +653,7 @@ struct iwl_mvm {
        unsigned int scan_status;
        void *scan_cmd;
        struct iwl_mcast_filter_cmd *mcast_filter_cmd;
-       bool scan_fragmented;
+       enum iwl_mvm_scan_type scan_type;
 
        /* max number of simultaneous scans the FW supports */
        unsigned int max_scans;
@@ -667,6 +677,7 @@ struct iwl_mvm {
 
        /* Internal station */
        struct iwl_mvm_int_sta aux_sta;
+       struct iwl_mvm_int_sta snif_sta;
 
        bool last_ebs_successful;
 
@@ -727,7 +738,7 @@ struct iwl_mvm {
 
        struct ieee80211_vif *p2p_device_vif;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
        struct wiphy_wowlan_support wowlan;
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
 
@@ -924,6 +935,19 @@ static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
                           IWL_UCODE_TLV_CAPA_DQA_SUPPORT);
 }
 
+static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
+{
+       /* For now we only use this mode to differentiate between
+        * slave transports, which handle D0i3 entry in suspend by
+        * themselves in conjunction with runtime PM D0i3.  So, this
+        * function is used to check whether we need to do anything
+        * when entering suspend or if the transport layer has already
+        * done it.
+        */
+       return (mvm->trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) &&
+               (mvm->trans->runtime_pm_mode != IWL_PLAT_PM_MODE_D0I3);
+}
+
 static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
 {
        bool nvm_lar = mvm->nvm_data->lar_enabled;
@@ -1111,6 +1135,11 @@ 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 iwl_rx_cmd_buffer *rxb, int queue);
 void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
@@ -1249,10 +1278,6 @@ static inline void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
 /* D3 (WoWLAN, NetDetect) */
 int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
 int iwl_mvm_resume(struct ieee80211_hw *hw);
-int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
-                                    struct ieee80211_vif *vif,
-                                    bool configure_keys,
-                                    u32 cmd_flags);
 void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled);
 void iwl_mvm_set_rekey_data(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
@@ -1263,10 +1288,31 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
 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;
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
+int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
+                                    struct ieee80211_vif *vif,
+                                    bool host_awake,
+                                    u32 cmd_flags);
+void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
+                             struct ieee80211_vif *vif,
+                             struct iwl_wowlan_status *status);
 void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
                                 struct ieee80211_vif *vif);
 #else
+static inline int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
+                                                  struct ieee80211_vif *vif,
+                                                  bool host_awake,
+                                                  u32 cmd_flags)
+{
+       return 0;
+}
+
+static inline void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm,
+                                           struct ieee80211_vif *vif,
+                                           struct iwl_wowlan_status *status)
+{
+}
+
 static inline void
 iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
@@ -1277,6 +1323,7 @@ void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
 int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                               struct ieee80211_vif *vif,
                               bool disable_offloading,
+                              bool offload_ns,
                               u32 cmd_flags);
 
 /* D0i3 */
index a9fcb15..d8dcb67 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index f83e2bc..6338d9c 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2015 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,6 +66,7 @@
  *****************************************************************************/
 #include <net/ipv6.h>
 #include <net/addrconf.h>
+#include <linux/bitops.h>
 #include "mvm.h"
 
 void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
@@ -86,6 +89,7 @@ void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta,
 int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                               struct ieee80211_vif *vif,
                               bool disable_offloading,
+                              bool offload_ns,
                               u32 cmd_flags)
 {
        union {
@@ -106,6 +110,13 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
 #if IS_ENABLED(CONFIG_IPV6)
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int i;
+       /*
+        * Skip tentative address when ns offload is enabled to avoid
+        * violating RFC4862.
+        * Keep tentative address when ns offload is disabled so the NS packets
+        * will not be filtered out and will wake up the host.
+        */
+       bool skip_tentative = offload_ns;
 
        if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL ||
            capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) {
@@ -113,6 +124,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                struct iwl_targ_addr *addrs;
                int n_nsc, n_addrs;
                int c;
+               int num_skipped = 0;
 
                if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
                        nsc = cmd.v3s.ns_config;
@@ -126,9 +138,6 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                        n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L;
                }
 
-               if (mvmvif->num_target_ipv6_addrs)
-                       enabled |= IWL_D3_PROTO_OFFLOAD_NS;
-
                /*
                 * For each address we have (and that will fit) fill a target
                 * address struct and combine for NS offload structs with the
@@ -140,6 +149,12 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                        struct in6_addr solicited_addr;
                        int j;
 
+                       if (skip_tentative &&
+                           test_bit(i, mvmvif->tentative_addrs)) {
+                               num_skipped++;
+                               continue;
+                       }
+
                        addrconf_addr_solict_mult(&mvmvif->target_ipv6_addrs[i],
                                                  &solicited_addr);
                        for (j = 0; j < c; j++)
@@ -154,41 +169,64 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
                        memcpy(nsc[j].target_mac_addr, vif->addr, ETH_ALEN);
                }
 
+               if (mvmvif->num_target_ipv6_addrs - num_skipped)
+                       enabled |= IWL_D3_PROTO_IPV6_VALID;
+
                if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL)
-                       cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i);
+                       cmd.v3s.num_valid_ipv6_addrs =
+                               cpu_to_le32(i - num_skipped);
                else
-                       cmd.v3l.num_valid_ipv6_addrs = cpu_to_le32(i);
+                       cmd.v3l.num_valid_ipv6_addrs =
+                               cpu_to_le32(i - num_skipped);
        } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) {
-               if (mvmvif->num_target_ipv6_addrs) {
-                       enabled |= IWL_D3_PROTO_OFFLOAD_NS;
-                       memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
-               }
+               bool found = false;
 
                BUILD_BUG_ON(sizeof(cmd.v2.target_ipv6_addr[0]) !=
                             sizeof(mvmvif->target_ipv6_addrs[0]));
 
                for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
-                                   IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++)
+                                   IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V2); i++) {
+                       if (skip_tentative &&
+                           test_bit(i, mvmvif->tentative_addrs))
+                               continue;
+
                        memcpy(cmd.v2.target_ipv6_addr[i],
                               &mvmvif->target_ipv6_addrs[i],
                               sizeof(cmd.v2.target_ipv6_addr[i]));
-       } else {
-               if (mvmvif->num_target_ipv6_addrs) {
-                       enabled |= IWL_D3_PROTO_OFFLOAD_NS;
-                       memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
-               }
 
+                       found = true;
+               }
+               if (found) {
+                       enabled |= IWL_D3_PROTO_IPV6_VALID;
+                       memcpy(cmd.v2.ndp_mac_addr, vif->addr, ETH_ALEN);
+               }
+       } else {
+               bool found = false;
                BUILD_BUG_ON(sizeof(cmd.v1.target_ipv6_addr[0]) !=
                             sizeof(mvmvif->target_ipv6_addrs[0]));
 
                for (i = 0; i < min(mvmvif->num_target_ipv6_addrs,
-                                   IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++)
+                                   IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1); i++) {
+                       if (skip_tentative &&
+                           test_bit(i, mvmvif->tentative_addrs))
+                               continue;
+
                        memcpy(cmd.v1.target_ipv6_addr[i],
                               &mvmvif->target_ipv6_addrs[i],
                               sizeof(cmd.v1.target_ipv6_addr[i]));
+
+                       found = true;
+               }
+
+               if (found) {
+                       enabled |= IWL_D3_PROTO_IPV6_VALID;
+                       memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
+               }
        }
-#endif
 
+       if (offload_ns && (enabled & IWL_D3_PROTO_IPV6_VALID))
+               enabled |= IWL_D3_PROTO_OFFLOAD_NS;
+#endif
        if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL) {
                common = &cmd.v3s.common;
                size = sizeof(cmd.v3s);
@@ -204,7 +242,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
        }
 
        if (vif->bss_conf.arp_addr_cnt) {
-               enabled |= IWL_D3_PROTO_OFFLOAD_ARP;
+               enabled |= IWL_D3_PROTO_OFFLOAD_ARP | IWL_D3_PROTO_IPV4_VALID;
                common->host_ipv4_addr = vif->bss_conf.arp_addr_list[0];
                memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
        }
index 3b0d597..89ea70d 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -83,6 +83,8 @@
 #include "fw-api-scan.h"
 #include "time-event.h"
 #include "fw-dbg.h"
+#include "fw-api.h"
+#include "fw-api-scan.h"
 
 #define DRV_DESCRIPTION        "The new Intel(R) wireless AGN driver for Linux"
 MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -269,104 +271,127 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
 };
 #undef RX_HANDLER
 #undef RX_HANDLER_GRP
-#define CMD(x) [x] = #x
-
-static const char *const iwl_mvm_cmd_strings[REPLY_MAX + 1] = {
-       CMD(MVM_ALIVE),
-       CMD(REPLY_ERROR),
-       CMD(ECHO_CMD),
-       CMD(INIT_COMPLETE_NOTIF),
-       CMD(PHY_CONTEXT_CMD),
-       CMD(MGMT_MCAST_KEY),
-       CMD(TX_CMD),
-       CMD(TXPATH_FLUSH),
-       CMD(SHARED_MEM_CFG),
-       CMD(MAC_CONTEXT_CMD),
-       CMD(TIME_EVENT_CMD),
-       CMD(TIME_EVENT_NOTIFICATION),
-       CMD(BINDING_CONTEXT_CMD),
-       CMD(TIME_QUOTA_CMD),
-       CMD(NON_QOS_TX_COUNTER_CMD),
-       CMD(DC2DC_CONFIG_CMD),
-       CMD(NVM_ACCESS_CMD),
-       CMD(PHY_CONFIGURATION_CMD),
-       CMD(CALIB_RES_NOTIF_PHY_DB),
-       CMD(SET_CALIB_DEFAULT_CMD),
-       CMD(FW_PAGING_BLOCK_CMD),
-       CMD(ADD_STA_KEY),
-       CMD(ADD_STA),
-       CMD(FW_GET_ITEM_CMD),
-       CMD(REMOVE_STA),
-       CMD(LQ_CMD),
-       CMD(SCAN_OFFLOAD_CONFIG_CMD),
-       CMD(MATCH_FOUND_NOTIFICATION),
-       CMD(SCAN_OFFLOAD_REQUEST_CMD),
-       CMD(SCAN_OFFLOAD_ABORT_CMD),
-       CMD(HOT_SPOT_CMD),
-       CMD(SCAN_OFFLOAD_COMPLETE),
-       CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
-       CMD(SCAN_ITERATION_COMPLETE),
-       CMD(POWER_TABLE_CMD),
-       CMD(WEP_KEY),
-       CMD(REPLY_RX_PHY_CMD),
-       CMD(REPLY_RX_MPDU_CMD),
-       CMD(FRAME_RELEASE),
-       CMD(BEACON_NOTIFICATION),
-       CMD(BEACON_TEMPLATE_CMD),
-       CMD(STATISTICS_CMD),
-       CMD(STATISTICS_NOTIFICATION),
-       CMD(EOSP_NOTIFICATION),
-       CMD(REDUCE_TX_POWER_CMD),
-       CMD(TX_ANT_CONFIGURATION_CMD),
-       CMD(D3_CONFIG_CMD),
-       CMD(D0I3_END_CMD),
-       CMD(PROT_OFFLOAD_CONFIG_CMD),
-       CMD(OFFLOADS_QUERY_CMD),
-       CMD(REMOTE_WAKE_CONFIG_CMD),
-       CMD(WOWLAN_PATTERNS),
-       CMD(WOWLAN_CONFIGURATION),
-       CMD(WOWLAN_TSC_RSC_PARAM),
-       CMD(WOWLAN_TKIP_PARAM),
-       CMD(WOWLAN_KEK_KCK_MATERIAL),
-       CMD(WOWLAN_GET_STATUSES),
-       CMD(WOWLAN_TX_POWER_PER_DB),
-       CMD(SCAN_OFFLOAD_PROFILES_QUERY_CMD),
-       CMD(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD),
-       CMD(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD),
-       CMD(CARD_STATE_NOTIFICATION),
-       CMD(MISSED_BEACONS_NOTIFICATION),
-       CMD(BT_COEX_PRIO_TABLE),
-       CMD(BT_COEX_PROT_ENV),
-       CMD(BT_PROFILE_NOTIFICATION),
-       CMD(BT_CONFIG),
-       CMD(MCAST_FILTER_CMD),
-       CMD(BCAST_FILTER_CMD),
-       CMD(REPLY_SF_CFG_CMD),
-       CMD(REPLY_BEACON_FILTERING_CMD),
-       CMD(CMD_DTS_MEASUREMENT_TRIGGER),
-       CMD(DTS_MEASUREMENT_NOTIFICATION),
-       CMD(REPLY_THERMAL_MNG_BACKOFF),
-       CMD(MAC_PM_POWER_TABLE),
-       CMD(LTR_CONFIG),
-       CMD(BT_COEX_CI),
-       CMD(BT_COEX_UPDATE_SW_BOOST),
-       CMD(BT_COEX_UPDATE_CORUN_LUT),
-       CMD(BT_COEX_UPDATE_REDUCED_TXP),
-       CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
-       CMD(ANTENNA_COUPLING_NOTIFICATION),
-       CMD(SCD_QUEUE_CFG),
-       CMD(SCAN_CFG_CMD),
-       CMD(SCAN_REQ_UMAC),
-       CMD(SCAN_ABORT_UMAC),
-       CMD(SCAN_COMPLETE_UMAC),
-       CMD(TDLS_CHANNEL_SWITCH_CMD),
-       CMD(TDLS_CHANNEL_SWITCH_NOTIFICATION),
-       CMD(TDLS_CONFIG_CMD),
-       CMD(MCC_UPDATE_CMD),
-       CMD(SCAN_ITERATION_COMPLETE_UMAC),
-       CMD(LDBG_CONFIG_CMD),
+
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search
+ */
+static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
+       HCMD_NAME(MVM_ALIVE),
+       HCMD_NAME(REPLY_ERROR),
+       HCMD_NAME(ECHO_CMD),
+       HCMD_NAME(INIT_COMPLETE_NOTIF),
+       HCMD_NAME(PHY_CONTEXT_CMD),
+       HCMD_NAME(DBG_CFG),
+       HCMD_NAME(ANTENNA_COUPLING_NOTIFICATION),
+       HCMD_NAME(SCAN_CFG_CMD),
+       HCMD_NAME(SCAN_REQ_UMAC),
+       HCMD_NAME(SCAN_ABORT_UMAC),
+       HCMD_NAME(SCAN_COMPLETE_UMAC),
+       HCMD_NAME(TOF_CMD),
+       HCMD_NAME(TOF_NOTIFICATION),
+       HCMD_NAME(ADD_STA_KEY),
+       HCMD_NAME(ADD_STA),
+       HCMD_NAME(REMOVE_STA),
+       HCMD_NAME(FW_GET_ITEM_CMD),
+       HCMD_NAME(TX_CMD),
+       HCMD_NAME(SCD_QUEUE_CFG),
+       HCMD_NAME(TXPATH_FLUSH),
+       HCMD_NAME(MGMT_MCAST_KEY),
+       HCMD_NAME(WEP_KEY),
+       HCMD_NAME(SHARED_MEM_CFG),
+       HCMD_NAME(TDLS_CHANNEL_SWITCH_CMD),
+       HCMD_NAME(MAC_CONTEXT_CMD),
+       HCMD_NAME(TIME_EVENT_CMD),
+       HCMD_NAME(TIME_EVENT_NOTIFICATION),
+       HCMD_NAME(BINDING_CONTEXT_CMD),
+       HCMD_NAME(TIME_QUOTA_CMD),
+       HCMD_NAME(NON_QOS_TX_COUNTER_CMD),
+       HCMD_NAME(LQ_CMD),
+       HCMD_NAME(FW_PAGING_BLOCK_CMD),
+       HCMD_NAME(SCAN_OFFLOAD_REQUEST_CMD),
+       HCMD_NAME(SCAN_OFFLOAD_ABORT_CMD),
+       HCMD_NAME(HOT_SPOT_CMD),
+       HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD),
+       HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_CONFIG_CMD),
+       HCMD_NAME(SCAN_OFFLOAD_HOTSPOTS_QUERY_CMD),
+       HCMD_NAME(BT_COEX_UPDATE_SW_BOOST),
+       HCMD_NAME(BT_COEX_UPDATE_CORUN_LUT),
+       HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP),
+       HCMD_NAME(BT_COEX_CI),
+       HCMD_NAME(PHY_CONFIGURATION_CMD),
+       HCMD_NAME(CALIB_RES_NOTIF_PHY_DB),
+       HCMD_NAME(SCAN_OFFLOAD_COMPLETE),
+       HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
+       HCMD_NAME(SCAN_OFFLOAD_CONFIG_CMD),
+       HCMD_NAME(POWER_TABLE_CMD),
+       HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION),
+       HCMD_NAME(REPLY_THERMAL_MNG_BACKOFF),
+       HCMD_NAME(DC2DC_CONFIG_CMD),
+       HCMD_NAME(NVM_ACCESS_CMD),
+       HCMD_NAME(SET_CALIB_DEFAULT_CMD),
+       HCMD_NAME(BEACON_NOTIFICATION),
+       HCMD_NAME(BEACON_TEMPLATE_CMD),
+       HCMD_NAME(TX_ANT_CONFIGURATION_CMD),
+       HCMD_NAME(BT_CONFIG),
+       HCMD_NAME(STATISTICS_CMD),
+       HCMD_NAME(STATISTICS_NOTIFICATION),
+       HCMD_NAME(EOSP_NOTIFICATION),
+       HCMD_NAME(REDUCE_TX_POWER_CMD),
+       HCMD_NAME(CARD_STATE_CMD),
+       HCMD_NAME(CARD_STATE_NOTIFICATION),
+       HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
+       HCMD_NAME(TDLS_CONFIG_CMD),
+       HCMD_NAME(MAC_PM_POWER_TABLE),
+       HCMD_NAME(TDLS_CHANNEL_SWITCH_NOTIFICATION),
+       HCMD_NAME(MFUART_LOAD_NOTIFICATION),
+       HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
+       HCMD_NAME(REPLY_RX_PHY_CMD),
+       HCMD_NAME(REPLY_RX_MPDU_CMD),
+       HCMD_NAME(BA_NOTIF),
+       HCMD_NAME(MCC_UPDATE_CMD),
+       HCMD_NAME(MCC_CHUB_UPDATE_CMD),
+       HCMD_NAME(MARKER_CMD),
+       HCMD_NAME(BT_COEX_PRIO_TABLE),
+       HCMD_NAME(BT_COEX_PROT_ENV),
+       HCMD_NAME(BT_PROFILE_NOTIFICATION),
+       HCMD_NAME(BCAST_FILTER_CMD),
+       HCMD_NAME(MCAST_FILTER_CMD),
+       HCMD_NAME(REPLY_SF_CFG_CMD),
+       HCMD_NAME(REPLY_BEACON_FILTERING_CMD),
+       HCMD_NAME(D3_CONFIG_CMD),
+       HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD),
+       HCMD_NAME(OFFLOADS_QUERY_CMD),
+       HCMD_NAME(REMOTE_WAKE_CONFIG_CMD),
+       HCMD_NAME(MATCH_FOUND_NOTIFICATION),
+       HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER),
+       HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION),
+       HCMD_NAME(WOWLAN_PATTERNS),
+       HCMD_NAME(WOWLAN_CONFIGURATION),
+       HCMD_NAME(WOWLAN_TSC_RSC_PARAM),
+       HCMD_NAME(WOWLAN_TKIP_PARAM),
+       HCMD_NAME(WOWLAN_KEK_KCK_MATERIAL),
+       HCMD_NAME(WOWLAN_GET_STATUSES),
+       HCMD_NAME(WOWLAN_TX_POWER_PER_DB),
+       HCMD_NAME(SCAN_ITERATION_COMPLETE),
+       HCMD_NAME(D0I3_END_CMD),
+       HCMD_NAME(LTR_CONFIG),
+       HCMD_NAME(REPLY_DEBUG_CMD),
+};
+
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search
+ */
+static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
+       HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
+       HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE),
+};
+
+static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
+       [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
+       [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
+       [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names),
 };
-#undef CMD
+
 
 /* this forward declaration can avoid to export the function */
 static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
@@ -508,13 +533,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
                trans_cfg.bc_table_dword = true;
 
-       trans_cfg.command_names = iwl_mvm_cmd_strings;
+       trans_cfg.command_groups = iwl_mvm_groups;
+       trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups);
 
        trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
        trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
        trans_cfg.scd_set_active = true;
 
        trans_cfg.sdio_adma_addr = fw->sdio_adma_addr;
+       trans_cfg.sw_csum_tx = IWL_MVM_SW_TX_CSUM_OFFLOAD;
 
        /* Set a short watchdog for the command queue */
        trans_cfg.cmd_q_wdg_timeout =
@@ -577,9 +604,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                        goto out_free;
 
                mutex_lock(&mvm->mutex);
+               iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE);
                err = iwl_run_init_mvm_ucode(mvm, true);
                if (!err || !iwlmvm_mod_params.init_dbg)
                        iwl_trans_stop_device(trans);
+               iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
                mutex_unlock(&mvm->mutex);
                /* returns 0 if successful, 1 if success but in rfkill */
                if (err < 0 && !iwlmvm_mod_params.init_dbg) {
@@ -607,8 +636,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
 
-       /* rpm starts with a taken ref. only set the appropriate bit here. */
-       mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1;
+       /* rpm starts with a taken reference, we can release it now */
+       iwl_trans_unref(mvm->trans);
 
        iwl_mvm_tof_init(mvm);
 
@@ -793,6 +822,8 @@ 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, rxb, 0);
        else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
                iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
        else
@@ -807,9 +838,9 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
 
        if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
-               iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
+               iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
        else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
-               iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
+               iwl_mvm_rx_phy_cmd_mq(mvm, rxb);
        else
                iwl_mvm_rx_common(mvm, rxb, pkt);
 }
@@ -839,6 +870,18 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
        }
 }
 
+static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode,
+                            const struct iwl_device_cmd *cmd)
+{
+       struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+
+       /*
+        * For now, we only set the CMD_WANT_ASYNC_CALLBACK for ADD_STA
+        * commands that need to block the Tx queues.
+        */
+       iwl_trans_block_txq_ptrs(mvm->trans, false);
+}
+
 static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
@@ -1033,6 +1076,7 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
 
 struct iwl_d0i3_iter_data {
        struct iwl_mvm *mvm;
+       struct ieee80211_vif *connected_vif;
        u8 ap_sta_id;
        u8 vif_count;
        u8 offloading_tid;
@@ -1113,7 +1157,8 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac,
                data->disable_offloading = true;
 
        iwl_mvm_update_d0i3_power_mode(mvm, vif, true, flags);
-       iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading, flags);
+       iwl_mvm_send_proto_offload(mvm, vif, data->disable_offloading,
+                                  false, flags);
 
        /*
         * on init/association, mvm already configures POWER_TABLE_CMD
@@ -1123,6 +1168,12 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac,
         */
        data->ap_sta_id = mvmvif->ap_sta_id;
        data->vif_count++;
+
+       /*
+        * no new commands can be sent at this stage, so it's safe
+        * to save the vif pointer during d0i3 entrance.
+        */
+       data->connected_vif = vif;
 }
 
 static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
@@ -1144,7 +1195,8 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
        mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
        cmd->is_11n_connection = ap_sta->ht_cap.ht_supported;
        cmd->offloading_tid = iter_data->offloading_tid;
-
+       cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING |
+               ENABLE_DHCP_FILTERING;
        /*
         * The d0i3 uCode takes care of the nonqos counters,
         * so configure only the qos seq ones.
@@ -1175,6 +1227,9 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
 
        IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n");
 
+       if (WARN_ON_ONCE(mvm->cur_ucode != IWL_UCODE_REGULAR))
+               return -EINVAL;
+
        set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
 
        /*
@@ -1213,6 +1268,10 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
 
        /* configure wowlan configuration only if needed */
        if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) {
+               iwl_mvm_wowlan_config_key_params(mvm,
+                                                d0i3_iter_data.connected_vif,
+                                                true, flags);
+
                iwl_mvm_set_wowlan_data(mvm, &wowlan_config_cmd,
                                        &d0i3_iter_data);
 
@@ -1242,25 +1301,30 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac,
        iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags);
 }
 
-struct iwl_mvm_wakeup_reason_iter_data {
+struct iwl_mvm_d0i3_exit_work_iter_data {
        struct iwl_mvm *mvm;
+       struct iwl_wowlan_status *status;
        u32 wakeup_reasons;
 };
 
-static void iwl_mvm_d0i3_wakeup_reason_iter(void *_data, u8 *mac,
-                                           struct ieee80211_vif *vif)
+static void iwl_mvm_d0i3_exit_work_iter(void *_data, u8 *mac,
+                                       struct ieee80211_vif *vif)
 {
-       struct iwl_mvm_wakeup_reason_iter_data *data = _data;
+       struct iwl_mvm_d0i3_exit_work_iter_data *data = _data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       u32 reasons = data->wakeup_reasons;
 
-       if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc &&
-           data->mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) {
-               if (data->wakeup_reasons &
-                   IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)
-                       iwl_mvm_connection_loss(data->mvm, vif, "D0i3");
-               else
-                       ieee80211_beacon_loss(vif);
-       }
+       /* consider only the relevant station interface */
+       if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc ||
+           data->mvm->d0i3_ap_sta_id != mvmvif->ap_sta_id)
+               return;
+
+       if (reasons & IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)
+               iwl_mvm_connection_loss(data->mvm, vif, "D0i3");
+       else if (reasons & IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON)
+               ieee80211_beacon_loss(vif);
+       else
+               iwl_mvm_d0i3_update_keys(data->mvm, vif, data->status);
 }
 
 void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq)
@@ -1326,9 +1390,13 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
                .id = WOWLAN_GET_STATUSES,
                .flags = CMD_HIGH_PRIO | CMD_WANT_SKB,
        };
+       struct iwl_mvm_d0i3_exit_work_iter_data iter_data = {
+               .mvm = mvm,
+       };
+
        struct iwl_wowlan_status *status;
        int ret;
-       u32 handled_reasons, wakeup_reasons = 0;
+       u32 wakeup_reasons = 0;
        __le16 *qos_seq = NULL;
 
        mutex_lock(&mvm->mutex);
@@ -1345,18 +1413,12 @@ static void iwl_mvm_d0i3_exit_work(struct work_struct *wk)
 
        IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons);
 
-       handled_reasons = IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
-                               IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH;
-       if (wakeup_reasons & handled_reasons) {
-               struct iwl_mvm_wakeup_reason_iter_data data = {
-                       .mvm = mvm,
-                       .wakeup_reasons = wakeup_reasons,
-               };
-
-               ieee80211_iterate_active_interfaces(
-                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-                       iwl_mvm_d0i3_wakeup_reason_iter, &data);
-       }
+       iter_data.wakeup_reasons = wakeup_reasons;
+       iter_data.status = status;
+       ieee80211_iterate_active_interfaces(mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_d0i3_exit_work_iter,
+                                           &iter_data);
 out:
        iwl_mvm_d0i3_enable_tx(mvm, qos_seq);
 
@@ -1382,6 +1444,9 @@ int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm)
 
        IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n");
 
+       if (WARN_ON_ONCE(mvm->cur_ucode != IWL_UCODE_REGULAR))
+               return -EINVAL;
+
        mutex_lock(&mvm->d0i3_suspend_mutex);
        if (test_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags)) {
                IWL_DEBUG_RPM(mvm, "Deferring d0i3 exit until resume\n");
@@ -1414,6 +1479,7 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
 
 #define IWL_MVM_COMMON_OPS                                     \
        /* these could be differentiated */                     \
+       .async_cb = iwl_mvm_async_cb,                           \
        .queue_full = iwl_mvm_stop_sw_queue,                    \
        .queue_not_full = iwl_mvm_wake_sw_queue,                \
        .hw_rf_kill = iwl_mvm_set_hw_rfkill_state,              \
@@ -1438,8 +1504,12 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
                              unsigned int queue)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
-       iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
+       if (unlikely(pkt->hdr.cmd == FRAME_RELEASE))
+               iwl_mvm_rx_frame_release(mvm, rxb, queue);
+       else
+               iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue);
 }
 
 static const struct iwl_op_mode_ops iwl_mvm_ops_mq = {
index e68a475..6e6a56f 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index bed9696..87a9f24 100644 (file)
@@ -27,7 +27,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 509a66d..0b762b4 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 54789bd..7bb6fd0 100644 (file)
@@ -20,7 +20,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -552,9 +552,10 @@ static char *rs_pretty_rate(const struct rs_rate *rate)
        };
        const char *rate_str;
 
-       if (is_type_legacy(rate->type))
+       if (is_type_legacy(rate->type) && (rate->index <= IWL_RATE_54M_INDEX))
                rate_str = legacy_rates[rate->index];
-       else if (is_type_ht(rate->type) || is_type_vht(rate->type))
+       else if ((is_type_ht(rate->type) || is_type_vht(rate->type)) &&
+                (rate->index <= IWL_RATE_MCS_9_INDEX))
                rate_str = ht_vht_rates[rate->index];
        else
                rate_str = "BAD_RATE";
@@ -2550,6 +2551,8 @@ static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = {
        { S8_MIN, IWL_RATE_MCS_0_INDEX },
 };
 
+#define IWL_RS_LOW_RSSI_THRESHOLD (-76) /* dBm */
+
 /* Init the optimal rate based on STA caps
  * This combined with rssi is used to report the last tx rate
  * to userspace when we haven't transmitted enough frames.
@@ -2635,11 +2638,13 @@ static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm,
  * of last Rx
  */
 static void rs_get_initial_rate(struct iwl_mvm *mvm,
+                               struct ieee80211_sta *sta,
                                struct iwl_lq_sta *lq_sta,
                                enum ieee80211_band band,
                                struct rs_rate *rate)
 {
        int i, nentries;
+       unsigned long active_rate;
        s8 best_rssi = S8_MIN;
        u8 best_ant = ANT_NONE;
        u8 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
@@ -2680,19 +2685,55 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
                nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy);
        }
 
-       if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) {
-               for (i = 0; i < nentries; i++) {
-                       int rate_idx = initial_rates[i].rate_idx;
-                       if ((best_rssi >= initial_rates[i].rssi) &&
-                           (BIT(rate_idx) & lq_sta->active_legacy_rate)) {
-                               rate->index = rate_idx;
-                               break;
-                       }
+       if (!IWL_MVM_RS_RSSI_BASED_INIT_RATE)
+               goto out;
+
+       /* Start from a higher rate if the corresponding debug capability
+        * is enabled. The rate is chosen according to AP capabilities.
+        * In case of VHT/HT when the rssi is low fallback to the case of
+        * legacy rates.
+        */
+       if (sta->vht_cap.vht_supported &&
+           best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
+               if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
+                       initial_rates = rs_optimal_rates_vht_40_80mhz;
+                       nentries = ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz);
+                       if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
+                               rate->bw = RATE_MCS_CHAN_WIDTH_80;
+                       else
+                               rate->bw = RATE_MCS_CHAN_WIDTH_40;
+               } else if (sta->bandwidth == IEEE80211_STA_RX_BW_20) {
+                       initial_rates = rs_optimal_rates_vht_20mhz;
+                       nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz);
+                       rate->bw = RATE_MCS_CHAN_WIDTH_20;
+               } else {
+                       IWL_ERR(mvm, "Invalid BW %d\n", sta->bandwidth);
+                       goto out;
                }
+               active_rate = lq_sta->active_siso_rate;
+               rate->type = LQ_VHT_SISO;
+       } else if (sta->ht_cap.ht_supported &&
+                  best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
+               initial_rates = rs_optimal_rates_ht;
+               nentries = ARRAY_SIZE(rs_optimal_rates_ht);
+               active_rate = lq_sta->active_siso_rate;
+               rate->type = LQ_HT_SISO;
+       } else {
+               active_rate = lq_sta->active_legacy_rate;
        }
 
-       IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index,
-                      rs_pretty_ant(rate->ant));
+       for (i = 0; i < nentries; i++) {
+               int rate_idx = initial_rates[i].rate_idx;
+
+               if ((best_rssi >= initial_rates[i].rssi) &&
+                   (BIT(rate_idx) & active_rate)) {
+                       rate->index = rate_idx;
+                       break;
+               }
+       }
+
+out:
+       rs_dump_rate(mvm, rate, "INITIAL");
 }
 
 /* Save info about RSSI of last Rx */
@@ -2752,14 +2793,11 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        tbl = &(lq_sta->lq_info[active_tbl]);
        rate = &tbl->rate;
 
-       rs_get_initial_rate(mvm, lq_sta, band, rate);
+       rs_get_initial_rate(mvm, sta, lq_sta, band, rate);
        rs_init_optimal_rate(mvm, sta, lq_sta);
 
        WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B);
-       if (rate->ant == ANT_A)
-               tbl->column = RS_COLUMN_LEGACY_ANT_A;
-       else
-               tbl->column = RS_COLUMN_LEGACY_ANT_B;
+       tbl->column = rs_get_column_from_rate(rate);
 
        rs_set_expected_tpt_table(lq_sta, tbl);
        rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
index 81314ad..bdb6f2d 100644 (file)
@@ -20,7 +20,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
index a0e957a..145ec68 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
new file mode 100644 (file)
index 0000000..e2a872d
--- /dev/null
@@ -0,0 +1,378 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2015        Intel Deutschland GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2015        Intel Deutschland GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "iwl-trans.h"
+#include "mvm.h"
+#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 void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
+                                           struct napi_struct *napi,
+                                           struct sk_buff *skb,
+                                           struct ieee80211_hdr *hdr, u16 len,
+                                           u32 ampdu_status, u8 crypt_len,
+                                           struct iwl_rx_cmd_buffer *rxb)
+{
+       unsigned int hdrlen, fraglen;
+
+       /* If frame is small enough to fit in skb->head, pull it completely.
+        * If not, only pull ieee80211_hdr (including crypto if present, and
+        * an additional 8 bytes for SNAP/ethertype, see below) so that
+        * splice() or TCP coalesce are more efficient.
+        *
+        * Since, in addition, ieee80211_data_to_8023() always pull in at
+        * least 8 bytes (possibly more for mesh) we can do the same here
+        * to save the cost of doing it later. That still doesn't pull in
+        * the actual IP header since the typical case has a SNAP header.
+        * If the latter changes (there are efforts in the standards group
+        * to do so) we should revisit this and ieee80211_data_to_8023().
+        */
+       hdrlen = (len <= skb_tailroom(skb)) ? len :
+                                             sizeof(*hdr) + crypt_len + 8;
+
+       memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
+       fraglen = len - hdrlen;
+
+       if (fraglen) {
+               int offset = (void *)hdr + hdrlen -
+                            rxb_addr(rxb) + rxb_offset(rxb);
+
+               skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
+                               fraglen, rxb->truesize);
+       }
+
+       ieee80211_rx_napi(mvm->hw, skb, napi);
+}
+
+static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
+                                       struct iwl_rx_mpdu_desc *desc,
+                                       struct ieee80211_rx_status *rx_status)
+{
+       int energy_a, energy_b, energy_c, max_energy;
+
+       energy_a = desc->energy_a;
+       energy_a = energy_a ? -energy_a : S8_MIN;
+       energy_b = desc->energy_b;
+       energy_b = energy_b ? -energy_b : S8_MIN;
+       energy_c = desc->energy_c;
+       energy_c = energy_c ? -energy_c : S8_MIN;
+       max_energy = max(energy_a, energy_b);
+       max_energy = max(max_energy, energy_c);
+
+       IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n",
+                       energy_a, energy_b, energy_c, max_energy);
+
+       rx_status->signal = max_energy;
+       rx_status->chains = 0; /* TODO: phy info */
+       rx_status->chain_signal[0] = energy_a;
+       rx_status->chain_signal[1] = energy_b;
+       rx_status->chain_signal[2] = energy_c;
+}
+
+static u32 iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
+                            struct ieee80211_rx_status *stats,
+                            struct iwl_rx_mpdu_desc *desc, int queue,
+                            u8 *crypt_len)
+{
+       u16 status = le16_to_cpu(desc->status);
+
+       if (!ieee80211_has_protected(hdr->frame_control) ||
+           (status & IWL_RX_MPDU_STATUS_SEC_MASK) ==
+           IWL_RX_MPDU_STATUS_SEC_NONE)
+               return 0;
+
+       /* TODO: handle packets encrypted with unknown alg */
+
+       switch (status & IWL_RX_MPDU_STATUS_SEC_MASK) {
+       case IWL_RX_MPDU_STATUS_SEC_CCM:
+       case IWL_RX_MPDU_STATUS_SEC_GCM:
+               /* alg is CCM: check MIC only */
+               if (!(status & IWL_RX_MPDU_STATUS_MIC_OK))
+                       return -1;
+
+               stats->flag |= RX_FLAG_DECRYPTED;
+               *crypt_len = IEEE80211_CCMP_HDR_LEN;
+               return 0;
+       case IWL_RX_MPDU_STATUS_SEC_TKIP:
+               /* Don't drop the frame and decrypt it in SW */
+               if (!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK))
+                       return 0;
+
+               *crypt_len = IEEE80211_TKIP_IV_LEN;
+               /* fall through if TTAK OK */
+       case IWL_RX_MPDU_STATUS_SEC_WEP:
+               if (!(status & IWL_RX_MPDU_STATUS_ICV_OK))
+                       return -1;
+
+               stats->flag |= RX_FLAG_DECRYPTED;
+               if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) ==
+                               IWL_RX_MPDU_STATUS_SEC_WEP)
+                       *crypt_len = IEEE80211_WEP_IV_LEN;
+               return 0;
+       case IWL_RX_MPDU_STATUS_SEC_EXT_ENC:
+               if (!(status & IWL_RX_MPDU_STATUS_MIC_OK))
+                       return -1;
+               stats->flag |= RX_FLAG_DECRYPTED;
+               return 0;
+       default:
+               IWL_ERR(mvm, "Unhandled alg: 0x%x\n", status);
+       }
+
+       return 0;
+}
+
+static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
+                           struct sk_buff *skb,
+                           struct iwl_rx_mpdu_desc *desc)
+{
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
+
+       if (mvmvif->features & NETIF_F_RXCSUM &&
+           desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_IP_HDR_CSUM_OK) &&
+           desc->l3l4_flags & cpu_to_le16(IWL_RX_L3L4_TCP_UDP_CSUM_OK))
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
+void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
+                       struct iwl_rx_cmd_buffer *rxb, int queue)
+{
+       struct ieee80211_rx_status *rx_status;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_rx_mpdu_desc *desc = (void *)pkt->data;
+       struct ieee80211_hdr *hdr = (void *)(desc + 1);
+       u32 len = le16_to_cpu(desc->mpdu_len);
+       u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
+       struct ieee80211_sta *sta = NULL;
+       struct sk_buff *skb;
+       u32 ampdu_status;
+       u8 crypt_len = 0;
+
+       /* Dont use dev_alloc_skb(), we'll have enough headroom once
+        * ieee80211_hdr pulled.
+        */
+       skb = alloc_skb(128, GFP_ATOMIC);
+       if (!skb) {
+               IWL_ERR(mvm, "alloc_skb failed\n");
+               return;
+       }
+
+       rx_status = IEEE80211_SKB_RXCB(skb);
+
+       if (iwl_mvm_rx_crypto(mvm, hdr, rx_status, desc, queue, &crypt_len)) {
+               kfree_skb(skb);
+               return;
+       }
+
+       /*
+        * Keep packets with CRC errors (and with overrun) for monitor mode
+        * (otherwise the firmware discards them) but mark them as bad.
+        */
+       if (!(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_CRC_OK)) ||
+           !(desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_OVERRUN_OK))) {
+               IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n",
+                            le16_to_cpu(desc->status));
+               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+       }
+
+       rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
+       rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise);
+       rx_status->band = desc->channel > 14 ? IEEE80211_BAND_5GHZ :
+                                              IEEE80211_BAND_2GHZ;
+       rx_status->freq = ieee80211_channel_to_frequency(desc->channel,
+                                                        rx_status->band);
+       iwl_mvm_get_signal_strength(mvm, desc, rx_status);
+
+       rcu_read_lock();
+
+       if (le16_to_cpu(desc->status) & IWL_RX_MPDU_STATUS_SRC_STA_FOUND) {
+               u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK;
+
+               if (!WARN_ON_ONCE(id >= IWL_MVM_STATION_COUNT)) {
+                       sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
+                       if (IS_ERR(sta))
+                               sta = NULL;
+               }
+       } else if (!is_multicast_ether_addr(hdr->addr2)) {
+               /*
+                * This is fine since we prevent two stations with the same
+                * address from being added.
+                */
+               sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
+       }
+
+       if (sta) {
+               struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+               /*
+                * 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);
+
+               rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
+
+               if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
+                   ieee80211_is_beacon(hdr->frame_control)) {
+                       struct iwl_fw_dbg_trigger_tlv *trig;
+                       struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
+                       bool trig_check;
+                       s32 rssi;
+
+                       trig = iwl_fw_dbg_get_trigger(mvm->fw,
+                                                     FW_DBG_TRIGGER_RSSI);
+                       rssi_trig = (void *)trig->data;
+                       rssi = le32_to_cpu(rssi_trig->rssi);
+
+                       trig_check =
+                               iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif,
+                                                             trig);
+                       if (trig_check && rx_status->signal < rssi)
+                               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);
+       }
+
+       rcu_read_unlock();
+
+       /*
+        * 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:
+               break;
+       case RATE_MCS_CHAN_WIDTH_40:
+               rx_status->flag |= RX_FLAG_40MHZ;
+               break;
+       case RATE_MCS_CHAN_WIDTH_80:
+               rx_status->vht_flag |= RX_VHT_FLAG_80MHZ;
+               break;
+       case RATE_MCS_CHAN_WIDTH_160:
+               rx_status->vht_flag |= RX_VHT_FLAG_160MHZ;
+               break;
+       }
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               rx_status->flag |= RX_FLAG_SHORT_GI;
+       if (rate_n_flags & RATE_HT_MCS_GF_MSK)
+               rx_status->flag |= RX_FLAG_HT_GF;
+       if (rate_n_flags & RATE_MCS_LDPC_MSK)
+               rx_status->flag |= RX_FLAG_LDPC;
+       if (rate_n_flags & RATE_MCS_HT_MSK) {
+               u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >>
+                               RATE_MCS_STBC_POS;
+               rx_status->flag |= RX_FLAG_HT;
+               rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+               rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT;
+       } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+               u8 stbc = (rate_n_flags & RATE_MCS_VHT_STBC_MSK) >>
+                               RATE_MCS_STBC_POS;
+               rx_status->vht_nss =
+                       ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
+                                               RATE_VHT_MCS_NSS_POS) + 1;
+               rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+               rx_status->flag |= RX_FLAG_VHT;
+               rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT;
+               if (rate_n_flags & RATE_MCS_BF_MSK)
+                       rx_status->vht_flag |= RX_VHT_FLAG_BF;
+       } else {
+               rx_status->rate_idx =
+                       iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
+                                                           rx_status->band);
+       }
+
+       /* TODO: PHY info - update ampdu queue statistics (for debugfs) */
+       /* TODO: PHY info - gscan */
+
+       iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status,
+                                       crypt_len, rxb);
+}
+
+void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
+                             struct iwl_rx_cmd_buffer *rxb, int queue)
+{
+       /* TODO */
+}
index 7cbfb08..bee3201 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
 #define IWL_DENSE_EBS_SCAN_RATIO 5
 #define IWL_SPARSE_EBS_SCAN_RATIO 1
 
-enum iwl_mvm_scan_type {
-       IWL_SCAN_TYPE_UNASSOC,
-       IWL_SCAN_TYPE_WILD,
-       IWL_SCAN_TYPE_MILD,
-       IWL_SCAN_TYPE_FRAGMENTED,
-};
-
 enum iwl_mvm_traffic_load {
        IWL_MVM_TRAFFIC_LOW,
        IWL_MVM_TRAFFIC_MEDIUM,
@@ -89,6 +82,7 @@ struct iwl_mvm_scan_timing_params {
        u32 dwell_active;
        u32 dwell_passive;
        u32 dwell_fragmented;
+       u32 dwell_extended;
        u32 suspend_time;
        u32 max_out_time;
 };
@@ -98,6 +92,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
                .dwell_active = 10,
                .dwell_passive = 110,
                .dwell_fragmented = 44,
+               .dwell_extended = 100,
                .suspend_time = 0,
                .max_out_time = 0,
        },
@@ -105,6 +100,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
                .dwell_active = 10,
                .dwell_passive = 110,
                .dwell_fragmented = 44,
+               .dwell_extended = 100,
                .suspend_time = 30,
                .max_out_time = 120,
        },
@@ -112,6 +108,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
                .dwell_active = 10,
                .dwell_passive = 110,
                .dwell_fragmented = 44,
+               .dwell_extended = 100,
                .suspend_time = 120,
                .max_out_time = 120,
        },
@@ -119,6 +116,7 @@ static struct iwl_mvm_scan_timing_params scan_timing[] = {
                .dwell_active = 10,
                .dwell_passive = 110,
                .dwell_fragmented = 44,
+               .dwell_extended = 44,
                .suspend_time = 95,
                .max_out_time = 44,
        },
@@ -206,9 +204,7 @@ static enum iwl_mvm_traffic_load iwl_mvm_get_traffic_load(struct iwl_mvm *mvm)
 }
 
 static enum
-iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm,
-                                       struct ieee80211_vif *vif,
-                                       struct iwl_mvm_scan_params *params)
+iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device)
 {
        int global_cnt = 0;
        enum iwl_mvm_traffic_load load;
@@ -224,8 +220,7 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm,
        load = iwl_mvm_get_traffic_load(mvm);
        low_latency = iwl_mvm_low_latency(mvm);
 
-       if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) &&
-           vif->type != NL80211_IFTYPE_P2P_DEVICE &&
+       if ((load == IWL_MVM_TRAFFIC_HIGH || low_latency) && !p2p_device &&
            fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAGMENTED_SCAN))
                return IWL_SCAN_TYPE_FRAGMENTED;
 
@@ -726,6 +721,7 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm,
        cmd->active_dwell = scan_timing[params->type].dwell_active;
        cmd->passive_dwell = scan_timing[params->type].dwell_passive;
        cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented;
+       cmd->extended_dwell = scan_timing[params->type].dwell_extended;
        cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time);
        cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time);
        cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
@@ -759,8 +755,15 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
                vif->type != NL80211_IFTYPE_P2P_DEVICE);
 }
 
+static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params)
+{
+       return params->n_scan_plans == 1 &&
+               params->scan_plans[0].iterations == 1;
+}
+
 static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
-                                  struct iwl_mvm_scan_params *params)
+                                  struct iwl_mvm_scan_params *params,
+                                  struct ieee80211_vif *vif)
 {
        int flags = 0;
 
@@ -786,6 +789,10 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
                flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
 #endif
 
+       if (iwl_mvm_is_regular_scan(params) &&
+           vif->type != NL80211_IFTYPE_P2P_DEVICE)
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_EXTENDED_DWELL;
+
        return flags;
 }
 
@@ -814,7 +821,8 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        cmd->delay = cpu_to_le32(params->delay);
 
-       cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params));
+       cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params,
+                                                             vif));
 
        cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band);
        cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
@@ -917,18 +925,20 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
        struct iwl_host_cmd cmd = {
                .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0),
        };
+       enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, false);
 
        if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels))
                return -ENOBUFS;
 
+       if (type == mvm->scan_type)
+               return 0;
+
        cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels;
 
        scan_config = kzalloc(cmd_size, GFP_KERNEL);
        if (!scan_config)
                return -ENOMEM;
 
-       mvm->scan_fragmented = iwl_mvm_low_latency(mvm);
-
        scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE |
                                         SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS |
                                         SCAN_CONFIG_FLAG_SET_TX_CHAINS |
@@ -938,17 +948,19 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
                                         SCAN_CONFIG_FLAG_SET_MAC_ADDR |
                                         SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
                                         SCAN_CONFIG_N_CHANNELS(num_channels) |
-                                        (mvm->scan_fragmented ?
+                                        (type == IWL_SCAN_TYPE_FRAGMENTED ?
                                          SCAN_CONFIG_FLAG_SET_FRAGMENTED :
                                          SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED));
        scan_config->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
        scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm));
        scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm);
-       scan_config->out_of_channel_time = cpu_to_le32(170);
-       scan_config->suspend_time = cpu_to_le32(30);
-       scan_config->dwell_active = 20;
-       scan_config->dwell_passive = 110;
-       scan_config->dwell_fragmented = 20;
+       scan_config->out_of_channel_time =
+               cpu_to_le32(scan_timing[type].max_out_time);
+       scan_config->suspend_time = cpu_to_le32(scan_timing[type].suspend_time);
+       scan_config->dwell_active = scan_timing[type].dwell_active;
+       scan_config->dwell_passive = scan_timing[type].dwell_passive;
+       scan_config->dwell_fragmented = scan_timing[type].dwell_fragmented;
+       scan_config->dwell_extended = scan_timing[type].dwell_extended;
 
        memcpy(&scan_config->mac_addr, &mvm->addresses[0].addr, ETH_ALEN);
 
@@ -972,6 +984,8 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
        IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n");
 
        ret = iwl_mvm_send_cmd(mvm, &cmd);
+       if (!ret)
+               mvm->scan_type = type;
 
        kfree(scan_config);
        return ret;
@@ -988,16 +1002,11 @@ static int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status)
        return -ENOENT;
 }
 
-static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params)
-{
-       return params->n_scan_plans == 1 &&
-               params->scan_plans[0].iterations == 1;
-}
-
 static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
                                    struct iwl_scan_req_umac *cmd,
                                    struct iwl_mvm_scan_params *params)
 {
+       cmd->extended_dwell = scan_timing[params->type].dwell_extended;
        cmd->active_dwell = scan_timing[params->type].dwell_active;
        cmd->passive_dwell = scan_timing[params->type].dwell_passive;
        cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented;
@@ -1032,7 +1041,8 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
 }
 
 static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
-                                  struct iwl_mvm_scan_params *params)
+                                  struct iwl_mvm_scan_params *params,
+                                  struct ieee80211_vif *vif)
 {
        int flags = 0;
 
@@ -1060,6 +1070,11 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
        if (mvm->scan_iter_notif_enabled)
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
 #endif
+
+       if (iwl_mvm_is_regular_scan(params) &&
+           vif->type != NL80211_IFTYPE_P2P_DEVICE)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL;
+
        return flags;
 }
 
@@ -1090,7 +1105,8 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        mvm->scan_uid_status[uid] = type;
 
        cmd->uid = cpu_to_le32(uid);
-       cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params));
+       cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params,
+                                                                vif));
 
        if (type == IWL_MVM_SCAN_SCHED)
                cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
@@ -1225,7 +1241,9 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        params.scan_plans = &scan_plan;
        params.n_scan_plans = 1;
 
-       params.type = iwl_mvm_get_scan_type(mvm, vif, &params);
+       params.type =
+               iwl_mvm_get_scan_type(mvm,
+                                     vif->type == NL80211_IFTYPE_P2P_DEVICE);
 
        iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
 
@@ -1307,7 +1325,9 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
        params.n_scan_plans = req->n_scan_plans;
        params.scan_plans = req->scan_plans;
 
-       params.type = iwl_mvm_get_scan_type(mvm, vif, &params);
+       params.type =
+               iwl_mvm_get_scan_type(mvm,
+                                     vif->type == NL80211_IFTYPE_P2P_DEVICE);
 
        /* In theory, LMAC scans can handle a 32-bit delay, but since
         * waiting for over 18 hours to start the scan is a bit silly
index 354acbd..b556e33 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -106,6 +106,7 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                .add_modify = update ? 1 : 0,
                .station_flags_msk = cpu_to_le32(STA_FLG_FAT_EN_MSK |
                                                 STA_FLG_MIMO_EN_MSK),
+               .tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg),
        };
        int ret;
        u32 status;
@@ -277,11 +278,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
        if (sta_id == IWL_MVM_STATION_COUNT)
                return -ENOSPC;
 
-       if (vif->type == NL80211_IFTYPE_AP) {
-               mvmvif->ap_assoc_sta_count++;
-               iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
-       }
-
        spin_lock_init(&mvm_sta->lock);
 
        mvm_sta->sta_id = sta_id;
@@ -580,9 +576,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
        return ret;
 }
 
-static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
-                                   struct iwl_mvm_int_sta *sta,
-                                   u32 qmask, enum nl80211_iftype iftype)
+int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
+                            struct iwl_mvm_int_sta *sta,
+                            u32 qmask, enum nl80211_iftype iftype)
 {
        if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
                sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
@@ -622,6 +618,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
                                                             color));
 
        cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk);
+       cmd.tid_disable_tx = cpu_to_le16(0xffff);
 
        if (addr)
                memcpy(cmd.addr, addr, ETH_ALEN);
@@ -671,6 +668,33 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
        return ret;
 }
 
+int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       lockdep_assert_held(&mvm->mutex);
+       return iwl_mvm_add_int_sta_common(mvm, &mvm->snif_sta, vif->addr,
+                                        mvmvif->id, 0);
+}
+
+int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+       int ret;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);
+       if (ret)
+               IWL_WARN(mvm, "Failed sending remove station\n");
+
+       return ret;
+}
+
+void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm)
+{
+       iwl_mvm_dealloc_int_sta(mvm, &mvm->snif_sta);
+}
+
 void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm)
 {
        lockdep_assert_held(&mvm->mutex);
@@ -1196,22 +1220,17 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
        if (max_offs < 0)
                return STA_KEY_IDX_INVALID;
 
-       __set_bit(max_offs, mvm->fw_key_table);
-
        return max_offs;
 }
 
-static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm,
-                                struct ieee80211_vif *vif,
-                                struct ieee80211_sta *sta)
+static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm,
+                                              struct ieee80211_vif *vif,
+                                              struct ieee80211_sta *sta)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
-       if (sta) {
-               struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
-
-               return mvm_sta->sta_id;
-       }
+       if (sta)
+               return iwl_mvm_sta_from_mac80211(sta);
 
        /*
         * The device expects GTKs for station interfaces to be
@@ -1222,20 +1241,20 @@ static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm,
            mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
                u8 sta_id = mvmvif->ap_sta_id;
 
-               sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
-                                               lockdep_is_held(&mvm->mutex));
+               sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
+                                           lockdep_is_held(&mvm->mutex));
                /*
                 * It is possible that the 'sta' parameter is NULL,
                 * for example when a GTK is removed - the sta_id will then
                 * be the AP ID, and no station was passed by mac80211.
                 */
                if (IS_ERR_OR_NULL(sta))
-                       return IWL_MVM_STATION_COUNT;
+                       return NULL;
 
-               return sta_id;
+               return iwl_mvm_sta_from_mac80211(sta);
        }
 
-       return IWL_MVM_STATION_COUNT;
+       return NULL;
 }
 
 static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
@@ -1452,6 +1471,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                        u8 key_offset)
 {
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
+       struct iwl_mvm_sta *mvm_sta;
        u8 sta_id;
        int ret;
        static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0};
@@ -1459,11 +1479,12 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        lockdep_assert_held(&mvm->mutex);
 
        /* Get the station id from the mvm local station table */
-       sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
-       if (sta_id == IWL_MVM_STATION_COUNT) {
-               IWL_ERR(mvm, "Failed to find station id\n");
+       mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
+       if (!mvm_sta) {
+               IWL_ERR(mvm, "Failed to find station\n");
                return -EINVAL;
        }
+       sta_id = mvm_sta->sta_id;
 
        if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
                ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
@@ -1505,10 +1526,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
        }
 
        ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast);
-       if (ret) {
-               __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
+       if (ret)
                goto end;
-       }
 
        /*
         * For WEP, the same key is used for multicast and unicast. Upload it
@@ -1521,11 +1540,13 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf,
                                            key_offset, !mcast);
                if (ret) {
-                       __clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
                        __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
+                       goto end;
                }
        }
 
+       __set_bit(key_offset, mvm->fw_key_table);
+
 end:
        IWL_DEBUG_WEP(mvm, "key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n",
                      keyconf->cipher, keyconf->keylen, keyconf->keyidx,
@@ -1539,13 +1560,14 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
                           struct ieee80211_key_conf *keyconf)
 {
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
-       u8 sta_id;
+       struct iwl_mvm_sta *mvm_sta;
+       u8 sta_id = IWL_MVM_STATION_COUNT;
        int ret, i;
 
        lockdep_assert_held(&mvm->mutex);
 
-       /* Get the station id from the mvm local station table */
-       sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
+       /* Get the station from the mvm local station table */
+       mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
 
        IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
                      keyconf->keyidx, sta_id);
@@ -1566,11 +1588,13 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
        }
        mvm->fw_key_deleted[keyconf->hw_key_idx] = 0;
 
-       if (sta_id == IWL_MVM_STATION_COUNT) {
+       if (!mvm_sta) {
                IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
                return 0;
        }
 
+       sta_id = mvm_sta->sta_id;
+
        ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
        if (ret)
                return ret;
@@ -1590,25 +1614,17 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
                             u16 *phase1key)
 {
        struct iwl_mvm_sta *mvm_sta;
-       u8 sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
        bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
 
-       if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
-               return;
-
        rcu_read_lock();
 
-       if (!sta) {
-               sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
-               if (WARN_ON(IS_ERR_OR_NULL(sta))) {
-                       rcu_read_unlock();
-                       return;
-               }
-       }
-
-       mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+       mvm_sta = iwl_mvm_get_key_sta(mvm, vif, sta);
+       if (WARN_ON_ONCE(!mvm_sta))
+               goto unlock;
        iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
                             iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
+
+ unlock:
        rcu_read_unlock();
 }
 
@@ -1662,6 +1678,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
         */
        if (agg) {
                int remaining = cnt;
+               int sleep_tx_count;
 
                spin_lock_bh(&mvmsta->lock);
                for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) {
@@ -1686,9 +1703,12 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
                        }
                        remaining -= n_queued;
                }
+               sleep_tx_count = cnt - remaining;
+               if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
+                       mvmsta->sleep_tx_count = sleep_tx_count;
                spin_unlock_bh(&mvmsta->lock);
 
-               cmd.sleep_tx_count = cpu_to_le16(cnt - remaining);
+               cmd.sleep_tx_count = cpu_to_le16(sleep_tx_count);
                if (WARN_ON(cnt - remaining == 0)) {
                        ieee80211_sta_eosp(sta);
                        return;
@@ -1706,7 +1726,12 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
                cmd.sleep_state_flags |= cpu_to_le16(STA_SLEEP_STATE_UAPSD);
        }
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+       /* block the Tx queues until the FW updated the sleep Tx count */
+       iwl_trans_block_txq_ptrs(mvm->trans, true);
+
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA,
+                                  CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK,
+                                  sizeof(cmd), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
index 0631cc0..badf17c 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -303,6 +303,11 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
  * @tt_tx_protection: is thermal throttling enable Tx protection?
  * @disable_tx: is tx to this STA disabled?
  * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
+ * @sleep_tx_count: the number of frames that we told the firmware to let out
+ *     even when that station is asleep. This is useful in case the queue
+ *     gets empty before all the frames were sent, which can happen when
+ *     we are sending frames from an AMPDU queue and there was a hole in
+ *     the BA window. To be used for UAPSD only.
  *
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is placed in that
@@ -329,6 +334,7 @@ struct iwl_mvm_sta {
 
        bool disable_tx;
        u8 agg_tids;
+       u8 sleep_tx_count;
 };
 
 static inline struct iwl_mvm_sta *
@@ -401,7 +407,13 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
+                            struct iwl_mvm_int_sta *sta,
+                                   u32 qmask, enum nl80211_iftype iftype);
 void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm);
 
 void iwl_mvm_sta_drained_wk(struct work_struct *wk);
 void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
index fe2fa56..18711c5 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 87a04c3..924dd6a 100644 (file)
@@ -792,11 +792,9 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
 }
 
-void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
+static struct iwl_mvm_time_event_data *iwl_mvm_get_roc_te(struct iwl_mvm *mvm)
 {
-       struct iwl_mvm_vif *mvmvif = NULL;
        struct iwl_mvm_time_event_data *te_data;
-       bool is_p2p = false;
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -810,11 +808,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
         * request
         */
        list_for_each_entry(te_data, &mvm->time_event_list, list) {
-               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
-                       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
-                       is_p2p = true;
-                       goto remove_te;
-               }
+               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE)
+                       goto out;
        }
 
        /* There can only be at most one AUX ROC time event, we just use the
@@ -823,18 +818,35 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
        te_data = list_first_entry_or_null(&mvm->aux_roc_te_list,
                                           struct iwl_mvm_time_event_data,
                                           list);
+out:
+       spin_unlock_bh(&mvm->time_event_lock);
+       return te_data;
+}
+
+void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm)
+{
+       struct iwl_mvm_time_event_data *te_data;
+       u32 uid;
+
+       te_data = iwl_mvm_get_roc_te(mvm);
        if (te_data)
-               mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+               __iwl_mvm_remove_time_event(mvm, te_data, &uid);
+}
 
-remove_te:
-       spin_unlock_bh(&mvm->time_event_lock);
+void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
+{
+       struct iwl_mvm_vif *mvmvif;
+       struct iwl_mvm_time_event_data *te_data;
 
-       if (!mvmvif) {
+       te_data = iwl_mvm_get_roc_te(mvm);
+       if (!te_data) {
                IWL_WARN(mvm, "No remain on channel event\n");
                return;
        }
 
-       if (is_p2p)
+       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+
+       if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE)
                iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
        else
                iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data);
index 61d7cd7..99d9a35 100644 (file)
@@ -215,6 +215,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
 void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
                           struct iwl_mvm_time_event_data *te_data);
 
+void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm);
 void iwl_mvm_roc_done_wk(struct work_struct *wk);
 
 /**
index 4007f1d..a1947d6 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 9beebc3..8c3421c 100644 (file)
@@ -25,7 +25,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index aaebb5d..8bf48a7 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -64,6 +64,7 @@
  *****************************************************************************/
 #include <linux/ieee80211.h>
 #include <linux/etherdevice.h>
+#include <linux/tcp.h>
 
 #include "iwl-trans.h"
 #include "iwl-eeprom-parse.h"
@@ -345,8 +346,8 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
        iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
 
        memset(&info->status, 0, sizeof(info->status));
+       memset(info->driver_data, 0, sizeof(info->driver_data));
 
-       info->driver_data[0] = NULL;
        info->driver_data[1] = dev_cmd;
 
        return dev_cmd;
@@ -425,11 +426,39 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
        return 0;
 }
 
+static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb_gso,
+                         struct ieee80211_sta *sta,
+                         struct sk_buff_head *mpdus_skb)
+{
+       struct sk_buff *tmp, *next;
+       char cb[sizeof(skb_gso->cb)];
+
+       memcpy(cb, skb_gso->cb, sizeof(cb));
+       next = skb_gso_segment(skb_gso, 0);
+       if (IS_ERR(next))
+               return -EINVAL;
+       else if (next)
+               consume_skb(skb_gso);
+
+       while (next) {
+               tmp = next;
+               next = tmp->next;
+               memcpy(tmp->cb, cb, sizeof(tmp->cb));
+
+               tmp->prev = NULL;
+               tmp->next = NULL;
+
+               __skb_queue_tail(mpdus_skb, tmp);
+       }
+
+       return 0;
+}
+
 /*
  * Sets the fields in the Tx cmd that are crypto related
  */
-int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
-                  struct ieee80211_sta *sta)
+static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
+                          struct ieee80211_sta *sta)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -525,6 +554,51 @@ drop:
        return -1;
 }
 
+int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
+                  struct ieee80211_sta *sta)
+{
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct sk_buff_head mpdus_skbs;
+       unsigned int payload_len;
+       int ret;
+
+       if (WARN_ON_ONCE(!mvmsta))
+               return -1;
+
+       if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
+               return -1;
+
+       if (!skb_is_gso(skb))
+               return iwl_mvm_tx_mpdu(mvm, skb, sta);
+
+       payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
+               tcp_hdrlen(skb) + skb->data_len;
+
+       if (payload_len <= skb_shinfo(skb)->gso_size)
+               return iwl_mvm_tx_mpdu(mvm, skb, sta);
+
+       __skb_queue_head_init(&mpdus_skbs);
+
+       ret = iwl_mvm_tx_tso(mvm, skb, sta, &mpdus_skbs);
+       if (ret)
+               return ret;
+
+       if (WARN_ON(skb_queue_empty(&mpdus_skbs)))
+               return ret;
+
+       while (!skb_queue_empty(&mpdus_skbs)) {
+               struct sk_buff *skb = __skb_dequeue(&mpdus_skbs);
+
+               ret = iwl_mvm_tx_mpdu(mvm, skb, sta);
+               if (ret) {
+                       __skb_queue_purge(&mpdus_skbs);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
                                      struct ieee80211_sta *sta, u8 tid)
 {
@@ -788,13 +862,43 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                if (tid != IWL_TID_NON_QOS) {
                        struct iwl_mvm_tid_data *tid_data =
                                &mvmsta->tid_data[tid];
+                       bool send_eosp_ndp = false;
 
                        spin_lock_bh(&mvmsta->lock);
                        tid_data->next_reclaimed = next_reclaimed;
                        IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n",
                                           next_reclaimed);
                        iwl_mvm_check_ratid_empty(mvm, sta, tid);
+
+                       if (mvmsta->sleep_tx_count) {
+                               mvmsta->sleep_tx_count--;
+                               if (mvmsta->sleep_tx_count &&
+                                   !iwl_mvm_tid_queued(tid_data)) {
+                                       /*
+                                        * The number of frames in the queue
+                                        * dropped to 0 even if we sent less
+                                        * frames than we thought we had on the
+                                        * Tx queue.
+                                        * This means we had holes in the BA
+                                        * window that we just filled, ask
+                                        * mac80211 to send EOSP since the
+                                        * firmware won't know how to do that.
+                                        * Send NDP and the firmware will send
+                                        * EOSP notification that will trigger
+                                        * a call to ieee80211_sta_eosp().
+                                        */
+                                       send_eosp_ndp = true;
+                               }
+                       }
+
                        spin_unlock_bh(&mvmsta->lock);
+                       if (send_eosp_ndp) {
+                               iwl_mvm_sta_modify_sleep_tx_count(mvm, sta,
+                                       IEEE80211_FRAME_RELEASE_UAPSD,
+                                       1, tid, false, false);
+                               mvmsta->sleep_tx_count = 0;
+                               ieee80211_send_eosp_nullfunc(sta, tid);
+                       }
                }
 
                if (mvmsta->next_status_eosp) {
index bbb7f6b..3a989f5 100644 (file)
@@ -27,7 +27,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
index 9bdce44..af10651 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -471,19 +471,20 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24F3, 0x0930, iwl8260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x24FD, 0x0000, iwl8265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24F3, 0x0000, iwl8265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x24FD, 0x8010, iwl8265_2ac_cfg)},
 
 /* 9000 Series */
        {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl5165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9260_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl5165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x9DF0, 0x0310, iwl5165_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl9260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9260_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl5165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x9DF0, 0x0510, iwl5165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl5165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x9DF0, 0x0210, iwl9260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x9DF0, 0x0410, iwl9260_2ac_cfg)},
        {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9260_2ac_cfg)},
 #endif /* CONFIG_IWLMVM */
index 44dc09d..cc3888e 100644 (file)
@@ -23,7 +23,7 @@
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
@@ -278,6 +278,7 @@ struct iwl_txq {
        bool frozen;
        u8 active;
        bool ampdu;
+       bool block;
        unsigned long wd_timeout;
 };
 
@@ -288,6 +289,11 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
               sizeof(struct iwl_pcie_txq_scratch_buf) * idx;
 }
 
+struct iwl_tso_hdr_page {
+       struct page *page;
+       u8 *pos;
+};
+
 /**
  * struct iwl_trans_pcie - PCIe transport specific data
  * @rxq: all the RX queue data
@@ -306,6 +312,8 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
  * @scd_set_active: should the transport configure the SCD for HCMD queue
  * @wide_cmd_header: true when ucode supports wide command header format
+ * @sw_csum_tx: if true, then the transport will compute the csum of the TXed
+ *     frame.
  * @rx_page_order: page order for receive buffer size
  * @reg_lock: protect hw register access
  * @mutex: to protect stop_device / start_fw / start_hw
@@ -323,6 +331,8 @@ struct iwl_trans_pcie {
        struct net_device napi_dev;
        struct napi_struct napi;
 
+       struct __percpu iwl_tso_hdr_page *tso_hdr_page;
+
        /* INT ICT Table */
        __le32 *ict_tbl;
        dma_addr_t ict_tbl_dma;
@@ -360,10 +370,9 @@ struct iwl_trans_pcie {
        bool bc_table_dword;
        bool scd_set_active;
        bool wide_cmd_header;
+       bool sw_csum_tx;
        u32 rx_page_order;
 
-       const char *const *command_names;
-
        /*protect hw register */
        spinlock_t reg_lock;
        bool cmd_hold_nic_awake;
@@ -526,14 +535,6 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
        return index & (q->n_window - 1);
 }
 
-static inline const char *get_cmd_string(struct iwl_trans_pcie *trans_pcie,
-                                        u8 cmd)
-{
-       if (!trans_pcie->command_names || !trans_pcie->command_names[cmd])
-               return "UNKNOWN";
-       return trans_pcie->command_names[cmd];
-}
-
 static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
 {
        return !(iwl_read32(trans, CSR_GP_CNTRL) &
index 9193f0c..ccafbd8 100644 (file)
@@ -877,7 +877,10 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                IWL_DEBUG_RX(trans,
                             "cmd at offset %d: %s (0x%.2x, seq 0x%x)\n",
                             rxcb._offset,
-                            get_cmd_string(trans_pcie, pkt->hdr.cmd),
+                            iwl_get_cmd_string(trans,
+                                               iwl_cmd_id(pkt->hdr.cmd,
+                                                          pkt->hdr.group_id,
+                                                          0)),
                             pkt->hdr.cmd, le16_to_cpu(pkt->hdr.sequence));
 
                len = iwl_rx_packet_len(pkt);
index efef487..d44e7af 100644 (file)
@@ -26,7 +26,7 @@
  * in the file called COPYING.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  * BSD LICENSE
@@ -1213,7 +1213,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (trans->wowlan_d0i3) {
+       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) {
                /* Enable persistence mode to avoid reset */
                iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_PERSIST_MODE);
@@ -1237,7 +1237,7 @@ 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);
 
-       if (!trans->wowlan_d0i3) {
+       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D3) {
                /*
                 * reset TX queues -- some of their registers reset during S3
                 * so if we don't reset everything here the D3 image would try
@@ -1286,7 +1286,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
 
        iwl_pcie_set_pwr(trans, false);
 
-       if (trans->wowlan_d0i3) {
+       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) {
                iwl_clear_bit(trans, CSR_GP_CNTRL,
                              CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        } else {
@@ -1440,9 +1440,12 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                iwl_trans_get_rb_size_order(trans_pcie->rx_buf_size);
 
        trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header;
-       trans_pcie->command_names = trans_cfg->command_names;
        trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
        trans_pcie->scd_set_active = trans_cfg->scd_set_active;
+       trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx;
+
+       trans->command_groups = trans_cfg->command_groups;
+       trans->command_groups_size = trans_cfg->command_groups_size;
 
        /* init ref_count to 1 (should be cleared when ucode is loaded) */
        trans_pcie->ref_count = 1;
@@ -1462,6 +1465,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
 void iwl_trans_pcie_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int i;
 
        synchronize_irq(trans_pcie->pci_dev->irq);
 
@@ -1481,6 +1485,15 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
 
        iwl_pcie_free_fw_monitor(trans);
 
+       for_each_possible_cpu(i) {
+               struct iwl_tso_hdr_page *p =
+                       per_cpu_ptr(trans_pcie->tso_hdr_page, i);
+
+               if (p->page)
+                       __free_page(p->page);
+       }
+
+       free_percpu(trans_pcie->tso_hdr_page);
        iwl_trans_free(trans);
 }
 
@@ -1492,8 +1505,8 @@ static void iwl_trans_pcie_set_pmi(struct iwl_trans *trans, bool state)
                clear_bit(STATUS_TPOWER_PMI, &trans->status);
 }
 
-static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
-                                               unsigned long *flags)
+static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
+                                          unsigned long *flags)
 {
        int ret;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1534,14 +1547,11 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
                            CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
        if (unlikely(ret < 0)) {
                iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
-               if (!silent) {
-                       u32 val = iwl_read32(trans, CSR_GP_CNTRL);
-                       WARN_ONCE(1,
-                                 "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
-                                 val);
-                       spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags);
-                       return false;
-               }
+               WARN_ONCE(1,
+                         "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
+                         iwl_read32(trans, CSR_GP_CNTRL));
+               spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags);
+               return false;
        }
 
 out:
@@ -1589,7 +1599,7 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
        int offs, ret = 0;
        u32 *vals = buf;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                iwl_write32(trans, HBUS_TARG_MEM_RADDR, addr);
                for (offs = 0; offs < dwords; offs++)
                        vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT);
@@ -1607,7 +1617,7 @@ static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
        int offs, ret = 0;
        const u32 *vals = buf;
 
-       if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+       if (iwl_trans_grab_nic_access(trans, &flags)) {
                iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
                for (offs = 0; offs < dwords; offs++)
                        iwl_write32(trans, HBUS_TARG_MEM_WDAT,
@@ -1673,6 +1683,33 @@ next_queue:
        }
 }
 
+static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int i;
+
+       for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
+               struct iwl_txq *txq = &trans_pcie->txq[i];
+
+               if (i == trans_pcie->cmd_queue)
+                       continue;
+
+               spin_lock_bh(&txq->lock);
+
+               if (!block && !(WARN_ON_ONCE(!txq->block))) {
+                       txq->block--;
+                       if (!txq->block) {
+                               iwl_write32(trans, HBUS_TARG_WRPTR,
+                                           txq->q.write_ptr | (i << 8));
+                       }
+               } else if (block) {
+                       txq->block++;
+               }
+
+               spin_unlock_bh(&txq->lock);
+       }
+}
+
 #define IWL_FLUSH_WAIT_MS      2000
 
 static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
@@ -2206,7 +2243,7 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans,
        __le32 *val;
        int i;
 
-       if (!iwl_trans_grab_nic_access(trans, false, &flags))
+       if (!iwl_trans_grab_nic_access(trans, &flags))
                return 0;
 
        (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FH_REGS);
@@ -2233,7 +2270,7 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans,
        unsigned long flags;
        u32 i;
 
-       if (!iwl_trans_grab_nic_access(trans, false, &flags))
+       if (!iwl_trans_grab_nic_access(trans, &flags))
                return 0;
 
        iwl_write_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x1);
@@ -2467,6 +2504,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
 
        .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty,
        .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer,
+       .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs,
 
        .write8 = iwl_trans_pcie_write8,
        .write32 = iwl_trans_pcie_write32,
@@ -2511,6 +2549,11 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        spin_lock_init(&trans_pcie->ref_lock);
        mutex_init(&trans_pcie->mutex);
        init_waitqueue_head(&trans_pcie->ucode_write_waitq);
+       trans_pcie->tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page);
+       if (!trans_pcie->tso_hdr_page) {
+               ret = -ENOMEM;
+               goto out_no_pci;
+       }
 
        ret = pci_enable_device(pdev);
        if (ret)
@@ -2612,7 +2655,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                        goto out_pci_disable_msi;
                }
 
-               if (iwl_trans_grab_nic_access(trans, false, &flags)) {
+               if (iwl_trans_grab_nic_access(trans, &flags)) {
                        u32 hw_step;
 
                        hw_step = iwl_read_prph_no_grab(trans, WFPM_CTRL_REG);
@@ -2647,7 +2690,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        }
 
        trans_pcie->inta_mask = CSR_INI_SET_MASK;
-       trans->d0i3_mode = IWL_D0I3_MODE_ON_SUSPEND;
 
        return trans;
 
@@ -2660,6 +2702,7 @@ out_pci_release_regions:
 out_pci_disable_device:
        pci_disable_device(pdev);
 out_no_pci:
+       free_percpu(trans_pcie->tso_hdr_page);
        iwl_trans_free(trans);
        return ERR_PTR(ret);
 }
index a8c8a4a..5262028 100644 (file)
  * file called LICENSE.
  *
  * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
+ *  Intel Linux Wireless <linuxwifi@intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
 #include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <net/ip6_checksum.h>
+#include <net/tso.h>
+#include <net/ip6_checksum.h>
 
 #include "iwl-debug.h"
 #include "iwl-csr.h"
@@ -318,7 +322,9 @@ static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans,
         * trying to tx (during RFKILL, we're not trying to tx).
         */
        IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr);
-       iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8));
+       if (!txq->block)
+               iwl_write32(trans, HBUS_TARG_WRPTR,
+                           txq->q.write_ptr | (txq_id << 8));
 }
 
 void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans)
@@ -576,6 +582,19 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
        return 0;
 }
 
+static void iwl_pcie_free_tso_page(struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       if (info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA]) {
+               struct page *page =
+                       info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA];
+
+               __free_page(page);
+               info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = NULL;
+       }
+}
+
 /*
  * iwl_pcie_txq_unmap -  Unmap any remaining DMA mappings and free skb's
  */
@@ -589,6 +608,15 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
        while (q->write_ptr != q->read_ptr) {
                IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n",
                                   txq_id, q->read_ptr);
+
+               if (txq_id != trans_pcie->cmd_queue) {
+                       struct sk_buff *skb = txq->entries[q->read_ptr].skb;
+
+                       if (WARN_ON_ONCE(!skb))
+                               continue;
+
+                       iwl_pcie_free_tso_page(skb);
+               }
                iwl_pcie_txq_free_tfd(trans, txq);
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr);
        }
@@ -742,7 +770,7 @@ static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans)
 
        spin_lock(&trans_pcie->irq_lock);
 
-       if (!iwl_trans_grab_nic_access(trans, false, &flags))
+       if (!iwl_trans_grab_nic_access(trans, &flags))
                goto out;
 
        /* Stop each Tx DMA channel */
@@ -1006,11 +1034,14 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
        for (;
             q->read_ptr != tfd_num;
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr)) {
+               struct sk_buff *skb = txq->entries[txq->q.read_ptr].skb;
 
-               if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
+               if (WARN_ON_ONCE(!skb))
                        continue;
 
-               __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
+               iwl_pcie_free_tso_page(skb);
+
+               __skb_queue_tail(skbs, skb);
 
                txq->entries[txq->q.read_ptr].skb = NULL;
 
@@ -1411,7 +1442,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
         */
        if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE,
                 "Command %s (%#x) is too large (%d bytes)\n",
-                get_cmd_string(trans_pcie, cmd->id), cmd->id, copy_size)) {
+                iwl_get_cmd_string(trans, cmd->id),
+                cmd->id, copy_size)) {
                idx = -EINVAL;
                goto free_dup_buf;
        }
@@ -1501,7 +1533,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
 
        IWL_DEBUG_HC(trans,
                     "Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
-                    get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
+                    iwl_get_cmd_string(trans, cmd->id),
                     group_id, out_cmd->hdr.cmd,
                     le16_to_cpu(out_cmd->hdr.sequence),
                     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
@@ -1591,16 +1623,14 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
 /*
  * iwl_pcie_hcmd_complete - Pull unused buffers off the queue and reclaim them
  * @rxb: Rx buffer to reclaim
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed.  The attached skb (if present) will only be freed
- * if the callback returns 1
  */
 void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                            struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       u8 group_id = iwl_cmd_groupid(pkt->hdr.group_id);
+       u32 cmd_id;
        int txq_id = SEQ_TO_QUEUE(sequence);
        int index = SEQ_TO_INDEX(sequence);
        int cmd_index;
@@ -1626,6 +1656,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
        cmd_index = get_cmd_index(&txq->q, index);
        cmd = txq->entries[cmd_index].cmd;
        meta = &txq->entries[cmd_index].meta;
+       cmd_id = iwl_cmd_id(cmd->hdr.cmd, group_id, 0);
 
        iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]);
 
@@ -1638,17 +1669,20 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                meta->source->_rx_page_order = trans_pcie->rx_page_order;
        }
 
+       if (meta->flags & CMD_WANT_ASYNC_CALLBACK)
+               iwl_op_mode_async_cb(trans->op_mode, cmd);
+
        iwl_pcie_cmdq_reclaim(trans, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
                if (!test_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status)) {
                        IWL_WARN(trans,
                                 "HCMD_ACTIVE already clear for command %s\n",
-                                get_cmd_string(trans_pcie, cmd->hdr.cmd));
+                                iwl_get_cmd_string(trans, cmd_id));
                }
                clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
-                              get_cmd_string(trans_pcie, cmd->hdr.cmd));
+                              iwl_get_cmd_string(trans, cmd_id));
                wake_up(&trans_pcie->wait_command_queue);
        }
 
@@ -1662,7 +1696,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
 static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
                                    struct iwl_host_cmd *cmd)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
 
        /* An asynchronous command can not expect an SKB to be set. */
@@ -1673,7 +1706,7 @@ static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
        if (ret < 0) {
                IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
-                       get_cmd_string(trans_pcie, cmd->id), ret);
+                       iwl_get_cmd_string(trans, cmd->id), ret);
                return ret;
        }
        return 0;
@@ -1687,16 +1720,16 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        int ret;
 
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
-                      get_cmd_string(trans_pcie, cmd->id));
+                      iwl_get_cmd_string(trans, cmd->id));
 
        if (WARN(test_and_set_bit(STATUS_SYNC_HCMD_ACTIVE,
                                  &trans->status),
                 "Command %s: a command is already active!\n",
-                get_cmd_string(trans_pcie, cmd->id)))
+                iwl_get_cmd_string(trans, cmd->id)))
                return -EIO;
 
        IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
-                      get_cmd_string(trans_pcie, cmd->id));
+                      iwl_get_cmd_string(trans, cmd->id));
 
        cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd);
        if (cmd_idx < 0) {
@@ -1704,7 +1737,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
-                       get_cmd_string(trans_pcie, cmd->id), ret);
+                       iwl_get_cmd_string(trans, cmd->id), ret);
                return ret;
        }
 
@@ -1717,7 +1750,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                struct iwl_queue *q = &txq->q;
 
                IWL_ERR(trans, "Error sending %s: time out after %dms.\n",
-                       get_cmd_string(trans_pcie, cmd->id),
+                       iwl_get_cmd_string(trans, cmd->id),
                        jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
                IWL_ERR(trans, "Current CMD queue read_ptr %d write_ptr %d\n",
@@ -1725,7 +1758,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
 
                clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
-                              get_cmd_string(trans_pcie, cmd->id));
+                              iwl_get_cmd_string(trans, cmd->id));
                ret = -ETIMEDOUT;
 
                iwl_force_nmi(trans);
@@ -1736,7 +1769,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
 
        if (test_bit(STATUS_FW_ERROR, &trans->status)) {
                IWL_ERR(trans, "FW error in SYNC CMD %s\n",
-                       get_cmd_string(trans_pcie, cmd->id));
+                       iwl_get_cmd_string(trans, cmd->id));
                dump_stack();
                ret = -EIO;
                goto cancel;
@@ -1751,7 +1784,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
 
        if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
                IWL_ERR(trans, "Error: Response NULL in '%s'\n",
-                       get_cmd_string(trans_pcie, cmd->id));
+                       iwl_get_cmd_string(trans, cmd->id));
                ret = -EIO;
                goto cancel;
        }
@@ -1794,6 +1827,305 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        return iwl_pcie_send_hcmd_sync(trans, cmd);
 }
 
+static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
+                            struct iwl_txq *txq, u8 hdr_len,
+                            struct iwl_cmd_meta *out_meta,
+                            struct iwl_device_cmd *dev_cmd, u16 tb1_len)
+{
+       struct iwl_queue *q = &txq->q;
+       u16 tb2_len;
+       int i;
+
+       /*
+        * Set up TFD's third entry to point directly to remainder
+        * of skb's head, if any
+        */
+       tb2_len = skb_headlen(skb) - hdr_len;
+
+       if (tb2_len > 0) {
+               dma_addr_t tb2_phys = dma_map_single(trans->dev,
+                                                    skb->data + hdr_len,
+                                                    tb2_len, DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) {
+                       iwl_pcie_tfd_unmap(trans, out_meta,
+                                          &txq->tfds[q->write_ptr]);
+                       return -EINVAL;
+               }
+               iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false);
+       }
+
+       /* set up the remaining entries to point to the data */
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               dma_addr_t tb_phys;
+               int tb_idx;
+
+               if (!skb_frag_size(frag))
+                       continue;
+
+               tb_phys = skb_frag_dma_map(trans->dev, frag, 0,
+                                          skb_frag_size(frag), DMA_TO_DEVICE);
+
+               if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
+                       iwl_pcie_tfd_unmap(trans, out_meta,
+                                          &txq->tfds[q->write_ptr]);
+                       return -EINVAL;
+               }
+               tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
+                                               skb_frag_size(frag), false);
+
+               out_meta->flags |= BIT(tb_idx + CMD_TB_BITMAP_POS);
+       }
+
+       trace_iwlwifi_dev_tx(trans->dev, skb,
+                            &txq->tfds[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,
+                            skb->data + hdr_len, tb2_len);
+       trace_iwlwifi_dev_tx_data(trans->dev, skb,
+                                 hdr_len, skb->len - hdr_len);
+       return 0;
+}
+
+#ifdef CONFIG_INET
+static struct iwl_tso_hdr_page *
+get_page_hdr(struct iwl_trans *trans, size_t len)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->tso_hdr_page);
+
+       if (!p->page)
+               goto alloc;
+
+       /* enough room on this page */
+       if (p->pos + len < (u8 *)page_address(p->page) + PAGE_SIZE)
+               return p;
+
+       /* We don't have enough room on this page, get a new one. */
+       __free_page(p->page);
+
+alloc:
+       p->page = alloc_page(GFP_ATOMIC);
+       if (!p->page)
+               return NULL;
+       p->pos = page_address(p->page);
+       return p;
+}
+
+static void iwl_compute_pseudo_hdr_csum(void *iph, struct tcphdr *tcph,
+                                       bool ipv6, unsigned int len)
+{
+       if (ipv6) {
+               struct ipv6hdr *iphv6 = iph;
+
+               tcph->check = ~csum_ipv6_magic(&iphv6->saddr, &iphv6->daddr,
+                                              len + tcph->doff * 4,
+                                              IPPROTO_TCP, 0);
+       } else {
+               struct iphdr *iphv4 = iph;
+
+               ip_send_check(iphv4);
+               tcph->check = ~csum_tcpudp_magic(iphv4->saddr, iphv4->daddr,
+                                                len + tcph->doff * 4,
+                                                IPPROTO_TCP, 0);
+       }
+}
+
+static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
+                                  struct iwl_txq *txq, u8 hdr_len,
+                                  struct iwl_cmd_meta *out_meta,
+                                  struct iwl_device_cmd *dev_cmd, u16 tb1_len)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
+       unsigned int mss = skb_shinfo(skb)->gso_size;
+       struct iwl_queue *q = &txq->q;
+       u16 length, iv_len, amsdu_pad;
+       u8 *start_hdr;
+       struct iwl_tso_hdr_page *hdr_page;
+       int ret;
+       struct tso_t tso;
+
+       /* if the packet is protected, then it must be CCMP or GCMP */
+       BUILD_BUG_ON(IEEE80211_CCMP_HDR_LEN != IEEE80211_GCMP_HDR_LEN);
+       iv_len = ieee80211_has_protected(hdr->frame_control) ?
+               IEEE80211_CCMP_HDR_LEN : 0;
+
+       trace_iwlwifi_dev_tx(trans->dev, skb,
+                            &txq->tfds[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,
+                            NULL, 0);
+
+       ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb);
+       snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb);
+       total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len;
+       amsdu_pad = 0;
+
+       /* total amount of header we may need for this A-MSDU */
+       hdr_room = DIV_ROUND_UP(total_len, mss) *
+               (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len;
+
+       /* Our device supports 9 segments at most, it will fit in 1 page */
+       hdr_page = get_page_hdr(trans, hdr_room);
+       if (!hdr_page)
+               return -ENOMEM;
+
+       get_page(hdr_page->page);
+       start_hdr = hdr_page->pos;
+       info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = hdr_page->page;
+       memcpy(hdr_page->pos, skb->data + hdr_len, iv_len);
+       hdr_page->pos += iv_len;
+
+       /*
+        * Pull the ieee80211 header + IV to be able to use TSO core,
+        * we will restore it for the tx_status flow.
+        */
+       skb_pull(skb, hdr_len + iv_len);
+
+       tso_start(skb, &tso);
+
+       while (total_len) {
+               /* this is the data left for this subframe */
+               unsigned int data_left =
+                       min_t(unsigned int, mss, total_len);
+               struct sk_buff *csum_skb = NULL;
+               unsigned int hdr_tb_len;
+               dma_addr_t hdr_tb_phys;
+               struct tcphdr *tcph;
+               u8 *iph;
+
+               total_len -= data_left;
+
+               memset(hdr_page->pos, 0, amsdu_pad);
+               hdr_page->pos += amsdu_pad;
+               amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen +
+                                 data_left)) & 0x3;
+               ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr));
+               hdr_page->pos += ETH_ALEN;
+               ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr));
+               hdr_page->pos += ETH_ALEN;
+
+               length = snap_ip_tcp_hdrlen + data_left;
+               *((__be16 *)hdr_page->pos) = cpu_to_be16(length);
+               hdr_page->pos += sizeof(length);
+
+               /*
+                * This will copy the SNAP as well which will be considered
+                * as MAC header.
+                */
+               tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len);
+               iph = hdr_page->pos + 8;
+               tcph = (void *)(iph + ip_hdrlen);
+
+               /* For testing on current hardware only */
+               if (trans_pcie->sw_csum_tx) {
+                       csum_skb = alloc_skb(data_left + tcp_hdrlen(skb),
+                                            GFP_ATOMIC);
+                       if (!csum_skb) {
+                               ret = -ENOMEM;
+                               goto out_unmap;
+                       }
+
+                       iwl_compute_pseudo_hdr_csum(iph, tcph,
+                                                   skb->protocol ==
+                                                       htons(ETH_P_IPV6),
+                                                   data_left);
+
+                       memcpy(skb_put(csum_skb, tcp_hdrlen(skb)),
+                              tcph, tcp_hdrlen(skb));
+                       skb_set_transport_header(csum_skb, 0);
+                       csum_skb->csum_start =
+                               (unsigned char *)tcp_hdr(csum_skb) -
+                                                csum_skb->head;
+               }
+
+               hdr_page->pos += snap_ip_tcp_hdrlen;
+
+               hdr_tb_len = hdr_page->pos - start_hdr;
+               hdr_tb_phys = dma_map_single(trans->dev, start_hdr,
+                                            hdr_tb_len, DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(trans->dev, hdr_tb_phys))) {
+                       dev_kfree_skb(csum_skb);
+                       ret = -EINVAL;
+                       goto out_unmap;
+               }
+               iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys,
+                                      hdr_tb_len, false);
+               trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr,
+                                              hdr_tb_len);
+
+               /* prepare the start_hdr for the next subframe */
+               start_hdr = hdr_page->pos;
+
+               /* put the payload */
+               while (data_left) {
+                       unsigned int size = min_t(unsigned int, tso.size,
+                                                 data_left);
+                       dma_addr_t tb_phys;
+
+                       if (trans_pcie->sw_csum_tx)
+                               memcpy(skb_put(csum_skb, size), tso.data, size);
+
+                       tb_phys = dma_map_single(trans->dev, tso.data,
+                                                size, DMA_TO_DEVICE);
+                       if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
+                               dev_kfree_skb(csum_skb);
+                               ret = -EINVAL;
+                               goto out_unmap;
+                       }
+
+                       iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
+                                              size, false);
+                       trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data,
+                                                      size);
+
+                       data_left -= size;
+                       tso_build_data(skb, &tso, size);
+               }
+
+               /* For testing on early hardware only */
+               if (trans_pcie->sw_csum_tx) {
+                       __wsum csum;
+
+                       csum = skb_checksum(csum_skb,
+                                           skb_checksum_start_offset(csum_skb),
+                                           csum_skb->len -
+                                           skb_checksum_start_offset(csum_skb),
+                                           0);
+                       dev_kfree_skb(csum_skb);
+                       dma_sync_single_for_cpu(trans->dev, hdr_tb_phys,
+                                               hdr_tb_len, DMA_TO_DEVICE);
+                       tcph->check = csum_fold(csum);
+                       dma_sync_single_for_device(trans->dev, hdr_tb_phys,
+                                                  hdr_tb_len, DMA_TO_DEVICE);
+               }
+       }
+
+       /* re -add the WiFi header and IV */
+       skb_push(skb, hdr_len + iv_len);
+
+       return 0;
+
+out_unmap:
+       iwl_pcie_tfd_unmap(trans, out_meta, &txq->tfds[q->write_ptr]);
+       return ret;
+}
+#else /* CONFIG_INET */
+static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
+                                  struct iwl_txq *txq, u8 hdr_len,
+                                  struct iwl_cmd_meta *out_meta,
+                                  struct iwl_device_cmd *dev_cmd, u16 tb1_len)
+{
+       /* No A-MSDU without CONFIG_INET */
+       WARN_ON(1);
+
+       return -1;
+}
+#endif /* CONFIG_INET */
+
 int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                      struct iwl_device_cmd *dev_cmd, int txq_id)
 {
@@ -1805,12 +2137,11 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
        struct iwl_queue *q;
        dma_addr_t tb0_phys, tb1_phys, scratch_phys;
        void *tb1_addr;
-       u16 len, tb1_len, tb2_len;
+       u16 len, tb1_len;
        bool wait_write_ptr;
        __le16 fc;
        u8 hdr_len;
        u16 wifi_seq;
-       int i;
 
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
@@ -1819,6 +2150,19 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                      "TX on unused queue %d\n", txq_id))
                return -EINVAL;
 
+       if (unlikely(trans_pcie->sw_csum_tx &&
+                    skb->ip_summed == CHECKSUM_PARTIAL)) {
+               int offs = skb_checksum_start_offset(skb);
+               int csum_offs = offs + skb->csum_offset;
+               __wsum csum;
+
+               if (skb_ensure_writable(skb, csum_offs + sizeof(__sum16)))
+                       return -1;
+
+               csum = skb_checksum(skb, offs, skb->len - offs, 0);
+               *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum);
+       }
+
        if (skb_is_nonlinear(skb) &&
            skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS &&
            __skb_linearize(skb))
@@ -1893,57 +2237,20 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                goto out_err;
        iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, false);
 
-       /*
-        * Set up TFD's third entry to point directly to remainder
-        * of skb's head, if any
-        */
-       tb2_len = skb_headlen(skb) - hdr_len;
-       if (tb2_len > 0) {
-               dma_addr_t tb2_phys = dma_map_single(trans->dev,
-                                                    skb->data + hdr_len,
-                                                    tb2_len, DMA_TO_DEVICE);
-               if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) {
-                       iwl_pcie_tfd_unmap(trans, out_meta,
-                                          &txq->tfds[q->write_ptr]);
-                       goto out_err;
-               }
-               iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false);
-       }
-
-       /* set up the remaining entries to point to the data */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-               dma_addr_t tb_phys;
-               int tb_idx;
-
-               if (!skb_frag_size(frag))
-                       continue;
-
-               tb_phys = skb_frag_dma_map(trans->dev, frag, 0,
-                                          skb_frag_size(frag), DMA_TO_DEVICE);
-
-               if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
-                       iwl_pcie_tfd_unmap(trans, out_meta,
-                                          &txq->tfds[q->write_ptr]);
+       if (ieee80211_is_data_qos(fc) &&
+           (*ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_A_MSDU_PRESENT)) {
+               if (unlikely(iwl_fill_data_tbs_amsdu(trans, skb, txq, hdr_len,
+                                                    out_meta, dev_cmd,
+                                                    tb1_len)))
                        goto out_err;
-               }
-               tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys,
-                                               skb_frag_size(frag), false);
-
-               out_meta->flags |= BIT(tb_idx + CMD_TB_BITMAP_POS);
+       } else if (unlikely(iwl_fill_data_tbs(trans, skb, txq, hdr_len,
+                                      out_meta, dev_cmd, tb1_len))) {
+               goto out_err;
        }
 
        /* Set up entry for this TFD in Tx byte-count array */
        iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
 
-       trace_iwlwifi_dev_tx(trans->dev, skb,
-                            &txq->tfds[txq->q.write_ptr],
-                            sizeof(struct iwl_tfd),
-                            &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,
-                            skb->data + hdr_len, tb2_len);
-       trace_iwlwifi_dev_tx_data(trans->dev, skb,
-                                 hdr_len, skb->len - hdr_len);
-
        wait_write_ptr = ieee80211_has_morefrags(fc);
 
        /* start timer if queue currently empty */