Merge tag 'iwlwifi-next-for-kalle-2015-12-21' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
* 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)
This commit is contained in:
@@ -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__ */
|
||||
|
@@ -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;
|
||||
|
@@ -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]);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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, ®_flags))
|
||||
if (!iwl_trans_grab_nic_access(priv->trans, ®_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, ®_flags))
|
||||
if (!iwl_trans_grab_nic_access(trans, ®_flags))
|
||||
return pos;
|
||||
|
||||
/* Set starting address; reads will auto-increment */
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
@@ -32,91 +33,13 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
|
@@ -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__
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
@@ -71,13 +71,19 @@
|
||||
#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));
|
||||
|
@@ -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,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,
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
@@ -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));
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -61,7 +61,10 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
#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);
|
||||
|
@@ -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
|
||||
*
|
||||
* @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)
|
||||
* 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_d0i3_mode {
|
||||
IWL_D0I3_MODE_OFF = 0,
|
||||
IWL_D0I3_MODE_ON_IDLE,
|
||||
IWL_D0I3_MODE_ON_SUSPEND,
|
||||
|
||||
/**
|
||||
* enum iwl_plat_pm_mode - platform power management mode
|
||||
*
|
||||
* 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_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)
|
||||
|
@@ -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)/../
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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 @@
|
||||
#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
|
||||
|
@@ -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, >kdata);
|
||||
|
||||
gtkdata.find_phase = false;
|
||||
iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, >kdata);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
@@ -79,6 +79,11 @@
|
||||
#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)
|
||||
@@ -97,6 +102,8 @@
|
||||
* @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,
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -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,
|
||||
};
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
@@ -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 */
|
||||
|
@@ -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
|
||||
|
@@ -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]));
|
||||
}
|
||||
#endif
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
enabled |= IWL_D3_PROTO_IPV6_VALID;
|
||||
memcpy(cmd.v1.ndp_mac_addr, vif->addr, ETH_ALEN);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@@ -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),
|
||||
};
|
||||
#undef 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),
|
||||
};
|
||||
|
||||
|
||||
/* 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 = {
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_RATE(mvm, "rate_idx %d ANT %s\n", rate->index,
|
||||
rs_pretty_ant(rate->ant));
|
||||
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);
|
||||
|
@@ -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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
@@ -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
|
||||
|
378
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
Normal file
378
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
Normal file
@@ -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 */
|
||||
}
|
@@ -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
|
||||
@@ -72,13 +72,6 @@
|
||||
#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, ¶ms);
|
||||
params.type =
|
||||
iwl_mvm_get_scan_type(mvm,
|
||||
vif->type == NL80211_IFTYPE_P2P_DEVICE);
|
||||
|
||||
iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);
|
||||
|
||||
@@ -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, ¶ms);
|
||||
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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
if (te_data)
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
|
||||
|
||||
remove_te:
|
||||
out:
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
return te_data;
|
||||
}
|
||||
|
||||
if (!mvmvif) {
|
||||
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)
|
||||
__iwl_mvm_remove_time_event(mvm, te_data, &uid);
|
||||
}
|
||||
|
||||
void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
struct iwl_mvm_time_event_data *te_data;
|
||||
|
||||
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);
|
||||
|
@@ -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);
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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
|
||||
|
@@ -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 */
|
||||
|
@@ -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) &
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -23,13 +23,17 @@
|
||||
* 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]);
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
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 */
|
||||
|
Reference in New Issue
Block a user