* more clean-ups towards multiple RX queues;

* some rate scaling fixes and improvements;
 * some time-of-flight fixes;
 * other generic improvements and clean-ups;
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWEmeEAAoJEKFHnKIaPMX6fEMP/39bRyGi09NwXM5d0svYuBzC
 Ch1/hIaK7gWV76coBNjEmMiaBHBeZCNuW4SwfrT4z2WXoenbaJLeKPWps1gR5F4l
 TiAUTNNzvp1JzmbCysb8bVisG5wdzqd9t0yvOHCiICpD956PS6aerFQ3LZEIJqmR
 0M/GklJuHENX3M3a6aVQCR9iOItNw6MjYXQpYlWK3HCQxmouim+Dru68jUHjYC4+
 F5qfuiLCdlAlI3RZ6TNqhMDuY4utFB54FepEqWd1A9x0P+1SJZ3AqDkTFLDNEJzm
 y6d6NTreKYpFO7XUvmb1BHa93a1PU0zpiIWmwA2sOYSep7bQcUT5cYn5n/+4DUOB
 r/u9/xd6TvC4UYOXCuzrxK58M/vMrHl74uzyo9s/FjtI+dvM3mGRXgs/Zv/CmebQ
 i+lLZ31vfuoFl+6NCR6vmWoiW8C0RX7xTok2bIAUeUjtKR26ioIf3KhirXWzvXZL
 5dwC1NDTgOCWzUyn21wZsr1G6B9Q+vX0QwWJaezfqB3HzTCrVVt6HDaG8e4QI0n/
 n+qRl2g9bbHgI4EWG7fFwEhGvCrl0mLR2DVw3wvaIfFmM8UH7PtRkVPJyGmute1e
 Yg6t8rarzlZm4N3cDlPTJMBZ7pjnAYZTtAR7pgAivCrPApt9ZpH+GYs0IXJQY6+L
 Gc4hWq2Ahshvf2lv9acw
 =NTgB
 -----END PGP SIGNATURE-----

Merge tag 'iwlwifi-next-for-kalle-2015-10-05' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

* more clean-ups towards multiple RX queues;
* some rate scaling fixes and improvements;
* some time-of-flight fixes;
* other generic improvements and clean-ups;
This commit is contained in:
Kalle Valo 2015-10-07 12:14:23 +03:00
commit 7e64e5e66a
32 changed files with 644 additions and 245 deletions

View File

@ -5541,7 +5541,7 @@ F: drivers/net/wireless/iwlegacy/
INTEL WIRELESS WIFI LINK (iwlwifi) INTEL WIRELESS WIFI LINK (iwlwifi)
M: Johannes Berg <johannes.berg@intel.com> M: Johannes Berg <johannes.berg@intel.com>
M: Emmanuel Grumbach <emmanuel.grumbach@intel.com> M: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com> M: Intel Linux Wireless <linuxwifi@intel.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org W: http://intellinuxwireless.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git

View File

@ -142,6 +142,7 @@ config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE
config IWLWIFI_DEVICE_TRACING config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing" bool "iwlwifi device access tracing"
depends on EVENT_TRACING depends on EVENT_TRACING
default y
help help
Say Y here to trace all commands, including TX frames and IO Say Y here to trace all commands, including TX frames and IO
accesses, sent to the device. If you say yes, iwlwifi will accesses, sent to the device. If you say yes, iwlwifi will

View File

@ -73,11 +73,9 @@
/* Oldest version we won't warn about */ /* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 13 #define IWL7260_UCODE_API_OK 13
#define IWL3165_UCODE_API_OK 13
/* Lowest firmware API version supported */ /* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 13 #define IWL7260_UCODE_API_MIN 13
#define IWL3165_UCODE_API_MIN 13
/* NVM versions */ /* NVM versions */
#define IWL7260_NVM_VERSION 0x0a1d #define IWL7260_NVM_VERSION 0x0a1d
@ -269,11 +267,6 @@ const struct iwl_cfg iwl3165_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 3165", .name = "Intel(R) Dual Band Wireless AC 3165",
.fw_name_pre = IWL7265D_FW_PRE, .fw_name_pre = IWL7265D_FW_PRE,
IWL_DEVICE_7000, IWL_DEVICE_7000,
/* sparse doens't like the re-assignment but it is safe */
#ifndef __CHECKER__
.ucode_api_ok = IWL3165_UCODE_API_OK,
.ucode_api_min = IWL3165_UCODE_API_MIN,
#endif
.ht_params = &iwl7000_ht_params, .ht_params = &iwl7000_ht_params,
.nvm_ver = IWL3165_NVM_VERSION, .nvm_ver = IWL3165_NVM_VERSION,
.nvm_calib_ver = IWL3165_TX_POWER_VERSION, .nvm_calib_ver = IWL3165_TX_POWER_VERSION,

View File

@ -223,13 +223,13 @@ struct iwl_tt_tx_backoff {
* @support_tx_backoff: Support tx-backoff? * @support_tx_backoff: Support tx-backoff?
*/ */
struct iwl_tt_params { struct iwl_tt_params {
s32 ct_kill_entry; u32 ct_kill_entry;
s32 ct_kill_exit; u32 ct_kill_exit;
u32 ct_kill_duration; u32 ct_kill_duration;
s32 dynamic_smps_entry; u32 dynamic_smps_entry;
s32 dynamic_smps_exit; u32 dynamic_smps_exit;
s32 tx_protection_entry; u32 tx_protection_entry;
s32 tx_protection_exit; u32 tx_protection_exit;
struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE]; struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE];
bool support_ct_kill; bool support_ct_kill;
bool support_dynamic_smps; bool support_dynamic_smps;

View File

@ -450,7 +450,7 @@ static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data,
u32 api_flags = le32_to_cpu(ucode_api->api_flags); u32 api_flags = le32_to_cpu(ucode_api->api_flags);
int i; int i;
if (api_index >= IWL_API_MAX_BITS / 32) { if (api_index >= DIV_ROUND_UP(NUM_IWL_UCODE_TLV_API, 32)) {
IWL_ERR(drv, "api_index larger than supported by driver\n"); IWL_ERR(drv, "api_index larger than supported by driver\n");
/* don't return an error so we can load FW that has more bits */ /* don't return an error so we can load FW that has more bits */
return 0; return 0;
@ -472,7 +472,7 @@ static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data,
u32 api_flags = le32_to_cpu(ucode_capa->api_capa); u32 api_flags = le32_to_cpu(ucode_capa->api_capa);
int i; int i;
if (api_index >= IWL_CAPABILITIES_MAX_BITS / 32) { if (api_index >= DIV_ROUND_UP(NUM_IWL_UCODE_TLV_CAPA, 32)) {
IWL_ERR(drv, "api_index larger than supported by driver\n"); IWL_ERR(drv, "api_index larger than supported by driver\n");
/* don't return an error so we can load FW that has more bits */ /* don't return an error so we can load FW that has more bits */
return 0; return 0;

View File

@ -254,6 +254,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
* instead of 3. * instead of 3.
* @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size * @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size
* (command version 3) that supports per-chain limits * (command version 3) that supports per-chain limits
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/ */
enum iwl_ucode_tlv_api { enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3, IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3,
@ -264,6 +266,12 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20, IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20,
IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24, IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24,
IWL_UCODE_TLV_API_TX_POWER_CHAIN = (__force iwl_ucode_tlv_api_t)27, IWL_UCODE_TLV_API_TX_POWER_CHAIN = (__force iwl_ucode_tlv_api_t)27,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
/* sparse says it cannot increment the previous enum member */
= 128
#endif
}; };
typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
@ -298,6 +306,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
* is supported. * is supported.
* @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
* @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan
*
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
*/ */
enum iwl_ucode_tlv_capa { enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0, IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0,
@ -320,6 +330,12 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29,
IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30,
IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31,
NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__
/* sparse says it cannot increment the previous enum member */
= 128
#endif
}; };
/* The default calibrate table size if not specified by firmware file */ /* The default calibrate table size if not specified by firmware file */
@ -330,9 +346,6 @@ enum iwl_ucode_tlv_capa {
/* The default max probe length if not specified by the firmware file */ /* The default max probe length if not specified by the firmware file */
#define IWL_DEFAULT_MAX_PROBE_LENGTH 200 #define IWL_DEFAULT_MAX_PROBE_LENGTH 200
#define IWL_API_MAX_BITS 64
#define IWL_CAPABILITIES_MAX_BITS 64
/* /*
* For 16.0 uCode and above, there is no differentiation between sections, * For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address. * just an offset to the HW address.

View File

@ -105,8 +105,8 @@ struct iwl_ucode_capabilities {
u32 n_scan_channels; u32 n_scan_channels;
u32 standard_phy_calibration_size; u32 standard_phy_calibration_size;
u32 flags; u32 flags;
unsigned long _api[BITS_TO_LONGS(IWL_API_MAX_BITS)]; unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)];
unsigned long _capa[BITS_TO_LONGS(IWL_CAPABILITIES_MAX_BITS)]; unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)];
}; };
static inline bool static inline bool

View File

@ -580,13 +580,15 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
IWL_ERR_DEV(dev, "mac address is not found\n"); IWL_ERR_DEV(dev, "mac address is not found\n");
} }
#define IWL_4165_DEVICE_ID 0x5501
struct iwl_nvm_data * struct iwl_nvm_data *
iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
const __le16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_hw, const __le16 *nvm_sw,
const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *nvm_calib, const __le16 *regulatory,
const __le16 *mac_override, const __le16 *phy_sku, const __le16 *mac_override, const __le16 *phy_sku,
u8 tx_chains, u8 rx_chains, bool lar_fw_supported, u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
u32 mac_addr0, u32 mac_addr1) u32 mac_addr0, u32 mac_addr1, u32 hw_id)
{ {
struct iwl_nvm_data *data; struct iwl_nvm_data *data;
u32 sku; u32 sku;
@ -625,6 +627,17 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
(sku & NVM_SKU_CAP_11AC_ENABLE); (sku & NVM_SKU_CAP_11AC_ENABLE);
data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE; data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE;
/*
* OTP 0x52 bug work around
* define antenna 1x1 according to MIMO disabled
*/
if (hw_id == IWL_4165_DEVICE_ID && data->sku_cap_mimo_disabled) {
data->valid_tx_ant = ANT_B;
data->valid_rx_ant = ANT_B;
tx_chains = ANT_B;
rx_chains = ANT_B;
}
data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) { if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {

View File

@ -79,7 +79,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *nvm_calib, const __le16 *regulatory,
const __le16 *mac_override, const __le16 *phy_sku, const __le16 *mac_override, const __le16 *phy_sku,
u8 tx_chains, u8 rx_chains, bool lar_fw_supported, u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
u32 mac_addr0, u32 mac_addr1); u32 mac_addr0, u32 mac_addr1, u32 hw_id);
/** /**
* iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW

View File

@ -7,6 +7,7 @@
* *
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * 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 * 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 * it under the terms of version 2 of the GNU General Public License as
@ -33,6 +34,7 @@
* *
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -108,7 +110,8 @@ struct iwl_cfg;
* interact with it. The driver layer typically calls the start and stop * interact with it. The driver layer typically calls the start and stop
* handlers, the transport layer calls the others. * handlers, the transport layer calls the others.
* *
* All the handlers MUST be implemented * All the handlers MUST be implemented, except @rx_rss which can be left
* out *iff* the opmode will never run on hardware with multi-queue capability.
* *
* @start: start the op_mode. The transport layer is already allocated. * @start: start the op_mode. The transport layer is already allocated.
* May sleep * May sleep
@ -116,6 +119,10 @@ struct iwl_cfg;
* May sleep * May sleep
* @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the
* HCMD this Rx responds to. Can't sleep. * HCMD this Rx responds to. Can't sleep.
* @rx_rss: data queue RX notification to the op_mode, for (data) notifications
* 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.
* @queue_full: notifies that a HW queue is full. * @queue_full: notifies that a HW queue is full.
* Must be atomic and called with BH disabled. * Must be atomic and called with BH disabled.
* @queue_not_full: notifies that a HW queue is not full any more. * @queue_not_full: notifies that a HW queue is not full any more.
@ -146,6 +153,8 @@ struct iwl_op_mode_ops {
void (*stop)(struct iwl_op_mode *op_mode); void (*stop)(struct iwl_op_mode *op_mode);
void (*rx)(struct iwl_op_mode *op_mode, struct napi_struct *napi, void (*rx)(struct iwl_op_mode *op_mode, struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb); 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 (*queue_full)(struct iwl_op_mode *op_mode, int queue); void (*queue_full)(struct iwl_op_mode *op_mode, int queue);
void (*queue_not_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); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
@ -186,6 +195,14 @@ static inline void iwl_op_mode_rx(struct iwl_op_mode *op_mode,
return op_mode->ops->rx(op_mode, napi, rxb); return op_mode->ops->rx(op_mode, napi, rxb);
} }
static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode,
struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb,
unsigned int queue)
{
op_mode->ops->rx_rss(op_mode, napi, rxb, queue);
}
static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode,
int queue) int queue)
{ {

View File

@ -87,6 +87,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
trans->cfg = cfg; trans->cfg = cfg;
trans->ops = ops; trans->ops = ops;
trans->dev_cmd_headroom = dev_cmd_headroom; trans->dev_cmd_headroom = dev_cmd_headroom;
trans->num_rx_queues = 1;
snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
"iwl_cmd_pool:%s", dev_name(trans->dev)); "iwl_cmd_pool:%s", dev_name(trans->dev));

View File

@ -386,6 +386,7 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
#define IWL_MAX_HW_QUEUES 32 #define IWL_MAX_HW_QUEUES 32
#define IWL_MAX_TID_COUNT 8 #define IWL_MAX_TID_COUNT 8
#define IWL_FRAME_LIMIT 64 #define IWL_FRAME_LIMIT 64
#define IWL_MAX_RX_HW_QUEUES 16
/** /**
* enum iwl_wowlan_status - WoWLAN image/device status * enum iwl_wowlan_status - WoWLAN image/device status
@ -654,6 +655,8 @@ enum iwl_d0i3_mode {
* @hw_id_str: a string with info about HW ID. Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation.
* @pm_support: set to true in start_hw if link pm is supported * @pm_support: set to true in start_hw if link pm is supported
* @ltr_enabled: set to true if the LTR is enabled * @ltr_enabled: set to true if the LTR is enabled
* @num_rx_queues: number of RX queues allocated by the transport;
* the transport must set this before calling iwl_drv_start()
* @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
* The user should use iwl_trans_{alloc,free}_tx_cmd. * The user should use iwl_trans_{alloc,free}_tx_cmd.
* @dev_cmd_headroom: room needed for the transport's private use before the * @dev_cmd_headroom: room needed for the transport's private use before the
@ -693,6 +696,8 @@ struct iwl_trans {
bool pm_support; bool pm_support;
bool ltr_enabled; bool ltr_enabled;
u8 num_rx_queues;
/* The following fields are internal only */ /* The following fields are internal only */
struct kmem_cache *dev_cmd_pool; struct kmem_cache *dev_cmd_pool;
size_t dev_cmd_headroom; size_t dev_cmd_headroom;

View File

@ -102,6 +102,7 @@
#define IWL_MVM_QUOTA_THRESHOLD 4 #define IWL_MVM_QUOTA_THRESHOLD 4
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
#define IWL_MVM_RS_DISABLE_P2P_MIMO 0 #define IWL_MVM_RS_DISABLE_P2P_MIMO 0
#define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1
#define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_TOF_IS_RESPONDER 0
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #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 2

View File

@ -511,7 +511,8 @@ static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm; struct iwl_mvm *mvm = mvmvif->mvm;
int value, ret = -EINVAL; u32 value;
int ret = -EINVAL;
char *data; char *data;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
@ -599,7 +600,8 @@ static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm; struct iwl_mvm *mvm = mvmvif->mvm;
int value, ret = 0; u32 value;
int ret = 0;
char *data; char *data;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
@ -822,7 +824,8 @@ static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm; struct iwl_mvm *mvm = mvmvif->mvm;
int value, ret = 0; u32 value;
int ret = 0;
char *data; char *data;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
@ -892,6 +895,7 @@ static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
goto out; goto out;
} }
memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
goto out;
} }
data = iwl_dbgfs_is_match("macaddr_mask=", buf); data = iwl_dbgfs_is_match("macaddr_mask=", buf);
@ -903,21 +907,22 @@ static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
goto out; goto out;
} }
memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
goto out;
} }
data = iwl_dbgfs_is_match("ap=", buf); data = iwl_dbgfs_is_match("ap=", buf);
if (data) { if (data) {
struct iwl_tof_range_req_ap_entry ap; struct iwl_tof_range_req_ap_entry ap = {};
int size = sizeof(struct iwl_tof_range_req_ap_entry); int size = sizeof(struct iwl_tof_range_req_ap_entry);
u16 burst_period; u16 burst_period;
u8 *mac = ap.bssid; u8 *mac = ap.bssid;
unsigned int i; unsigned int i;
if (sscanf(data, "%u %hhd %hhx %hhx" if (sscanf(data, "%u %hhd %hhd %hhd"
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
"%hhx %hhx %hx" "%hhd %hhd %hd"
"%hhx %hhx %x" "%hhd %hhd %d"
"%hhx %hhx %hhx %hhx", "%hhx %hhd %hhd %hhd",
&i, &ap.channel_num, &ap.bandwidth, &i, &ap.channel_num, &ap.bandwidth,
&ap.ctrl_ch_position, &ap.ctrl_ch_position,
mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
@ -944,12 +949,12 @@ static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
data = iwl_dbgfs_is_match("send_range_request=", buf); data = iwl_dbgfs_is_match("send_range_request=", buf);
if (data) { if (data) {
ret = kstrtou32(data, 10, &value); ret = kstrtou32(data, 10, &value);
if (ret == 0 && value) { if (ret == 0 && value)
ret = iwl_mvm_tof_range_request_cmd(mvm, vif); ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
goto out; goto out;
} }
}
ret = -EINVAL;
out: out:
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
return ret ?: count; return ret ?: count;
@ -994,16 +999,18 @@ static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ap %.2d: channel_num=%hhx bw=%hhx" "ap %.2d: channel_num=%hhd bw=%hhd"
" control=%hhx bssid=%pM type=%hhx" " control=%hhd bssid=%pM type=%hhd"
" num_of_bursts=%hhx burst_period=%hx ftm=%hhx" " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
" retries=%hhx tsf_delta=%x location_req=%hhx " " retries=%hhd tsf_delta=%d"
" asap=%hhx enable=%hhx rssi=%hhx\n", " tsf_delta_direction=%hhd location_req=0x%hhx "
" asap=%hhd enable=%hhd rssi=%hhd\n",
i, ap->channel_num, ap->bandwidth, i, ap->channel_num, ap->bandwidth,
ap->ctrl_ch_position, ap->bssid, ap->ctrl_ch_position, ap->bssid,
ap->measure_type, ap->num_of_bursts, ap->measure_type, ap->num_of_bursts,
ap->burst_period, ap->samples_per_burst, ap->burst_period, ap->samples_per_burst,
ap->retries_per_sample, ap->tsf_delta, ap->retries_per_sample, ap->tsf_delta,
ap->tsf_delta_direction,
ap->location_req, ap->asap_mode, ap->location_req, ap->asap_mode,
ap->enable_dyn_ack, ap->rssi); ap->enable_dyn_ack, ap->rssi);
} }
@ -1019,7 +1026,8 @@ static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm; struct iwl_mvm *mvm = mvmvif->mvm;
int value, ret = 0; u32 value;
int ret = 0;
char *data; char *data;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
@ -1071,12 +1079,12 @@ static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
data = iwl_dbgfs_is_match("send_range_req_ext=", buf); data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
if (data) { if (data) {
ret = kstrtou32(data, 10, &value); ret = kstrtou32(data, 10, &value);
if (ret == 0 && value) { if (ret == 0 && value)
ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
goto out; goto out;
} }
}
ret = -EINVAL;
out: out:
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
return ret ?: count; return ret ?: count;
@ -1099,18 +1107,18 @@ static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"tsf_timer_offset_msec = %hx\n", "tsf_timer_offset_msec = %hd\n",
cmd->tsf_timer_offset_msec); cmd->tsf_timer_offset_msec);
pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhx\n", pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
cmd->min_delta_ftm); cmd->min_delta_ftm);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ftm_format_and_bw20M = %hhx\n", "ftm_format_and_bw20M = %hhd\n",
cmd->ftm_format_and_bw20M); cmd->ftm_format_and_bw20M);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ftm_format_and_bw40M = %hhx\n", "ftm_format_and_bw40M = %hhd\n",
cmd->ftm_format_and_bw40M); cmd->ftm_format_and_bw40M);
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ftm_format_and_bw80M = %hhx\n", "ftm_format_and_bw80M = %hhd\n",
cmd->ftm_format_and_bw80M); cmd->ftm_format_and_bw80M);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
@ -1123,8 +1131,8 @@ static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm; struct iwl_mvm *mvm = mvmvif->mvm;
int value, ret = 0; u32 value;
int abort_id; int abort_id, ret = 0;
char *data; char *data;
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
@ -1205,11 +1213,11 @@ static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
pos += scnprintf(buf + pos, bufsz - pos, pos += scnprintf(buf + pos, bufsz - pos,
"ap %.2d: bssid=%pM status=%hhx bw=%hhx" "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
" rtt=%x rtt_var=%x rtt_spread=%x" " rtt=%d rtt_var=%d rtt_spread=%d"
" rssi=%hhx rssi_spread=%hhx" " rssi=%hhd rssi_spread=%hhd"
" range=%x range_var=%x" " range=%d range_var=%d"
" time_stamp=%x\n", " time_stamp=%d\n",
i, ap->bssid, ap->measure_status, i, ap->bssid, ap->measure_status,
ap->measure_bw, ap->measure_bw,
ap->rtt, ap->rtt_variance, ap->rtt_spread, ap->rtt, ap->rtt_variance, ap->rtt_spread,

View File

@ -1495,6 +1495,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
if (!debugfs_create_blob("nvm_prod", S_IRUSR, if (!debugfs_create_blob("nvm_prod", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_prod_blob)) mvm->debugfs_dir, &mvm->nvm_prod_blob))
goto err; goto err;
if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR,
mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
goto err;
/* /*
* Create a symlink with mac80211. It will be removed when mac80211 * Create a symlink with mac80211. It will be removed when mac80211

View File

@ -192,16 +192,10 @@ struct iwl_powertable_cmd {
/** /**
* enum iwl_device_power_flags - masks for device power command flags * enum iwl_device_power_flags - masks for device power command flags
* @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off * @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
* receiver and transmitter. '0' - does not allow. This flag should be * receiver and transmitter. '0' - does not allow.
* always set to '1' unless one need to disable actual power down for debug
* purposes.
* @DEVICE_POWER_FLAGS_CAM_MSK: '1' CAM (Continuous Active Mode) is set, meaning
* that power management is disabled. '0' Power management is enabled, one
* of power schemes is applied.
*/ */
enum iwl_device_power_flags { enum iwl_device_power_flags {
DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
DEVICE_POWER_FLAGS_CAM_MSK = BIT(13),
}; };
/** /**

View File

@ -268,6 +268,16 @@ enum {
REPLY_MAX = 0xff, REPLY_MAX = 0xff,
}; };
enum iwl_phy_ops_subcmd_ids {
CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0,
DTS_MEASUREMENT_NOTIF_WIDE = 0xFF,
};
/* command groups */
enum {
PHY_OPS_GROUP = 0x4,
};
/** /**
* struct iwl_cmd_response - generic response struct for most commands * struct iwl_cmd_response - generic response struct for most commands
* @status: status of the command asked, changes for each one * @status: status of the command asked, changes for each one

View File

@ -616,12 +616,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
* will be empty. * will be empty.
*/ */
for (i = 0; i < IWL_MAX_HW_QUEUES; i++) { memset(&mvm->queue_info, 0, sizeof(mvm->queue_info));
if (i < mvm->first_agg_queue && i != IWL_MVM_CMD_QUEUE) mvm->queue_info[IWL_MVM_CMD_QUEUE].hw_queue_refcount = 1;
mvm->queue_to_mac80211[i] = i;
else
mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
}
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
atomic_set(&mvm->mac80211_queue_stop_count[i], 0); atomic_set(&mvm->mac80211_queue_stop_count[i], 0);

View File

@ -486,16 +486,18 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_P2P_DEVICE:
iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MVM_TX_FIFO_VO, wdg_timeout); IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MVM_TX_FIFO_VO, 0, wdg_timeout);
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, vif->cab_queue,
IWL_MVM_TX_FIFO_MCAST, wdg_timeout); IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
/* fall through */ /* fall through */
default: default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
iwl_mvm_ac_to_tx_fifo[ac], vif->hw_queue[ac],
iwl_mvm_ac_to_tx_fifo[ac], 0,
wdg_timeout); wdg_timeout);
break; break;
} }
@ -511,14 +513,19 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) { switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_P2P_DEVICE:
iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, 0); iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MVM_OFFCHANNEL_QUEUE, IWL_MAX_TID_COUNT,
0);
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
iwl_mvm_disable_txq(mvm, vif->cab_queue, 0); iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue,
IWL_MAX_TID_COUNT, 0);
/* fall through */ /* fall through */
default: default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
iwl_mvm_disable_txq(mvm, vif->hw_queue[ac], 0); iwl_mvm_disable_txq(mvm, vif->hw_queue[ac],
vif->hw_queue[ac],
IWL_MAX_TID_COUNT, 0);
} }
} }
@ -1126,7 +1133,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id); ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id);
} }
int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm, static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
u32 action) u32 action)
{ {

View File

@ -2616,7 +2616,7 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
if (mvm_sta->vif->type == NL80211_IFTYPE_AP) { if (mvm_sta->vif->type == NL80211_IFTYPE_AP) {
mvmvif->ap_assoc_sta_count--; mvmvif->ap_assoc_sta_count--;
iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, FW_CTXT_ACTION_MODIFY); iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
} }
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);

View File

@ -82,7 +82,6 @@
#include "constants.h" #include "constants.h"
#include "tof.h" #include "tof.h"
#define IWL_INVALID_MAC80211_QUEUE 0xff
#define IWL_MVM_MAX_ADDRESSES 5 #define IWL_MVM_MAX_ADDRESSES 5
/* RSSI offset for WkP */ /* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50 #define IWL_RSSI_OFFSET 50
@ -605,7 +604,14 @@ struct iwl_mvm {
u64 on_time_scan; u64 on_time_scan;
} radio_stats, accu_radio_stats; } radio_stats, accu_radio_stats;
u8 queue_to_mac80211[IWL_MAX_HW_QUEUES]; struct {
/* Map to HW queue */
u32 hw_queue_to_mac80211;
u8 hw_queue_refcount;
bool setup_reserved;
u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
} queue_info[IWL_MAX_HW_QUEUES];
spinlock_t queue_info_lock; /* For syncing queue mgmt operations */
atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES]; atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
const char *nvm_file_name; const char *nvm_file_name;
@ -682,6 +688,7 @@ struct iwl_mvm {
struct debugfs_blob_wrapper nvm_sw_blob; struct debugfs_blob_wrapper nvm_sw_blob;
struct debugfs_blob_wrapper nvm_calib_blob; struct debugfs_blob_wrapper nvm_calib_blob;
struct debugfs_blob_wrapper nvm_prod_blob; struct debugfs_blob_wrapper nvm_prod_blob;
struct debugfs_blob_wrapper nvm_phy_sku_blob;
struct iwl_mvm_frame_stats drv_rx_stats; struct iwl_mvm_frame_stats drv_rx_stats;
spinlock_t drv_stats_lock; spinlock_t drv_stats_lock;
@ -910,6 +917,12 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
} }
static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
{
return fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_DQA_SUPPORT);
}
static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
{ {
bool nvm_lar = mvm->nvm_data->lar_enabled; bool nvm_lar = mvm->nvm_data->lar_enabled;
@ -957,6 +970,12 @@ static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_CSUM_SUPPORT); IWL_UCODE_TLV_CAPA_CSUM_SUPPORT);
} }
static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm)
{
/* firmware flag isn't defined yet */
return false;
}
extern const u8 iwl_mvm_ac_to_tx_fifo[]; extern const u8 iwl_mvm_ac_to_tx_fifo[];
struct iwl_rate_info { struct iwl_rate_info {
@ -1129,10 +1148,6 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
struct ieee80211_vif *exclude_vif); struct ieee80211_vif *exclude_vif);
int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 action);
/* Bindings */ /* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@ -1345,14 +1360,20 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
} }
/* hw scheduler queue config */ /* hw scheduler queue config */
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn, void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
const struct iwl_trans_txq_scd_cfg *cfg, u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int wdg_timeout); unsigned int wdg_timeout);
void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags); /*
* Disable a TXQ.
* Note that in non-DQA mode the %mac80211_queue and %tid params are ignored.
*/
void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
u8 tid, u8 flags);
int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq);
static inline static inline
void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
u8 fifo, unsigned int wdg_timeout) u8 fifo, u16 ssn, unsigned int wdg_timeout)
{ {
struct iwl_trans_txq_scd_cfg cfg = { struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo, .fifo = fifo,
@ -1361,13 +1382,13 @@ void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
.frame_limit = IWL_FRAME_LIMIT, .frame_limit = IWL_FRAME_LIMIT,
}; };
iwl_mvm_enable_txq(mvm, queue, 0, &cfg, wdg_timeout); iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout);
} }
static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
int fifo, int sta_id, int tid, int mac80211_queue, int fifo,
int frame_limit, u16 ssn, int sta_id, int tid, int frame_limit,
unsigned int wdg_timeout) u16 ssn, unsigned int wdg_timeout)
{ {
struct iwl_trans_txq_scd_cfg cfg = { struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo, .fifo = fifo,
@ -1377,7 +1398,7 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
.aggregate = true, .aggregate = true,
}; };
iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout); iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout);
} }
/* Thermal management and CT-kill */ /* Thermal management and CT-kill */

View File

@ -316,7 +316,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib,
regulatory, mac_override, phy_sku, regulatory, mac_override, phy_sku,
mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant, mvm->fw->valid_tx_ant, mvm->fw->valid_rx_ant,
lar_enabled, mac_addr0, mac_addr1); lar_enabled, mac_addr0, mac_addr1,
mvm->trans->hw_id);
} }
#define MAX_NVM_FILE_LEN 16384 #define MAX_NVM_FILE_LEN 16384
@ -563,6 +564,10 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
mvm->nvm_prod_blob.data = temp; mvm->nvm_prod_blob.data = temp;
mvm->nvm_prod_blob.size = ret; mvm->nvm_prod_blob.size = ret;
break; break;
case NVM_SECTION_TYPE_PHY_SKU:
mvm->nvm_phy_sku_blob.data = temp;
mvm->nvm_phy_sku_blob.size = ret;
break;
default: default:
if (section == mvm->cfg->nvm_hw_section_num) { if (section == mvm->cfg->nvm_hw_section_num) {
mvm->nvm_hw_blob.data = temp; mvm->nvm_hw_blob.data = temp;

View File

@ -89,6 +89,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static const struct iwl_op_mode_ops iwl_mvm_ops; static const struct iwl_op_mode_ops iwl_mvm_ops;
static const struct iwl_op_mode_ops iwl_mvm_ops_mq;
struct iwl_mvm_mod_params iwlmvm_mod_params = { struct iwl_mvm_mod_params iwlmvm_mod_params = {
.power_scheme = IWL_POWER_SCHEME_BPS, .power_scheme = IWL_POWER_SCHEME_BPS,
@ -222,7 +223,6 @@ struct iwl_rx_handlers {
* called from a worker with mvm->mutex held. * called from a worker with mvm->mutex held.
*/ */
static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false),
RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false),
RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false),
@ -257,6 +257,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION,
iwl_mvm_power_uapsd_misbehaving_ap_notif, false), iwl_mvm_power_uapsd_misbehaving_ap_notif, false),
RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true), RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true),
RX_HANDLER_GRP(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE,
iwl_mvm_temp_notif, true),
RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,
true), true),
@ -423,7 +425,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
op_mode = hw->priv; op_mode = hw->priv;
op_mode->ops = &iwl_mvm_ops;
mvm = IWL_OP_MODE_GET_MVM(op_mode); mvm = IWL_OP_MODE_GET_MVM(op_mode);
mvm->dev = trans->dev; mvm->dev = trans->dev;
@ -432,6 +433,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->fw = fw; mvm->fw = fw;
mvm->hw = hw; mvm->hw = hw;
if (iwl_mvm_has_new_rx_api(mvm)) {
op_mode->ops = &iwl_mvm_ops_mq;
} else {
op_mode->ops = &iwl_mvm_ops;
if (WARN_ON(trans->num_rx_queues > 1))
goto out_free;
}
mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0; mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0;
mvm->aux_queue = 15; mvm->aux_queue = 15;
@ -452,6 +462,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_LIST_HEAD(&mvm->aux_roc_te_list); INIT_LIST_HEAD(&mvm->aux_roc_te_list);
INIT_LIST_HEAD(&mvm->async_handlers_list); INIT_LIST_HEAD(&mvm->async_handlers_list);
spin_lock_init(&mvm->time_event_lock); spin_lock_init(&mvm->time_event_lock);
spin_lock_init(&mvm->queue_info_lock);
INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
@ -717,18 +728,11 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm,
} }
} }
static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, static void iwl_mvm_rx_common(struct iwl_mvm *mvm,
struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb,
struct iwl_rx_cmd_buffer *rxb) struct iwl_rx_packet *pkt)
{ {
struct iwl_rx_packet *pkt = rxb_addr(rxb); int i;
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u8 i;
if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) {
iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
return;
}
iwl_mvm_rx_check_trigger(mvm, pkt); iwl_mvm_rx_check_trigger(mvm, pkt);
@ -768,40 +772,84 @@ static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode,
} }
} }
static void iwl_mvm_rx(struct iwl_op_mode *op_mode,
struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
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);
else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
else
iwl_mvm_rx_common(mvm, rxb, pkt);
}
static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
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);
else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
else
iwl_mvm_rx_common(mvm, rxb, pkt);
}
static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
{ {
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
int mq = mvm->queue_to_mac80211[queue]; unsigned long mq;
int q;
if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) spin_lock_bh(&mvm->queue_info_lock);
mq = mvm->queue_info[queue].hw_queue_to_mac80211;
spin_unlock_bh(&mvm->queue_info_lock);
if (WARN_ON_ONCE(!mq))
return; return;
if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) { for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) {
if (atomic_inc_return(&mvm->mac80211_queue_stop_count[q]) > 1) {
IWL_DEBUG_TX_QUEUES(mvm, IWL_DEBUG_TX_QUEUES(mvm,
"queue %d (mac80211 %d) already stopped\n", "queue %d (mac80211 %d) already stopped\n",
queue, mq); queue, q);
return; continue;
} }
ieee80211_stop_queue(mvm->hw, mq); ieee80211_stop_queue(mvm->hw, q);
}
} }
static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) 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); struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
int mq = mvm->queue_to_mac80211[queue]; unsigned long mq;
int q;
if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE)) spin_lock_bh(&mvm->queue_info_lock);
mq = mvm->queue_info[queue].hw_queue_to_mac80211;
spin_unlock_bh(&mvm->queue_info_lock);
if (WARN_ON_ONCE(!mq))
return; return;
if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) { for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) {
if (atomic_dec_return(&mvm->mac80211_queue_stop_count[q]) > 0) {
IWL_DEBUG_TX_QUEUES(mvm, IWL_DEBUG_TX_QUEUES(mvm,
"queue %d (mac80211 %d) still stopped\n", "queue %d (mac80211 %d) still stopped\n",
queue, mq); queue, q);
return; continue;
} }
ieee80211_wake_queue(mvm->hw, mq); ieee80211_wake_queue(mvm->hw, q);
}
} }
void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
@ -1347,17 +1395,38 @@ int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
return _iwl_mvm_exit_d0i3(mvm); return _iwl_mvm_exit_d0i3(mvm);
} }
#define IWL_MVM_COMMON_OPS \
/* these could be differentiated */ \
.queue_full = iwl_mvm_stop_sw_queue, \
.queue_not_full = iwl_mvm_wake_sw_queue, \
.hw_rf_kill = iwl_mvm_set_hw_rfkill_state, \
.free_skb = iwl_mvm_free_skb, \
.nic_error = iwl_mvm_nic_error, \
.cmd_queue_full = iwl_mvm_cmd_queue_full, \
.nic_config = iwl_mvm_nic_config, \
.enter_d0i3 = iwl_mvm_enter_d0i3, \
.exit_d0i3 = iwl_mvm_exit_d0i3, \
/* as we only register one, these MUST be common! */ \
.start = iwl_op_mode_mvm_start, \
.stop = iwl_op_mode_mvm_stop
static const struct iwl_op_mode_ops iwl_mvm_ops = { static const struct iwl_op_mode_ops iwl_mvm_ops = {
.start = iwl_op_mode_mvm_start, IWL_MVM_COMMON_OPS,
.stop = iwl_op_mode_mvm_stop, .rx = iwl_mvm_rx,
.rx = iwl_mvm_rx_dispatch, };
.queue_full = iwl_mvm_stop_sw_queue,
.queue_not_full = iwl_mvm_wake_sw_queue, static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
.hw_rf_kill = iwl_mvm_set_hw_rfkill_state, struct napi_struct *napi,
.free_skb = iwl_mvm_free_skb, struct iwl_rx_cmd_buffer *rxb,
.nic_error = iwl_mvm_nic_error, unsigned int queue)
.cmd_queue_full = iwl_mvm_cmd_queue_full, {
.nic_config = iwl_mvm_nic_config, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
.enter_d0i3 = iwl_mvm_enter_d0i3,
.exit_d0i3 = iwl_mvm_exit_d0i3, iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
}
static const struct iwl_op_mode_ops iwl_mvm_ops_mq = {
IWL_MVM_COMMON_OPS,
.rx = iwl_mvm_rx_mq,
.rx_rss = iwl_mvm_rx_mq_rss,
}; };

View File

@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * 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 * 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 * 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) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -306,13 +308,50 @@ static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
return radar_detect; return radar_detect;
} }
static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd,
bool host_awake)
{
int dtimper = vif->bss_conf.dtim_period ?: 1;
int skip;
/* disable, in case we're supposed to override */
cmd->skip_dtim_periods = 0;
cmd->flags &= ~cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
if (iwl_mvm_power_is_radar(vif))
return;
if (dtimper >= 10)
return;
/* TODO: check that multicast wake lock is off */
if (host_awake) {
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP)
return;
skip = 2;
} else {
int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
if (WARN_ON(!dtimper_tu))
return;
/* configure skip over dtim up to 306TU - 314 msec */
skip = max_t(u8, 1, 306 / dtimper_tu);
}
/* the firmware really expects "look at every X DTIMs", so add 1 */
cmd->skip_dtim_periods = 1 + skip;
cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
}
static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct iwl_mac_power_cmd *cmd) struct iwl_mac_power_cmd *cmd)
{ {
int dtimper, bi; int dtimper, bi;
int keep_alive; int keep_alive;
bool radar_detect = false;
struct iwl_mvm_vif *mvmvif __maybe_unused = struct iwl_mvm_vif *mvmvif __maybe_unused =
iwl_mvm_vif_from_mac80211(vif); iwl_mvm_vif_from_mac80211(vif);
@ -350,16 +389,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm,
cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD; cmd->lprx_rssi_threshold = POWER_LPRX_RSSI_THRESHOLD;
} }
/* Check if radar detection is required on current channel */ iwl_mvm_power_config_skip_dtim(mvm, vif, cmd,
radar_detect = iwl_mvm_power_is_radar(vif); mvm->cur_ucode != IWL_UCODE_WOWLAN);
/* Check skip over DTIM conditions */
if (!radar_detect && (dtimper < 10) &&
(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP ||
mvm->cur_ucode == IWL_UCODE_WOWLAN)) {
cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
cmd->skip_dtim_periods = 3;
}
if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { if (mvm->cur_ucode != IWL_UCODE_WOWLAN) {
cmd->rx_data_timeout = cmd->rx_data_timeout =
@ -440,14 +471,14 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm,
int iwl_mvm_power_update_device(struct iwl_mvm *mvm) int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
{ {
struct iwl_device_power_cmd cmd = { struct iwl_device_power_cmd cmd = {
.flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), .flags = 0,
}; };
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
mvm->ps_disabled = true; mvm->ps_disabled = true;
if (mvm->ps_disabled) if (!mvm->ps_disabled)
cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 : if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 :
@ -964,24 +995,11 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
return 0; return 0;
iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_build_cmd(mvm, vif, &cmd);
if (enable) {
/* configure skip over dtim up to 306TU - 314 msec */
int dtimper = vif->bss_conf.dtim_period ?: 1;
int dtimper_tu = dtimper * vif->bss_conf.beacon_int;
bool radar_detect = iwl_mvm_power_is_radar(vif);
if (WARN_ON(!dtimper_tu)) /* when enabling D0i3, override the skip-over-dtim configuration */
return 0; if (enable)
iwl_mvm_power_config_skip_dtim(mvm, vif, &cmd, false);
/* Check skip over DTIM conditions */
/* TODO: check that multicast wake lock is off */
if (!radar_detect && (dtimper < 10)) {
cmd.skip_dtim_periods = 306 / dtimper_tu;
if (cmd.skip_dtim_periods)
cmd.flags |= cpu_to_le16(
POWER_FLAGS_SKIP_OVER_DTIM_MSK);
}
}
iwl_mvm_power_log(mvm, &cmd); iwl_mvm_power_log(mvm, &cmd);
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd));

View File

@ -524,14 +524,56 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
return lq_types[type]; return lq_types[type];
} }
static char *rs_pretty_rate(const struct rs_rate *rate)
{
static char buf[40];
static const char * const legacy_rates[] = {
[IWL_RATE_1M_INDEX] = "1M",
[IWL_RATE_2M_INDEX] = "2M",
[IWL_RATE_5M_INDEX] = "5.5M",
[IWL_RATE_11M_INDEX] = "11M",
[IWL_RATE_6M_INDEX] = "6M",
[IWL_RATE_9M_INDEX] = "9M",
[IWL_RATE_12M_INDEX] = "12M",
[IWL_RATE_18M_INDEX] = "18M",
[IWL_RATE_24M_INDEX] = "24M",
[IWL_RATE_36M_INDEX] = "36M",
[IWL_RATE_48M_INDEX] = "48M",
[IWL_RATE_54M_INDEX] = "54M",
};
static const char *const ht_vht_rates[] = {
[IWL_RATE_MCS_0_INDEX] = "MCS0",
[IWL_RATE_MCS_1_INDEX] = "MCS1",
[IWL_RATE_MCS_2_INDEX] = "MCS2",
[IWL_RATE_MCS_3_INDEX] = "MCS3",
[IWL_RATE_MCS_4_INDEX] = "MCS4",
[IWL_RATE_MCS_5_INDEX] = "MCS5",
[IWL_RATE_MCS_6_INDEX] = "MCS6",
[IWL_RATE_MCS_7_INDEX] = "MCS7",
[IWL_RATE_MCS_8_INDEX] = "MCS8",
[IWL_RATE_MCS_9_INDEX] = "MCS9",
};
const char *rate_str;
if (is_type_legacy(rate->type))
rate_str = legacy_rates[rate->index];
else if (is_type_ht(rate->type) || is_type_vht(rate->type))
rate_str = ht_vht_rates[rate->index];
else
rate_str = "BAD_RATE";
sprintf(buf, "(%s|%s|%s)", rs_pretty_lq_type(rate->type),
rs_pretty_ant(rate->ant), rate_str);
return buf;
}
static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate, static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
const char *prefix) const char *prefix)
{ {
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC: %d\n", "%s: %s BW: %d SGI: %d LDPC: %d STBC: %d\n",
prefix, rs_pretty_lq_type(rate->type), prefix, rs_pretty_rate(rate), rate->bw,
rate->index, rs_pretty_ant(rate->ant), rate->sgi, rate->ldpc, rate->stbc);
rate->bw, rate->sgi, rate->ldpc, rate->stbc);
} }
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
@ -1485,7 +1527,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
u32 target_tpt; u32 target_tpt;
int rate_idx; int rate_idx;
if (success_ratio > IWL_MVM_RS_SR_NO_DECREASE) { if (success_ratio >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) {
target_tpt = 100 * expected_current_tpt; target_tpt = 100 * expected_current_tpt;
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n", "SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n",
@ -1493,7 +1535,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
} else { } else {
target_tpt = lq_sta->last_tpt; target_tpt = lq_sta->last_tpt;
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"SR %d not thag good. Find rate exceeding ACTUAL_TPT %d\n", "SR %d not that good. Find rate exceeding ACTUAL_TPT %d\n",
success_ratio, target_tpt); success_ratio, target_tpt);
} }
@ -1622,6 +1664,51 @@ static void rs_update_rate_tbl(struct iwl_mvm *mvm,
iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false); iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, false);
} }
static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl,
enum rs_action scale_action)
{
if (sta->bandwidth != IEEE80211_STA_RX_BW_80)
return false;
if (!is_vht_siso(&tbl->rate))
return false;
if ((tbl->rate.bw == RATE_MCS_CHAN_WIDTH_80) &&
(tbl->rate.index == IWL_RATE_MCS_0_INDEX) &&
(scale_action == RS_ACTION_DOWNSCALE)) {
tbl->rate.bw = RATE_MCS_CHAN_WIDTH_20;
tbl->rate.index = IWL_RATE_MCS_4_INDEX;
IWL_DEBUG_RATE(mvm, "Switch 80Mhz SISO MCS0 -> 20Mhz MCS4\n");
goto tweaked;
}
/* Go back to 80Mhz MCS1 only if we've established that 20Mhz MCS5 is
* sustainable, i.e. we're past the test window. We can't go back
* if MCS5 is just tested as this will happen always after switching
* to 20Mhz MCS4 because the rate stats are cleared.
*/
if ((tbl->rate.bw == RATE_MCS_CHAN_WIDTH_20) &&
(((tbl->rate.index == IWL_RATE_MCS_5_INDEX) &&
(scale_action == RS_ACTION_STAY)) ||
((tbl->rate.index > IWL_RATE_MCS_5_INDEX) &&
(scale_action == RS_ACTION_UPSCALE)))) {
tbl->rate.bw = RATE_MCS_CHAN_WIDTH_80;
tbl->rate.index = IWL_RATE_MCS_1_INDEX;
IWL_DEBUG_RATE(mvm, "Switch 20Mhz SISO MCS5 -> 80Mhz MCS1\n");
goto tweaked;
}
return false;
tweaked:
rs_set_expected_tpt_table(lq_sta, tbl);
rs_rate_scale_clear_tbl_windows(mvm, tbl);
return true;
}
static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta, struct iwl_lq_sta *lq_sta,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
@ -2174,9 +2261,9 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) && if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) &&
(window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) { (window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) {
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"(%s: %d): Test Window: succ %d total %d\n", "%s: Test Window: succ %d total %d\n",
rs_pretty_lq_type(rate->type), rs_pretty_rate(rate),
index, window->success_counter, window->counter); window->success_counter, window->counter);
/* Can't calculate this yet; not enough history */ /* Can't calculate this yet; not enough history */
window->average_tpt = IWL_INVALID_VALUE; window->average_tpt = IWL_INVALID_VALUE;
@ -2253,8 +2340,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
high_tpt = tbl->win[high].average_tpt; high_tpt = tbl->win[high].average_tpt;
IWL_DEBUG_RATE(mvm, IWL_DEBUG_RATE(mvm,
"(%s: %d): cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n", "%s: cur_tpt %d SR %d low %d high %d low_tpt %d high_tpt %d\n",
rs_pretty_lq_type(rate->type), index, current_tpt, sr, rs_pretty_rate(rate), current_tpt, sr,
low, high, low_tpt, high_tpt); low, high, low_tpt, high_tpt);
scale_action = rs_get_rate_action(mvm, tbl, sr, low, high, scale_action = rs_get_rate_action(mvm, tbl, sr, low, high,
@ -2305,6 +2392,8 @@ lq_update:
/* Replace uCode's rate table for the destination station. */ /* Replace uCode's rate table for the destination station. */
if (update_lq) { if (update_lq) {
tbl->rate.index = index; tbl->rate.index = index;
if (IWL_MVM_RS_80_20_FAR_RANGE_TWEAK)
rs_tweak_rate_tbl(mvm, sta, lq_sta, tbl, scale_action);
rs_update_rate_tbl(mvm, sta, lq_sta, tbl); rs_update_rate_tbl(mvm, sta, lq_sta, tbl);
} }
@ -2542,7 +2631,6 @@ static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm,
} }
} }
rs_dump_rate(mvm, rate, "OPTIMAL RATE");
return rate; return rate;
} }

View File

@ -346,8 +346,8 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
/* This is fine since we don't support multiple AP interfaces */ /* This is fine since we don't support multiple AP interfaces */
sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL); sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
if (sta) { if (sta) {
struct iwl_mvm_sta *mvmsta; struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvmsta = iwl_mvm_sta_from_mac80211(sta);
rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status); rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) && if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&

View File

@ -234,7 +234,9 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
/* Found a place for all queues - enable them */ /* Found a place for all queues - enable them */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac],
iwl_mvm_ac_to_tx_fifo[ac], wdg_timeout); mvmsta->hw_queue[ac],
iwl_mvm_ac_to_tx_fifo[ac], 0,
wdg_timeout);
mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]);
} }
@ -253,7 +255,7 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
/* disable the TDLS STA-specific queues */ /* disable the TDLS STA-specific queues */
sta_msk = mvmsta->tfd_queue_msk; sta_msk = mvmsta->tfd_queue_msk;
for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE) for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE)
iwl_mvm_disable_txq(mvm, i, 0); iwl_mvm_disable_txq(mvm, i, i, 0, 0);
} }
int iwl_mvm_add_sta(struct iwl_mvm *mvm, int iwl_mvm_add_sta(struct iwl_mvm *mvm,
@ -277,7 +279,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_AP) { if (vif->type == NL80211_IFTYPE_AP) {
mvmvif->ap_assoc_sta_count++; mvmvif->ap_assoc_sta_count++;
iwl_mvm_mac_ctxt_cmd_ap(mvm, vif, FW_CTXT_ACTION_MODIFY); iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
} }
spin_lock_init(&mvm_sta->lock); spin_lock_init(&mvm_sta->lock);
@ -292,7 +294,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
/* HW restart, don't assume the memory has been zeroed */ /* HW restart, don't assume the memory has been zeroed */
atomic_set(&mvm->pending_frames[sta_id], 0); atomic_set(&mvm->pending_frames[sta_id], 0);
mvm_sta->tid_disable_agg = 0; mvm_sta->tid_disable_agg = 0xffff; /* No aggs at first */
mvm_sta->tfd_queue_msk = 0; mvm_sta->tfd_queue_msk = 0;
/* allocate new queues for a TDLS station */ /* allocate new queues for a TDLS station */
@ -472,7 +474,7 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
unsigned long i, msk = mvm->tfd_drained[sta_id]; unsigned long i, msk = mvm->tfd_drained[sta_id];
for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE) for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE)
iwl_mvm_disable_txq(mvm, i, 0); iwl_mvm_disable_txq(mvm, i, i, 0, 0);
mvm->tfd_drained[sta_id] = 0; mvm->tfd_drained[sta_id] = 0;
IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n", IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
@ -651,8 +653,8 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
/* Map Aux queue to fifo - needs to happen before adding Aux station */ /* Map Aux queue to fifo - needs to happen before adding Aux station */
iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue,
IWL_MVM_TX_FIFO_MCAST, wdg_timeout); IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
/* Allocate aux station and assign to it the aux queue */ /* Allocate aux station and assign to it the aux queue */
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue), ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
@ -923,6 +925,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_tid_data *tid_data; struct iwl_mvm_tid_data *tid_data;
int txq_id; int txq_id;
int ret;
if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
return -EINVAL; return -EINVAL;
@ -935,17 +938,6 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
for (txq_id = mvm->first_agg_queue;
txq_id <= mvm->last_agg_queue; txq_id++)
if (mvm->queue_to_mac80211[txq_id] ==
IWL_INVALID_MAC80211_QUEUE)
break;
if (txq_id > mvm->last_agg_queue) {
IWL_ERR(mvm, "Failed to allocate agg queue\n");
return -EIO;
}
spin_lock_bh(&mvmsta->lock); spin_lock_bh(&mvmsta->lock);
/* possible race condition - we entered D0i3 while starting agg */ /* possible race condition - we entered D0i3 while starting agg */
@ -955,8 +947,18 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EIO; return -EIO;
} }
/* the new tx queue is still connected to the same mac80211 queue */ spin_lock_bh(&mvm->queue_info_lock);
mvm->queue_to_mac80211[txq_id] = vif->hw_queue[tid_to_mac80211_ac[tid]];
txq_id = iwl_mvm_find_free_queue(mvm, mvm->first_agg_queue,
mvm->last_agg_queue);
if (txq_id < 0) {
ret = txq_id;
spin_unlock_bh(&mvm->queue_info_lock);
IWL_ERR(mvm, "Failed to allocate agg queue\n");
goto release_locks;
}
mvm->queue_info[txq_id].setup_reserved = true;
spin_unlock_bh(&mvm->queue_info_lock);
tid_data = &mvmsta->tid_data[tid]; tid_data = &mvmsta->tid_data[tid];
tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
@ -975,9 +977,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA; tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA;
} }
ret = 0;
release_locks:
spin_unlock_bh(&mvmsta->lock); spin_unlock_bh(&mvmsta->lock);
return 0; return ret;
} }
int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@ -1005,13 +1010,19 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid, iwl_mvm_enable_agg_txq(mvm, queue,
buf_size, ssn, wdg_timeout); vif->hw_queue[tid_to_mac80211_ac[tid]], fifo,
mvmsta->sta_id, tid, buf_size, ssn, wdg_timeout);
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true); ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
if (ret) if (ret)
return -EIO; return -EIO;
/* No need to mark as reserved */
spin_lock_bh(&mvm->queue_info_lock);
mvm->queue_info[queue].setup_reserved = false;
spin_unlock_bh(&mvm->queue_info_lock);
/* /*
* Even though in theory the peer could have different * Even though in theory the peer could have different
* aggregation reorder buffer sizes for different sessions, * aggregation reorder buffer sizes for different sessions,
@ -1056,6 +1067,11 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvmsta->agg_tids &= ~BIT(tid); mvmsta->agg_tids &= ~BIT(tid);
/* No need to mark as reserved anymore */
spin_lock_bh(&mvm->queue_info_lock);
mvm->queue_info[txq_id].setup_reserved = false;
spin_unlock_bh(&mvm->queue_info_lock);
switch (tid_data->state) { switch (tid_data->state) {
case IWL_AGG_ON: case IWL_AGG_ON:
tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number); tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
@ -1073,14 +1089,15 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
tid_data->ssn = 0xffff; tid_data->ssn = 0xffff;
tid_data->state = IWL_AGG_OFF; tid_data->state = IWL_AGG_OFF;
mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
spin_unlock_bh(&mvmsta->lock); spin_unlock_bh(&mvmsta->lock);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
iwl_mvm_disable_txq(mvm, txq_id, 0); iwl_mvm_disable_txq(mvm, txq_id,
vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
0);
return 0; return 0;
case IWL_AGG_STARTING: case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA: case IWL_EMPTYING_HW_QUEUE_ADDBA:
@ -1091,7 +1108,6 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* No barriers since we are under mutex */ /* No barriers since we are under mutex */
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
mvm->queue_to_mac80211[txq_id] = IWL_INVALID_MAC80211_QUEUE;
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
tid_data->state = IWL_AGG_OFF; tid_data->state = IWL_AGG_OFF;
@ -1132,6 +1148,11 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvmsta->agg_tids &= ~BIT(tid); mvmsta->agg_tids &= ~BIT(tid);
spin_unlock_bh(&mvmsta->lock); spin_unlock_bh(&mvmsta->lock);
/* No need to mark as reserved */
spin_lock_bh(&mvm->queue_info_lock);
mvm->queue_info[txq_id].setup_reserved = false;
spin_unlock_bh(&mvm->queue_info_lock);
if (old_state >= IWL_AGG_ON) { if (old_state >= IWL_AGG_ON) {
iwl_mvm_drain_sta(mvm, mvmsta, true); iwl_mvm_drain_sta(mvm, mvmsta, true);
if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true)) if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
@ -1142,12 +1163,11 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
iwl_mvm_disable_txq(mvm, tid_data->txq_id, 0); iwl_mvm_disable_txq(mvm, tid_data->txq_id,
vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
0);
} }
mvm->queue_to_mac80211[tid_data->txq_id] =
IWL_INVALID_MAC80211_QUEUE;
return 0; return 0;
} }

View File

@ -185,6 +185,7 @@ int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm,
} }
cmd->sta_id = mvmvif->bcast_sta.sta_id; cmd->sta_id = mvmvif->bcast_sta.sta_id;
memcpy(cmd->bssid, vif->addr, ETH_ALEN);
return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD,
IWL_ALWAYS_LONG_GROUP, 0), IWL_ALWAYS_LONG_GROUP, 0),
0, sizeof(*cmd), cmd); 0, sizeof(*cmd), cmd);

View File

@ -60,7 +60,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
*****************************************************************************/ *****************************************************************************/
#ifndef __tof #ifndef __tof_h__
#define __tof_h__ #define __tof_h__
#include "fw-api-tof.h" #include "fw-api-tof.h"

View File

@ -176,17 +176,27 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
struct iwl_dts_measurement_cmd cmd = { struct iwl_dts_measurement_cmd cmd = {
.flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP),
}; };
u32 cmdid;
return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0, if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
cmdid = iwl_cmd_id(CMD_DTS_MEASUREMENT_TRIGGER_WIDE,
PHY_OPS_GROUP, 0);
else
cmdid = CMD_DTS_MEASUREMENT_TRIGGER;
return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0,
sizeof(cmd), &cmd); sizeof(cmd), &cmd);
} }
int iwl_mvm_get_temp(struct iwl_mvm *mvm) int iwl_mvm_get_temp(struct iwl_mvm *mvm)
{ {
struct iwl_notification_wait wait_temp_notif; struct iwl_notification_wait wait_temp_notif;
static const u16 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP,
DTS_MEASUREMENT_NOTIF_WIDE) };
int ret, temp; int ret, temp;
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
temp_notif[0] = DTS_MEASUREMENT_NOTIFICATION;
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif, iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,

View File

@ -560,15 +560,10 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
IWL_DEBUG_TX_QUEUES(mvm, IWL_DEBUG_TX_QUEUES(mvm,
"Can continue DELBA flow ssn = next_recl = %d\n", "Can continue DELBA flow ssn = next_recl = %d\n",
tid_data->next_reclaimed); tid_data->next_reclaimed);
iwl_mvm_disable_txq(mvm, tid_data->txq_id, CMD_ASYNC); iwl_mvm_disable_txq(mvm, tid_data->txq_id,
vif->hw_queue[tid_to_mac80211_ac[tid]], tid,
CMD_ASYNC);
tid_data->state = IWL_AGG_OFF; tid_data->state = IWL_AGG_OFF;
/*
* we can't hold the mutex - but since we are after a sequence
* point (call to iwl_mvm_disable_txq(), so we don't even need
* a memory barrier.
*/
mvm->queue_to_mac80211[tid_data->txq_id] =
IWL_INVALID_MAC80211_QUEUE;
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break; break;

View File

@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * 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 * 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 * it under the terms of version 2 of the GNU General Public License as
@ -657,10 +658,53 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
if (mvm->support_umac_log) if (mvm->support_umac_log)
iwl_mvm_dump_umac_error_log(mvm); iwl_mvm_dump_umac_error_log(mvm);
} }
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
const struct iwl_trans_txq_scd_cfg *cfg, int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq)
{
int i;
lockdep_assert_held(&mvm->queue_info_lock);
for (i = minq; i <= maxq; i++)
if (mvm->queue_info[i].hw_queue_refcount == 0 &&
!mvm->queue_info[i].setup_reserved)
return i;
return -ENOSPC;
}
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
u16 ssn, const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int wdg_timeout) unsigned int wdg_timeout)
{ {
bool enable_queue = true;
spin_lock_bh(&mvm->queue_info_lock);
/* Make sure this TID isn't already enabled */
if (mvm->queue_info[queue].tid_bitmap & BIT(cfg->tid)) {
spin_unlock_bh(&mvm->queue_info_lock);
IWL_ERR(mvm, "Trying to enable TXQ with existing TID %d\n",
cfg->tid);
return;
}
/* Update mappings and refcounts */
mvm->queue_info[queue].hw_queue_to_mac80211 |= BIT(mac80211_queue);
mvm->queue_info[queue].hw_queue_refcount++;
if (mvm->queue_info[queue].hw_queue_refcount > 1)
enable_queue = false;
mvm->queue_info[queue].tid_bitmap |= BIT(cfg->tid);
IWL_DEBUG_TX_QUEUES(mvm,
"Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
queue, mvm->queue_info[queue].hw_queue_refcount,
mvm->queue_info[queue].hw_queue_to_mac80211);
spin_unlock_bh(&mvm->queue_info_lock);
/* Send the enabling command if we need to */
if (enable_queue) {
struct iwl_scd_txq_cfg_cmd cmd = { struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue, .scd_queue = queue,
.enable = 1, .enable = 1,
@ -672,19 +716,85 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
.tid = cfg->tid, .tid = cfg->tid,
}; };
iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout); iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL,
WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd), wdg_timeout);
"Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo); WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd),
&cmd),
"Failed to configure queue %d on FIFO %d\n", queue,
cfg->fifo);
}
} }
void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags) void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
u8 tid, u8 flags)
{ {
struct iwl_scd_txq_cfg_cmd cmd = { struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue, .scd_queue = queue,
.enable = 0, .enable = 0,
}; };
bool remove_mac_queue = true;
int ret; int ret;
spin_lock_bh(&mvm->queue_info_lock);
if (WARN_ON(mvm->queue_info[queue].hw_queue_refcount == 0)) {
spin_unlock_bh(&mvm->queue_info_lock);
return;
}
mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
/*
* If there is another TID with the same AC - don't remove the MAC queue
* from the mapping
*/
if (tid < IWL_MAX_TID_COUNT) {
unsigned long tid_bitmap =
mvm->queue_info[queue].tid_bitmap;
int ac = tid_to_mac80211_ac[tid];
int i;
for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) {
if (tid_to_mac80211_ac[i] == ac)
remove_mac_queue = false;
}
}
if (remove_mac_queue)
mvm->queue_info[queue].hw_queue_to_mac80211 &=
~BIT(mac80211_queue);
mvm->queue_info[queue].hw_queue_refcount--;
cmd.enable = mvm->queue_info[queue].hw_queue_refcount ? 1 : 0;
IWL_DEBUG_TX_QUEUES(mvm,
"Disabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
queue,
mvm->queue_info[queue].hw_queue_refcount,
mvm->queue_info[queue].hw_queue_to_mac80211);
/* If the queue is still enabled - nothing left to do in this func */
if (cmd.enable) {
spin_unlock_bh(&mvm->queue_info_lock);
return;
}
/* Make sure queue info is correct even though we overwrite it */
WARN(mvm->queue_info[queue].hw_queue_refcount ||
mvm->queue_info[queue].tid_bitmap ||
mvm->queue_info[queue].hw_queue_to_mac80211,
"TXQ #%d info out-of-sync - refcount=%d, mac map=0x%x, tid=0x%x\n",
queue, mvm->queue_info[queue].hw_queue_refcount,
mvm->queue_info[queue].hw_queue_to_mac80211,
mvm->queue_info[queue].tid_bitmap);
/* If we are here - the queue is freed and we can zero out these vals */
mvm->queue_info[queue].hw_queue_refcount = 0;
mvm->queue_info[queue].tid_bitmap = 0;
mvm->queue_info[queue].hw_queue_to_mac80211 = 0;
spin_unlock_bh(&mvm->queue_info_lock);
iwl_trans_txq_disable(mvm->trans, queue, false); iwl_trans_txq_disable(mvm->trans, queue, false);
ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags, ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags,
sizeof(cmd), &cmd); sizeof(cmd), &cmd);