Merge tag 'iwlwifi-next-for-john-2014-10-29' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Emmanuel Grumbach <egrumbach@gmail.com> says: "The big new thing here is netdetect which allows the firmware to wake up the platform when a specific network is detected. Along with that I have fixes for d3 operation. The usual amount of rate scaling stuff - we now support STBC. The other commit that stands out is Johannes's work on devcoredump. He basically starts to use the standard infrastructure he built." Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
@@ -59,6 +59,7 @@ config IWLDVM
|
|||||||
|
|
||||||
config IWLMVM
|
config IWLMVM
|
||||||
tristate "Intel Wireless WiFi MVM Firmware support"
|
tristate "Intel Wireless WiFi MVM Firmware support"
|
||||||
|
select BACKPORT_WANT_DEV_COREDUMP
|
||||||
help
|
help
|
||||||
This is the driver that supports the MVM firmware which is
|
This is the driver that supports the MVM firmware which is
|
||||||
currently only available for 7260 and 3160 devices.
|
currently only available for 7260 and 3160 devices.
|
||||||
|
@@ -418,7 +418,7 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
|
|||||||
|
|
||||||
static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
|
static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
|
||||||
{
|
{
|
||||||
return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
|
return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
|
||||||
BT_UART_MSG_FRAME3SCOESCO_POS;
|
BT_UART_MSG_FRAME3SCOESCO_POS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1095,6 +1095,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||||||
u32 queues, bool drop)
|
u32 queues, bool drop)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||||
|
u32 scd_queues;
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
IWL_DEBUG_MAC80211(priv, "enter\n");
|
IWL_DEBUG_MAC80211(priv, "enter\n");
|
||||||
@@ -1108,18 +1109,19 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
scd_queues = BIT(priv->cfg->base_params->num_of_queues) - 1;
|
||||||
* mac80211 will not push any more frames for transmit
|
scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
|
||||||
* until the flush is completed
|
BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
|
||||||
*/
|
|
||||||
if (drop) {
|
if (vif)
|
||||||
IWL_DEBUG_MAC80211(priv, "send flush command\n");
|
scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
|
||||||
if (iwlagn_txfifo_flush(priv, 0)) {
|
|
||||||
|
IWL_DEBUG_TX_QUEUES(priv, "Flushing SCD queues: 0x%x\n", scd_queues);
|
||||||
|
if (iwlagn_txfifo_flush(priv, scd_queues)) {
|
||||||
IWL_ERR(priv, "flush request fail\n");
|
IWL_ERR(priv, "flush request fail\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
|
||||||
IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
|
|
||||||
iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
|
iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
|
||||||
done:
|
done:
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
@@ -82,7 +82,8 @@
|
|||||||
#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */
|
#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */
|
||||||
|
|
||||||
#define IWL8000_FW_PRE "iwlwifi-8000"
|
#define IWL8000_FW_PRE "iwlwifi-8000"
|
||||||
#define IWL8000_MODULE_FIRMWARE(api) IWL8000_FW_PRE __stringify(api) ".ucode"
|
#define IWL8000_MODULE_FIRMWARE(api) \
|
||||||
|
IWL8000_FW_PRE "-" __stringify(api) ".ucode"
|
||||||
|
|
||||||
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
|
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
|
||||||
#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin"
|
#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin"
|
||||||
@@ -103,6 +104,7 @@ static const struct iwl_base_params iwl8000_base_params = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct iwl_ht_params iwl8000_ht_params = {
|
static const struct iwl_ht_params iwl8000_ht_params = {
|
||||||
|
.stbc = true,
|
||||||
.ldpc = true,
|
.ldpc = true,
|
||||||
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
|
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
|
||||||
};
|
};
|
||||||
|
@@ -87,6 +87,16 @@ enum iwl_device_family {
|
|||||||
IWL_DEVICE_FAMILY_8000,
|
IWL_DEVICE_FAMILY_8000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool iwl_has_secure_boot(u32 hw_rev,
|
||||||
|
enum iwl_device_family family)
|
||||||
|
{
|
||||||
|
/* return 1 only for family 8000 B0 */
|
||||||
|
if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LED mode
|
* LED mode
|
||||||
* IWL_LED_DEFAULT: use device default
|
* IWL_LED_DEFAULT: use device default
|
||||||
@@ -246,6 +256,7 @@ struct iwl_pwr_tx_backoff {
|
|||||||
* @nvm_hw_section_num: the ID of the HW NVM section
|
* @nvm_hw_section_num: the ID of the HW NVM section
|
||||||
* @pwr_tx_backoffs: translation table between power limits and backoffs
|
* @pwr_tx_backoffs: translation table between power limits and backoffs
|
||||||
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
|
* @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
|
||||||
|
* @max_tx_agg_size: max TX aggregation size of the ADDBA request/response
|
||||||
*
|
*
|
||||||
* We enable the driver to be backward compatible wrt. hardware features.
|
* We enable the driver to be backward compatible wrt. hardware features.
|
||||||
* API differences in uCode shouldn't be handled here but through TLVs
|
* API differences in uCode shouldn't be handled here but through TLVs
|
||||||
@@ -285,6 +296,7 @@ struct iwl_cfg {
|
|||||||
const char *default_nvm_file;
|
const char *default_nvm_file;
|
||||||
unsigned int max_rx_agg_size;
|
unsigned int max_rx_agg_size;
|
||||||
bool disable_dummy_notification;
|
bool disable_dummy_notification;
|
||||||
|
unsigned int max_tx_agg_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -807,19 +807,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
|
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
|
||||||
tlv_len);
|
tlv_len);
|
||||||
drv->fw.mvm_fw = true;
|
drv->fw.mvm_fw = true;
|
||||||
drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
|
|
||||||
break;
|
break;
|
||||||
case IWL_UCODE_TLV_SECURE_SEC_INIT:
|
case IWL_UCODE_TLV_SECURE_SEC_INIT:
|
||||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
|
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
|
||||||
tlv_len);
|
tlv_len);
|
||||||
drv->fw.mvm_fw = true;
|
drv->fw.mvm_fw = true;
|
||||||
drv->fw.img[IWL_UCODE_INIT].is_secure = true;
|
|
||||||
break;
|
break;
|
||||||
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
|
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
|
||||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
|
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
|
||||||
tlv_len);
|
tlv_len);
|
||||||
drv->fw.mvm_fw = true;
|
drv->fw.mvm_fw = true;
|
||||||
drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
|
|
||||||
break;
|
break;
|
||||||
case IWL_UCODE_TLV_NUM_OF_CPU:
|
case IWL_UCODE_TLV_NUM_OF_CPU:
|
||||||
if (tlv_len != sizeof(u32))
|
if (tlv_len != sizeof(u32))
|
||||||
|
@@ -227,7 +227,6 @@ struct fw_desc {
|
|||||||
|
|
||||||
struct fw_img {
|
struct fw_img {
|
||||||
struct fw_desc sec[IWL_UCODE_SECTION_MAX];
|
struct fw_desc sec[IWL_UCODE_SECTION_MAX];
|
||||||
bool is_secure;
|
|
||||||
bool is_dual_cpus;
|
bool is_dual_cpus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -535,9 +535,7 @@ struct iwl_trans_ops {
|
|||||||
void (*ref)(struct iwl_trans *trans);
|
void (*ref)(struct iwl_trans *trans);
|
||||||
void (*unref)(struct iwl_trans *trans);
|
void (*unref)(struct iwl_trans *trans);
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
||||||
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
|
struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -563,6 +561,7 @@ enum iwl_trans_state {
|
|||||||
* Set during transport allocation.
|
* Set during transport allocation.
|
||||||
* @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
|
||||||
* @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
|
||||||
@@ -589,6 +588,7 @@ struct iwl_trans {
|
|||||||
u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
|
u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size;
|
||||||
|
|
||||||
bool pm_support;
|
bool pm_support;
|
||||||
|
bool ltr_enabled;
|
||||||
|
|
||||||
/* The following fields are internal only */
|
/* The following fields are internal only */
|
||||||
struct kmem_cache *dev_cmd_pool;
|
struct kmem_cache *dev_cmd_pool;
|
||||||
@@ -702,7 +702,6 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
|
|||||||
trans->ops->unref(trans);
|
trans->ops->unref(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
||||||
static inline struct iwl_trans_dump_data *
|
static inline struct iwl_trans_dump_data *
|
||||||
iwl_trans_dump_data(struct iwl_trans *trans)
|
iwl_trans_dump_data(struct iwl_trans *trans)
|
||||||
{
|
{
|
||||||
@@ -710,7 +709,6 @@ iwl_trans_dump_data(struct iwl_trans *trans)
|
|||||||
return NULL;
|
return NULL;
|
||||||
return trans->ops->dump_data(trans);
|
return trans->ops->dump_data(trans);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
|
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
|
||||||
struct iwl_host_cmd *cmd)
|
struct iwl_host_cmd *cmd)
|
||||||
|
@@ -72,8 +72,6 @@
|
|||||||
#include "mvm.h"
|
#include "mvm.h"
|
||||||
#include "iwl-debug.h"
|
#include "iwl-debug.h"
|
||||||
|
|
||||||
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
|
|
||||||
|
|
||||||
const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
|
const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
|
||||||
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
|
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
|
||||||
[BT_KILL_MSK_NEVER] = 0xffffffff,
|
[BT_KILL_MSK_NEVER] = 0xffffffff,
|
||||||
@@ -302,11 +300,6 @@ static const __le64 iwl_ci_mask[][3] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
|
|
||||||
cpu_to_le32(0x28412201),
|
|
||||||
cpu_to_le32(0x11118451),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct corunning_block_luts {
|
struct corunning_block_luts {
|
||||||
u8 range;
|
u8 range;
|
||||||
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
|
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
|
||||||
@@ -605,7 +598,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
|||||||
|
|
||||||
bt_cmd->max_kill = cpu_to_le32(5);
|
bt_cmd->max_kill = cpu_to_le32(5);
|
||||||
bt_cmd->bt4_antenna_isolation_thr =
|
bt_cmd->bt4_antenna_isolation_thr =
|
||||||
cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD);
|
cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS);
|
||||||
bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
|
bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
|
||||||
bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
|
bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
|
||||||
bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
|
bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
|
||||||
@@ -638,8 +631,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
|
|||||||
|
|
||||||
memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
|
memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
|
||||||
sizeof(iwl_bt_prio_boost));
|
sizeof(iwl_bt_prio_boost));
|
||||||
memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut,
|
bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
|
||||||
sizeof(iwl_bt_mprio_lut));
|
bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
|
||||||
|
|
||||||
send_cmd:
|
send_cmd:
|
||||||
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
||||||
|
@@ -102,8 +102,6 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
|
|||||||
|
|
||||||
#undef EVENT_PRIO_ANT
|
#undef EVENT_PRIO_ANT
|
||||||
|
|
||||||
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
|
|
||||||
|
|
||||||
static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
|
static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
|
||||||
{
|
{
|
||||||
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
|
if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
|
||||||
@@ -290,11 +288,6 @@ static const __le64 iwl_ci_mask[][3] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
|
|
||||||
cpu_to_le32(0x28412201),
|
|
||||||
cpu_to_le32(0x11118451),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct corunning_block_luts {
|
struct corunning_block_luts {
|
||||||
u8 range;
|
u8 range;
|
||||||
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
|
__le32 lut20[BT_COEX_CORUN_LUT_SIZE];
|
||||||
@@ -593,7 +586,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bt_cmd->max_kill = 5;
|
bt_cmd->max_kill = 5;
|
||||||
bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
|
bt_cmd->bt4_antenna_isolation_thr =
|
||||||
|
IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS;
|
||||||
bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
|
bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
|
||||||
bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
|
bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
|
||||||
bt_cmd->bt4_tx_rx_max_freq0 = 15;
|
bt_cmd->bt4_tx_rx_max_freq0 = 15;
|
||||||
@@ -649,8 +643,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
|
|||||||
|
|
||||||
memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
|
memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
|
||||||
sizeof(iwl_bt_prio_boost));
|
sizeof(iwl_bt_prio_boost));
|
||||||
memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
|
bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
|
||||||
sizeof(iwl_bt_mprio_lut));
|
bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
|
||||||
|
|
||||||
send_cmd:
|
send_cmd:
|
||||||
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
|
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
|
||||||
|
@@ -92,8 +92,13 @@
|
|||||||
#define IWL_MVM_BT_COEX_SYNC2SCO 1
|
#define IWL_MVM_BT_COEX_SYNC2SCO 1
|
||||||
#define IWL_MVM_BT_COEX_CORUNNING 0
|
#define IWL_MVM_BT_COEX_CORUNNING 0
|
||||||
#define IWL_MVM_BT_COEX_MPLUT 1
|
#define IWL_MVM_BT_COEX_MPLUT 1
|
||||||
|
#define IWL_MVM_BT_COEX_MPLUT_REG0 0x2e402280
|
||||||
|
#define IWL_MVM_BT_COEX_MPLUT_REG1 0x7711a751
|
||||||
|
#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30
|
||||||
#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
|
#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
|
||||||
|
#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0
|
||||||
#define IWL_MVM_QUOTA_THRESHOLD 8
|
#define IWL_MVM_QUOTA_THRESHOLD 8
|
||||||
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
|
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
|
||||||
|
#define IWL_MVM_RS_DISABLE_MIMO 0
|
||||||
|
|
||||||
#endif /* __MVM_CONSTANTS_H */
|
#endif /* __MVM_CONSTANTS_H */
|
||||||
|
@@ -601,33 +601,6 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iwl_d3_iter_data {
|
|
||||||
struct iwl_mvm *mvm;
|
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
bool error;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
|
|
||||||
struct ieee80211_vif *vif)
|
|
||||||
{
|
|
||||||
struct iwl_d3_iter_data *data = _data;
|
|
||||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
||||||
|
|
||||||
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (data->vif) {
|
|
||||||
IWL_ERR(data->mvm, "More than one managed interface active!\n");
|
|
||||||
data->error = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->vif = vif;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *ap_sta)
|
struct ieee80211_sta *ap_sta)
|
||||||
{
|
{
|
||||||
@@ -783,144 +756,8 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||||||
IWL_ERR(mvm, "failed to set non-QoS seqno\n");
|
IWL_ERR(mvm, "failed to set non-QoS seqno\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
|
||||||
iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
|
|
||||||
const struct iwl_wowlan_config_cmd_v3 *cmd)
|
|
||||||
{
|
{
|
||||||
/* start only with the v2 part of the command */
|
|
||||||
u16 cmd_len = sizeof(cmd->common);
|
|
||||||
|
|
||||||
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID)
|
|
||||||
cmd_len = sizeof(*cmd);
|
|
||||||
|
|
||||||
return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
|
|
||||||
cmd_len, cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|
||||||
struct cfg80211_wowlan *wowlan,
|
|
||||||
bool test)
|
|
||||||
{
|
|
||||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
|
||||||
struct iwl_d3_iter_data suspend_iter_data = {
|
|
||||||
.mvm = mvm,
|
|
||||||
};
|
|
||||||
struct ieee80211_vif *vif;
|
|
||||||
struct iwl_mvm_vif *mvmvif;
|
|
||||||
struct ieee80211_sta *ap_sta;
|
|
||||||
struct iwl_mvm_sta *mvm_ap_sta;
|
|
||||||
struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
|
|
||||||
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
|
|
||||||
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
|
|
||||||
struct iwl_d3_manager_config d3_cfg_cmd_data = {
|
|
||||||
/*
|
|
||||||
* Program the minimum sleep time to 10 seconds, as many
|
|
||||||
* platforms have issues processing a wakeup signal while
|
|
||||||
* still being in the process of suspending.
|
|
||||||
*/
|
|
||||||
.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
|
|
||||||
};
|
|
||||||
struct iwl_host_cmd d3_cfg_cmd = {
|
|
||||||
.id = D3_CONFIG_CMD,
|
|
||||||
.flags = CMD_WANT_SKB,
|
|
||||||
.data[0] = &d3_cfg_cmd_data,
|
|
||||||
.len[0] = sizeof(d3_cfg_cmd_data),
|
|
||||||
};
|
|
||||||
struct wowlan_key_data key_data = {
|
|
||||||
.use_rsc_tsc = false,
|
|
||||||
.tkip = &tkip_cmd,
|
|
||||||
.use_tkip = false,
|
|
||||||
};
|
|
||||||
int ret;
|
|
||||||
int len __maybe_unused;
|
|
||||||
|
|
||||||
if (!wowlan) {
|
|
||||||
/*
|
|
||||||
* mac80211 shouldn't get here, but for D3 test
|
|
||||||
* it doesn't warrant a warning
|
|
||||||
*/
|
|
||||||
WARN_ON(!test);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
|
|
||||||
if (!key_data.rsc_tsc)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
mutex_lock(&mvm->mutex);
|
|
||||||
|
|
||||||
/* see if there's only a single BSS vif and it's associated */
|
|
||||||
ieee80211_iterate_active_interfaces_atomic(
|
|
||||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
|
||||||
iwl_mvm_d3_iface_iterator, &suspend_iter_data);
|
|
||||||
|
|
||||||
if (suspend_iter_data.error || !suspend_iter_data.vif) {
|
|
||||||
ret = 1;
|
|
||||||
goto out_noreset;
|
|
||||||
}
|
|
||||||
|
|
||||||
vif = suspend_iter_data.vif;
|
|
||||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
||||||
|
|
||||||
ap_sta = rcu_dereference_protected(
|
|
||||||
mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
|
|
||||||
lockdep_is_held(&mvm->mutex));
|
|
||||||
if (IS_ERR_OR_NULL(ap_sta)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto out_noreset;
|
|
||||||
}
|
|
||||||
|
|
||||||
mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
|
|
||||||
|
|
||||||
/* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */
|
|
||||||
|
|
||||||
wowlan_config_cmd.common.is_11n_connection =
|
|
||||||
ap_sta->ht_cap.ht_supported;
|
|
||||||
|
|
||||||
/* Query the last used seqno and set it */
|
|
||||||
ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out_noreset;
|
|
||||||
wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret);
|
|
||||||
|
|
||||||
iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common);
|
|
||||||
|
|
||||||
if (wowlan->disconnect)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
|
|
||||||
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
|
|
||||||
if (wowlan->magic_pkt)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
|
|
||||||
if (wowlan->gtk_rekey_failure)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
|
|
||||||
if (wowlan->eap_identity_req)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
|
|
||||||
if (wowlan->four_way_handshake)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
|
|
||||||
if (wowlan->n_patterns)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
|
|
||||||
|
|
||||||
if (wowlan->rfkill_release)
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
|
|
||||||
|
|
||||||
if (wowlan->tcp) {
|
|
||||||
/*
|
|
||||||
* Set the "link change" (really "link lost") flag as well
|
|
||||||
* since that implies losing the TCP connection.
|
|
||||||
*/
|
|
||||||
wowlan_config_cmd.common.wakeup_filter |=
|
|
||||||
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
|
|
||||||
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
|
|
||||||
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
|
|
||||||
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
iwl_mvm_cancel_scan(mvm);
|
iwl_mvm_cancel_scan(mvm);
|
||||||
|
|
||||||
iwl_trans_stop_device(mvm->trans);
|
iwl_trans_stop_device(mvm->trans);
|
||||||
@@ -945,13 +782,109 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||||||
mvm->ptk_ivlen = 0;
|
mvm->ptk_ivlen = 0;
|
||||||
mvm->ptk_icvlen = 0;
|
mvm->ptk_icvlen = 0;
|
||||||
|
|
||||||
ret = iwl_mvm_load_d3_fw(mvm);
|
return iwl_mvm_load_d3_fw(mvm);
|
||||||
if (ret)
|
}
|
||||||
goto out;
|
|
||||||
|
static int
|
||||||
|
iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
|
||||||
|
const struct iwl_wowlan_config_cmd_v3 *cmd)
|
||||||
|
{
|
||||||
|
/* start only with the v2 part of the command */
|
||||||
|
u16 cmd_len = sizeof(cmd->common);
|
||||||
|
|
||||||
|
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID)
|
||||||
|
cmd_len = sizeof(*cmd);
|
||||||
|
|
||||||
|
return iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0,
|
||||||
|
cmd_len, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
|
||||||
|
struct cfg80211_wowlan *wowlan,
|
||||||
|
struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
|
||||||
|
struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
|
||||||
|
struct ieee80211_sta *ap_sta)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
|
||||||
|
|
||||||
|
/* TODO: wowlan_config_cmd->common.wowlan_ba_teardown_tids */
|
||||||
|
|
||||||
|
wowlan_config_cmd->common.is_11n_connection =
|
||||||
|
ap_sta->ht_cap.ht_supported;
|
||||||
|
|
||||||
|
/* Query the last used seqno and set it */
|
||||||
|
ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
wowlan_config_cmd->common.non_qos_seq = cpu_to_le16(ret);
|
||||||
|
|
||||||
|
iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd->common);
|
||||||
|
|
||||||
|
if (wowlan->disconnect)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
|
||||||
|
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
|
||||||
|
if (wowlan->magic_pkt)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
|
||||||
|
if (wowlan->gtk_rekey_failure)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
|
||||||
|
if (wowlan->eap_identity_req)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
|
||||||
|
if (wowlan->four_way_handshake)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
|
||||||
|
if (wowlan->n_patterns)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
|
||||||
|
|
||||||
|
if (wowlan->rfkill_release)
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
|
||||||
|
|
||||||
|
if (wowlan->tcp) {
|
||||||
|
/*
|
||||||
|
* Set the "link change" (really "link lost") flag as well
|
||||||
|
* since that implies losing the TCP connection.
|
||||||
|
*/
|
||||||
|
wowlan_config_cmd->common.wakeup_filter |=
|
||||||
|
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
|
||||||
|
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
|
||||||
|
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
|
||||||
|
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
|
||||||
|
struct cfg80211_wowlan *wowlan,
|
||||||
|
struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
|
||||||
|
struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
|
||||||
|
struct ieee80211_sta *ap_sta)
|
||||||
|
{
|
||||||
|
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
|
||||||
|
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
|
||||||
|
struct wowlan_key_data key_data = {
|
||||||
|
.use_rsc_tsc = false,
|
||||||
|
.tkip = &tkip_cmd,
|
||||||
|
.use_tkip = false,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
|
ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
return ret;
|
||||||
|
|
||||||
|
key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
|
||||||
|
if (!key_data.rsc_tsc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!iwlwifi_mod_params.sw_crypto) {
|
if (!iwlwifi_mod_params.sw_crypto) {
|
||||||
/*
|
/*
|
||||||
@@ -1010,7 +943,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd);
|
ret = iwl_mvm_send_wowlan_config_cmd(mvm, wowlan_config_cmd);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -1023,9 +956,94 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
|
ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(key_data.rsc_tsc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||||
|
struct cfg80211_wowlan *wowlan,
|
||||||
|
bool test)
|
||||||
|
{
|
||||||
|
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||||
|
struct ieee80211_vif *vif = NULL;
|
||||||
|
struct iwl_mvm_vif *mvmvif = NULL;
|
||||||
|
struct ieee80211_sta *ap_sta = NULL;
|
||||||
|
struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
|
||||||
|
struct iwl_d3_manager_config d3_cfg_cmd_data = {
|
||||||
|
/*
|
||||||
|
* Program the minimum sleep time to 10 seconds, as many
|
||||||
|
* platforms have issues processing a wakeup signal while
|
||||||
|
* still being in the process of suspending.
|
||||||
|
*/
|
||||||
|
.min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
|
||||||
|
};
|
||||||
|
struct iwl_host_cmd d3_cfg_cmd = {
|
||||||
|
.id = D3_CONFIG_CMD,
|
||||||
|
.flags = CMD_WANT_SKB,
|
||||||
|
.data[0] = &d3_cfg_cmd_data,
|
||||||
|
.len[0] = sizeof(d3_cfg_cmd_data),
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
int len __maybe_unused;
|
||||||
|
|
||||||
|
if (!wowlan) {
|
||||||
|
/*
|
||||||
|
* mac80211 shouldn't get here, but for D3 test
|
||||||
|
* it doesn't warrant a warning
|
||||||
|
*/
|
||||||
|
WARN_ON(!test);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&mvm->mutex);
|
||||||
|
|
||||||
|
vif = iwl_mvm_get_bss_vif(mvm);
|
||||||
|
if (IS_ERR_OR_NULL(vif)) {
|
||||||
|
ret = 1;
|
||||||
|
goto out_noreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||||
|
|
||||||
|
/* if we're associated, this is wowlan */
|
||||||
|
if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
|
||||||
|
ap_sta = rcu_dereference_protected(
|
||||||
|
mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
|
||||||
|
lockdep_is_held(&mvm->mutex));
|
||||||
|
if (IS_ERR_OR_NULL(ap_sta)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_noreset;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
|
||||||
|
vif, mvmvif, ap_sta);
|
||||||
|
if (ret)
|
||||||
|
goto out_noreset;
|
||||||
|
|
||||||
|
ret = iwl_mvm_switch_to_d3(mvm);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
|
||||||
|
vif, mvmvif, ap_sta);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
} else if (mvm->nd_config) {
|
||||||
|
ret = iwl_mvm_switch_to_d3(mvm);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config,
|
||||||
|
mvm->nd_ies);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
ret = 1;
|
||||||
|
goto out_noreset;
|
||||||
|
}
|
||||||
|
|
||||||
ret = iwl_mvm_power_update_device(mvm);
|
ret = iwl_mvm_power_update_device(mvm);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -1060,8 +1078,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ieee80211_restart_hw(mvm->hw);
|
ieee80211_restart_hw(mvm->hw);
|
||||||
out_noreset:
|
out_noreset:
|
||||||
kfree(key_data.rsc_tsc);
|
|
||||||
|
|
||||||
mutex_unlock(&mvm->mutex);
|
mutex_unlock(&mvm->mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1592,9 +1608,6 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
|
|||||||
|
|
||||||
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
||||||
{
|
{
|
||||||
struct iwl_d3_iter_data resume_iter_data = {
|
|
||||||
.mvm = mvm,
|
|
||||||
};
|
|
||||||
struct ieee80211_vif *vif = NULL;
|
struct ieee80211_vif *vif = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
enum iwl_d3_status d3_status;
|
enum iwl_d3_status d3_status;
|
||||||
@@ -1603,15 +1616,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
|
|||||||
mutex_lock(&mvm->mutex);
|
mutex_lock(&mvm->mutex);
|
||||||
|
|
||||||
/* get the BSS vif pointer again */
|
/* get the BSS vif pointer again */
|
||||||
ieee80211_iterate_active_interfaces_atomic(
|
vif = iwl_mvm_get_bss_vif(mvm);
|
||||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
if (IS_ERR_OR_NULL(vif))
|
||||||
iwl_mvm_d3_iface_iterator, &resume_iter_data);
|
|
||||||
|
|
||||||
if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
|
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
vif = resume_iter_data.vif;
|
|
||||||
|
|
||||||
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
|
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
@@ -1741,7 +1749,9 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
|
|||||||
int remaining_time = 10;
|
int remaining_time = 10;
|
||||||
|
|
||||||
mvm->d3_test_active = false;
|
mvm->d3_test_active = false;
|
||||||
|
rtnl_lock();
|
||||||
__iwl_mvm_resume(mvm, true);
|
__iwl_mvm_resume(mvm, true);
|
||||||
|
rtnl_unlock();
|
||||||
iwl_abort_notification_waits(&mvm->notif_wait);
|
iwl_abort_notification_waits(&mvm->notif_wait);
|
||||||
ieee80211_restart_hw(mvm->hw);
|
ieee80211_restart_hw(mvm->hw);
|
||||||
|
|
||||||
|
@@ -121,78 +121,6 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
struct iwl_mvm *mvm = inode->i_private;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!mvm)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mutex_lock(&mvm->mutex);
|
|
||||||
if (!mvm->fw_error_dump) {
|
|
||||||
ret = -ENODATA;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
file->private_data = mvm->fw_error_dump;
|
|
||||||
mvm->fw_error_dump = NULL;
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
mutex_unlock(&mvm->mutex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
|
|
||||||
char __user *user_buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
|
|
||||||
ssize_t bytes_read = 0;
|
|
||||||
ssize_t bytes_read_trans = 0;
|
|
||||||
|
|
||||||
if (*ppos < dump_ptrs->op_mode_len)
|
|
||||||
bytes_read +=
|
|
||||||
simple_read_from_buffer(user_buf, count, ppos,
|
|
||||||
dump_ptrs->op_mode_ptr,
|
|
||||||
dump_ptrs->op_mode_len);
|
|
||||||
|
|
||||||
if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
|
|
||||||
return bytes_read;
|
|
||||||
|
|
||||||
if (dump_ptrs->trans_ptr) {
|
|
||||||
*ppos -= dump_ptrs->op_mode_len;
|
|
||||||
bytes_read_trans =
|
|
||||||
simple_read_from_buffer(user_buf + bytes_read,
|
|
||||||
count - bytes_read, ppos,
|
|
||||||
dump_ptrs->trans_ptr->data,
|
|
||||||
dump_ptrs->trans_ptr->len);
|
|
||||||
*ppos += dump_ptrs->op_mode_len;
|
|
||||||
|
|
||||||
if (bytes_read_trans >= 0)
|
|
||||||
bytes_read += bytes_read_trans;
|
|
||||||
else if (!bytes_read)
|
|
||||||
/* propagate the failure */
|
|
||||||
return bytes_read_trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes_read;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
|
|
||||||
struct file *file)
|
|
||||||
{
|
|
||||||
struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
|
|
||||||
|
|
||||||
vfree(dump_ptrs->op_mode_ptr);
|
|
||||||
vfree(dump_ptrs->trans_ptr);
|
|
||||||
kfree(dump_ptrs);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
|
static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
@@ -1250,6 +1178,126 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_NUM_ND_MATCHSETS 10
|
||||||
|
|
||||||
|
static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
const char *seps = ",\n";
|
||||||
|
char *buf_ptr = buf;
|
||||||
|
char *value_str = NULL;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
/* TODO: don't free if write is being called several times in one go */
|
||||||
|
if (mvm->nd_config) {
|
||||||
|
kfree(mvm->nd_config->match_sets);
|
||||||
|
kfree(mvm->nd_config);
|
||||||
|
mvm->nd_config = NULL;
|
||||||
|
kfree(mvm->nd_ies);
|
||||||
|
mvm->nd_ies = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL);
|
||||||
|
if (!mvm->nd_ies)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) +
|
||||||
|
(11 * sizeof(struct ieee80211_channel *)),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!mvm->nd_config) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
mvm->nd_config->n_channels = 11;
|
||||||
|
mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20;
|
||||||
|
mvm->nd_config->interval = 5;
|
||||||
|
mvm->nd_config->min_rssi_thold = -80;
|
||||||
|
for (i = 0; i < mvm->nd_config->n_channels; i++)
|
||||||
|
mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i];
|
||||||
|
|
||||||
|
mvm->nd_config->match_sets =
|
||||||
|
kcalloc(MAX_NUM_ND_MATCHSETS,
|
||||||
|
sizeof(*mvm->nd_config->match_sets),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!mvm->nd_config->match_sets) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((value_str = strsep(&buf_ptr, seps)) &&
|
||||||
|
strlen(value_str)) {
|
||||||
|
struct cfg80211_match_set *set;
|
||||||
|
|
||||||
|
if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets];
|
||||||
|
set->ssid.ssid_len = strlen(value_str);
|
||||||
|
|
||||||
|
if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len);
|
||||||
|
|
||||||
|
mvm->nd_config->n_match_sets++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = count;
|
||||||
|
|
||||||
|
if (mvm->nd_config->n_match_sets)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
if (mvm->nd_config)
|
||||||
|
kfree(mvm->nd_config->match_sets);
|
||||||
|
kfree(mvm->nd_config);
|
||||||
|
mvm->nd_config = NULL;
|
||||||
|
kfree(mvm->nd_ies);
|
||||||
|
mvm->nd_ies = NULL;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct iwl_mvm *mvm = file->private_data;
|
||||||
|
size_t bufsz, ret;
|
||||||
|
char *buf;
|
||||||
|
int i, n_match_sets, pos = 0;
|
||||||
|
|
||||||
|
n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0;
|
||||||
|
|
||||||
|
bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1;
|
||||||
|
buf = kzalloc(bufsz, GFP_KERNEL);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < n_match_sets; i++) {
|
||||||
|
if (pos +
|
||||||
|
mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid,
|
||||||
|
mvm->nd_config->match_sets[i].ssid.ssid_len);
|
||||||
|
pos += mvm->nd_config->match_sets[i].ssid.ssid_len;
|
||||||
|
buf[pos++] = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
|
||||||
|
out:
|
||||||
|
kfree(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PRINT_MVM_REF(ref) do { \
|
#define PRINT_MVM_REF(ref) do { \
|
||||||
@@ -1415,12 +1463,6 @@ 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(scan_ant_rxchain, 8);
|
||||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
|
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
|
||||||
|
|
||||||
static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
|
|
||||||
.open = iwl_dbgfs_fw_error_dump_open,
|
|
||||||
.read = iwl_dbgfs_fw_error_dump_read,
|
|
||||||
.release = iwl_dbgfs_fw_error_dump_release,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
|
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
|
||||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
|
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
|
||||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
|
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
|
||||||
@@ -1428,6 +1470,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
|
|||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
|
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
|
||||||
|
MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
||||||
@@ -1446,7 +1489,6 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||||||
S_IWUSR | S_IRUSR);
|
S_IWUSR | S_IRUSR);
|
||||||
MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
|
MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
|
||||||
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
|
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
|
||||||
MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
|
|
||||||
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
|
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
|
||||||
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
|
MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
|
||||||
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
|
MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
|
||||||
@@ -1487,6 +1529,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
|
|||||||
if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
|
if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
|
||||||
mvm->debugfs_dir, &mvm->d3_wake_sysassert))
|
mvm->debugfs_dir, &mvm->d3_wake_sysassert))
|
||||||
goto err;
|
goto err;
|
||||||
|
MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
|
if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
|
||||||
|
@@ -68,13 +68,46 @@
|
|||||||
|
|
||||||
/* Power Management Commands, Responses, Notifications */
|
/* Power Management Commands, Responses, Notifications */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum iwl_ltr_config_flags - masks for LTR config command flags
|
||||||
|
* @LTR_CFG_FLAG_FEATURE_ENABLE: Feature operational status
|
||||||
|
* @LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS: allow LTR change on shadow
|
||||||
|
* memory access
|
||||||
|
* @LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH: allow LTR msg send on ANY LTR
|
||||||
|
* reg change
|
||||||
|
* @LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3: allow LTR msg send on transition from
|
||||||
|
* D0 to D3
|
||||||
|
* @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register
|
||||||
|
* @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register
|
||||||
|
* @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD
|
||||||
|
*/
|
||||||
|
enum iwl_ltr_config_flags {
|
||||||
|
LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0),
|
||||||
|
LTR_CFG_FLAG_HW_DIS_ON_SHADOW_REG_ACCESS = BIT(1),
|
||||||
|
LTR_CFG_FLAG_HW_EN_SHRT_WR_THROUGH = BIT(2),
|
||||||
|
LTR_CFG_FLAG_HW_DIS_ON_D0_2_D3 = BIT(3),
|
||||||
|
LTR_CFG_FLAG_SW_SET_SHORT = BIT(4),
|
||||||
|
LTR_CFG_FLAG_SW_SET_LONG = BIT(5),
|
||||||
|
LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iwl_ltr_config_cmd - configures the LTR
|
||||||
|
* @flags: See %enum iwl_ltr_config_flags
|
||||||
|
*/
|
||||||
|
struct iwl_ltr_config_cmd {
|
||||||
|
__le32 flags;
|
||||||
|
__le32 static_long;
|
||||||
|
__le32 static_short;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* Radio LP RX Energy Threshold measured in dBm */
|
/* Radio LP RX Energy Threshold measured in dBm */
|
||||||
#define POWER_LPRX_RSSI_THRESHOLD 75
|
#define POWER_LPRX_RSSI_THRESHOLD 75
|
||||||
#define POWER_LPRX_RSSI_THRESHOLD_MAX 94
|
#define POWER_LPRX_RSSI_THRESHOLD_MAX 94
|
||||||
#define POWER_LPRX_RSSI_THRESHOLD_MIN 30
|
#define POWER_LPRX_RSSI_THRESHOLD_MIN 30
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum iwl_scan_flags - masks for power table command flags
|
* enum iwl_power_flags - masks for power table command flags
|
||||||
* @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
|
* @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
|
||||||
* receiver and transmitter. '0' - does not allow.
|
* receiver and transmitter. '0' - does not allow.
|
||||||
* @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
|
* @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
|
||||||
|
@@ -157,6 +157,7 @@ enum {
|
|||||||
/* Power - legacy power table command */
|
/* Power - legacy power table command */
|
||||||
POWER_TABLE_CMD = 0x77,
|
POWER_TABLE_CMD = 0x77,
|
||||||
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
|
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
|
||||||
|
LTR_CONFIG = 0xee,
|
||||||
|
|
||||||
/* Thermal Throttling*/
|
/* Thermal Throttling*/
|
||||||
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
|
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
|
||||||
|
@@ -480,6 +480,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||||||
/* Initialize tx backoffs to the minimal possible */
|
/* Initialize tx backoffs to the minimal possible */
|
||||||
iwl_mvm_tt_tx_backoff(mvm, 0);
|
iwl_mvm_tt_tx_backoff(mvm, 0);
|
||||||
|
|
||||||
|
if (mvm->trans->ltr_enabled) {
|
||||||
|
struct iwl_ltr_config_cmd cmd = {
|
||||||
|
.flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
|
||||||
|
};
|
||||||
|
|
||||||
|
WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
|
||||||
|
sizeof(cmd), &cmd));
|
||||||
|
}
|
||||||
|
|
||||||
ret = iwl_mvm_power_update_device(mvm);
|
ret = iwl_mvm_power_update_device(mvm);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto error;
|
goto error;
|
||||||
|
@@ -197,8 +197,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
|
|||||||
/*
|
/*
|
||||||
* Get the mask of the queues used by the vif
|
* Get the mask of the queues used by the vif
|
||||||
*/
|
*/
|
||||||
u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
|
u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
|
||||||
struct ieee80211_vif *vif)
|
|
||||||
{
|
{
|
||||||
u32 qmask = 0, ac;
|
u32 qmask = 0, ac;
|
||||||
|
|
||||||
@@ -227,7 +226,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the queues used by the vif */
|
/* Mark the queues used by the vif */
|
||||||
data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
|
data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
|
||||||
|
|
||||||
/* Mark MAC IDs as used by clearing the available bit, and
|
/* Mark MAC IDs as used by clearing the available bit, and
|
||||||
* (below) mark TSFs as used if their existing use is not
|
* (below) mark TSFs as used if their existing use is not
|
||||||
|
@@ -69,6 +69,7 @@
|
|||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/if_arp.h>
|
#include <linux/if_arp.h>
|
||||||
|
#include <linux/devcoredump.h>
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
#include <net/ieee80211_radiotap.h>
|
#include <net/ieee80211_radiotap.h>
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
@@ -526,7 +527,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
|
if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
|
||||||
!test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
|
!test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) &&
|
||||||
|
!test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
/* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
|
/* treat non-bufferable MMPDUs as broadcast if sta is sleeping */
|
||||||
@@ -678,10 +680,51 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
|
|||||||
memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
|
memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count,
|
||||||
|
const void *data, size_t datalen)
|
||||||
|
{
|
||||||
|
const struct iwl_mvm_dump_ptrs *dump_ptrs = data;
|
||||||
|
ssize_t bytes_read;
|
||||||
|
ssize_t bytes_read_trans;
|
||||||
|
|
||||||
|
if (offset < dump_ptrs->op_mode_len) {
|
||||||
|
bytes_read = min_t(ssize_t, count,
|
||||||
|
dump_ptrs->op_mode_len - offset);
|
||||||
|
memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset,
|
||||||
|
bytes_read);
|
||||||
|
offset += bytes_read;
|
||||||
|
count -= bytes_read;
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return bytes_read;
|
||||||
|
} else {
|
||||||
|
bytes_read = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dump_ptrs->trans_ptr)
|
||||||
|
return bytes_read;
|
||||||
|
|
||||||
|
offset -= dump_ptrs->op_mode_len;
|
||||||
|
bytes_read_trans = min_t(ssize_t, count,
|
||||||
|
dump_ptrs->trans_ptr->len - offset);
|
||||||
|
memcpy(buffer + bytes_read,
|
||||||
|
(u8 *)dump_ptrs->trans_ptr->data + offset,
|
||||||
|
bytes_read_trans);
|
||||||
|
|
||||||
|
return bytes_read + bytes_read_trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iwl_mvm_free_coredump(const void *data)
|
||||||
|
{
|
||||||
|
const struct iwl_mvm_dump_ptrs *fw_error_dump = data;
|
||||||
|
|
||||||
|
vfree(fw_error_dump->op_mode_ptr);
|
||||||
|
vfree(fw_error_dump->trans_ptr);
|
||||||
|
kfree(fw_error_dump);
|
||||||
|
}
|
||||||
|
|
||||||
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
||||||
{
|
{
|
||||||
static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
|
|
||||||
struct iwl_fw_error_dump_file *dump_file;
|
struct iwl_fw_error_dump_file *dump_file;
|
||||||
struct iwl_fw_error_dump_data *dump_data;
|
struct iwl_fw_error_dump_data *dump_data;
|
||||||
struct iwl_fw_error_dump_info *dump_info;
|
struct iwl_fw_error_dump_info *dump_info;
|
||||||
@@ -694,10 +737,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
|||||||
|
|
||||||
lockdep_assert_held(&mvm->mutex);
|
lockdep_assert_held(&mvm->mutex);
|
||||||
|
|
||||||
if (mvm->fw_error_dump)
|
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
|
||||||
return;
|
|
||||||
|
|
||||||
fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
|
|
||||||
if (!fw_error_dump)
|
if (!fw_error_dump)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -772,12 +812,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
|||||||
if (fw_error_dump->trans_ptr)
|
if (fw_error_dump->trans_ptr)
|
||||||
file_len += fw_error_dump->trans_ptr->len;
|
file_len += fw_error_dump->trans_ptr->len;
|
||||||
dump_file->file_len = cpu_to_le32(file_len);
|
dump_file->file_len = cpu_to_le32(file_len);
|
||||||
mvm->fw_error_dump = fw_error_dump;
|
|
||||||
|
|
||||||
/* notify the userspace about the error we had */
|
dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
|
||||||
kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
|
GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
||||||
{
|
{
|
||||||
@@ -1085,7 +1123,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|||||||
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
|
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
|
||||||
struct ieee80211_vif *vif)
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
|
u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
|
||||||
|
|
||||||
if (tfd_msk) {
|
if (tfd_msk) {
|
||||||
mutex_lock(&mvm->mutex);
|
mutex_lock(&mvm->mutex);
|
||||||
@@ -1381,6 +1419,9 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
|
|||||||
.cmd = cmd,
|
.cmd = cmd,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
|
||||||
|
return false;
|
||||||
|
|
||||||
memset(cmd, 0, sizeof(*cmd));
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
|
cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
|
||||||
cmd->max_macs = ARRAY_SIZE(cmd->macs);
|
cmd->max_macs = ARRAY_SIZE(cmd->macs);
|
||||||
@@ -1734,6 +1775,13 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
|
|||||||
if (changes & BSS_CHANGED_BEACON &&
|
if (changes & BSS_CHANGED_BEACON &&
|
||||||
iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
|
iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
|
||||||
IWL_WARN(mvm, "Failed updating beacon data\n");
|
IWL_WARN(mvm, "Failed updating beacon data\n");
|
||||||
|
|
||||||
|
if (changes & BSS_CHANGED_TXPOWER) {
|
||||||
|
IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
|
||||||
|
bss_conf->txpower);
|
||||||
|
iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
|
static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
|
||||||
@@ -2162,24 +2210,8 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
mvm->scan_status = IWL_MVM_SCAN_SCHED;
|
mvm->scan_status = IWL_MVM_SCAN_SCHED;
|
||||||
|
|
||||||
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
|
ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
|
||||||
ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
|
|
||||||
if (ret)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
|
|
||||||
ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
|
|
||||||
else
|
|
||||||
ret = iwl_mvm_sched_scan_start(mvm, req);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
goto out;
|
|
||||||
err:
|
|
||||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&mvm->mutex);
|
mutex_unlock(&mvm->mutex);
|
||||||
@@ -2367,14 +2399,19 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
|
|||||||
/* Set the node address */
|
/* Set the node address */
|
||||||
memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
|
memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
|
||||||
|
|
||||||
|
lockdep_assert_held(&mvm->mutex);
|
||||||
|
|
||||||
|
spin_lock_bh(&mvm->time_event_lock);
|
||||||
|
|
||||||
|
if (WARN_ON(te_data->id == HOT_SPOT_CMD)) {
|
||||||
|
spin_unlock_bh(&mvm->time_event_lock);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
te_data->vif = vif;
|
te_data->vif = vif;
|
||||||
te_data->duration = duration;
|
te_data->duration = duration;
|
||||||
te_data->id = HOT_SPOT_CMD;
|
te_data->id = HOT_SPOT_CMD;
|
||||||
|
|
||||||
lockdep_assert_held(&mvm->mutex);
|
|
||||||
|
|
||||||
spin_lock_bh(&mvm->time_event_lock);
|
|
||||||
list_add_tail(&te_data->list, &mvm->time_event_list);
|
|
||||||
spin_unlock_bh(&mvm->time_event_lock);
|
spin_unlock_bh(&mvm->time_event_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2430,22 +2467,23 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
|
|||||||
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
|
IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
|
||||||
duration, type);
|
duration, type);
|
||||||
|
|
||||||
|
mutex_lock(&mvm->mutex);
|
||||||
|
|
||||||
switch (vif->type) {
|
switch (vif->type) {
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
/* Use aux roc framework (HS20) */
|
/* Use aux roc framework (HS20) */
|
||||||
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
|
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
|
||||||
vif, duration);
|
vif, duration);
|
||||||
return ret;
|
goto out_unlock;
|
||||||
case NL80211_IFTYPE_P2P_DEVICE:
|
case NL80211_IFTYPE_P2P_DEVICE:
|
||||||
/* handle below */
|
/* handle below */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
|
IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&mvm->mutex);
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_PHY_CTX; i++) {
|
for (i = 0; i < NUM_PHY_CTX; i++) {
|
||||||
phy_ctxt = &mvm->phy_ctxts[i];
|
phy_ctxt = &mvm->phy_ctxts[i];
|
||||||
if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
|
if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt)
|
||||||
@@ -2996,18 +3034,24 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
|
|||||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||||
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
|
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!mvmsta))
|
if (WARN_ON_ONCE(!mvmsta)) {
|
||||||
goto done;
|
mutex_unlock(&mvm->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (drop) {
|
if (drop) {
|
||||||
if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
|
if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
|
||||||
IWL_ERR(mvm, "flush request fail\n");
|
IWL_ERR(mvm, "flush request fail\n");
|
||||||
} else {
|
|
||||||
iwl_trans_wait_tx_queue_empty(mvm->trans,
|
|
||||||
mvmsta->tfd_queue_msk);
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
mutex_unlock(&mvm->mutex);
|
mutex_unlock(&mvm->mutex);
|
||||||
|
} else {
|
||||||
|
u32 tfd_queue_msk = mvmsta->tfd_queue_msk;
|
||||||
|
mutex_unlock(&mvm->mutex);
|
||||||
|
|
||||||
|
/* this can take a while, and we may need/want other operations
|
||||||
|
* to succeed while doing this, so do it without the mutex held
|
||||||
|
*/
|
||||||
|
iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct ieee80211_ops iwl_mvm_hw_ops = {
|
const struct ieee80211_ops iwl_mvm_hw_ops = {
|
||||||
|
@@ -648,7 +648,6 @@ struct iwl_mvm {
|
|||||||
/* -1 for always, 0 for never, >0 for that many times */
|
/* -1 for always, 0 for never, >0 for that many times */
|
||||||
s8 restart_fw;
|
s8 restart_fw;
|
||||||
struct work_struct fw_error_dump_wk;
|
struct work_struct fw_error_dump_wk;
|
||||||
struct iwl_mvm_dump_ptrs *fw_error_dump;
|
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_LEDS
|
#ifdef CONFIG_IWLWIFI_LEDS
|
||||||
struct led_classdev led;
|
struct led_classdev led;
|
||||||
@@ -659,6 +658,10 @@ struct iwl_mvm {
|
|||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
struct wiphy_wowlan_support wowlan;
|
struct wiphy_wowlan_support wowlan;
|
||||||
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
|
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
|
||||||
|
|
||||||
|
/* sched scan settings for net detect */
|
||||||
|
struct cfg80211_sched_scan_request *nd_config;
|
||||||
|
struct ieee80211_scan_ies *nd_ies;
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||||
u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
|
u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
|
||||||
bool d3_test_active;
|
bool d3_test_active;
|
||||||
@@ -905,8 +908,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
|||||||
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||||
bool force_assoc_off, const u8 *bssid_override);
|
bool force_assoc_off, const u8 *bssid_override);
|
||||||
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||||
u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
|
u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);
|
||||||
struct ieee80211_vif *vif);
|
|
||||||
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
|
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
|
||||||
struct ieee80211_vif *vif);
|
struct ieee80211_vif *vif);
|
||||||
int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
|
int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
|
||||||
@@ -949,6 +951,10 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
|
|||||||
struct cfg80211_sched_scan_request *req);
|
struct cfg80211_sched_scan_request *req);
|
||||||
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
||||||
struct cfg80211_sched_scan_request *req);
|
struct cfg80211_sched_scan_request *req);
|
||||||
|
int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct cfg80211_sched_scan_request *req,
|
||||||
|
struct ieee80211_scan_ies *ies);
|
||||||
int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
|
int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
|
||||||
int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
|
int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
|
||||||
struct iwl_rx_cmd_buffer *rxb,
|
struct iwl_rx_cmd_buffer *rxb,
|
||||||
@@ -1206,11 +1212,9 @@ void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||||||
void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif);
|
struct ieee80211_vif *vif);
|
||||||
|
|
||||||
|
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
|
||||||
|
|
||||||
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
|
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
||||||
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
|
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
|
||||||
#else
|
|
||||||
static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __IWL_MVM_H__ */
|
#endif /* __IWL_MVM_H__ */
|
||||||
|
@@ -336,6 +336,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
|
|||||||
CMD(DTS_MEASUREMENT_NOTIFICATION),
|
CMD(DTS_MEASUREMENT_NOTIFICATION),
|
||||||
CMD(REPLY_THERMAL_MNG_BACKOFF),
|
CMD(REPLY_THERMAL_MNG_BACKOFF),
|
||||||
CMD(MAC_PM_POWER_TABLE),
|
CMD(MAC_PM_POWER_TABLE),
|
||||||
|
CMD(LTR_CONFIG),
|
||||||
CMD(BT_COEX_CI),
|
CMD(BT_COEX_CI),
|
||||||
CMD(BT_COEX_UPDATE_SW_BOOST),
|
CMD(BT_COEX_UPDATE_SW_BOOST),
|
||||||
CMD(BT_COEX_UPDATE_CORUN_LUT),
|
CMD(BT_COEX_UPDATE_CORUN_LUT),
|
||||||
@@ -402,6 +403,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||||||
if (cfg->max_rx_agg_size)
|
if (cfg->max_rx_agg_size)
|
||||||
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
|
hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
|
||||||
|
|
||||||
|
if (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;
|
op_mode->ops = &iwl_mvm_ops;
|
||||||
|
|
||||||
@@ -583,16 +587,18 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
|
|||||||
ieee80211_unregister_hw(mvm->hw);
|
ieee80211_unregister_hw(mvm->hw);
|
||||||
|
|
||||||
kfree(mvm->scan_cmd);
|
kfree(mvm->scan_cmd);
|
||||||
if (mvm->fw_error_dump) {
|
|
||||||
vfree(mvm->fw_error_dump->op_mode_ptr);
|
|
||||||
vfree(mvm->fw_error_dump->trans_ptr);
|
|
||||||
kfree(mvm->fw_error_dump);
|
|
||||||
}
|
|
||||||
kfree(mvm->mcast_filter_cmd);
|
kfree(mvm->mcast_filter_cmd);
|
||||||
mvm->mcast_filter_cmd = NULL;
|
mvm->mcast_filter_cmd = NULL;
|
||||||
|
|
||||||
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
|
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
|
||||||
kfree(mvm->d3_resume_sram);
|
kfree(mvm->d3_resume_sram);
|
||||||
|
if (mvm->nd_config) {
|
||||||
|
kfree(mvm->nd_config->match_sets);
|
||||||
|
kfree(mvm->nd_config);
|
||||||
|
mvm->nd_config = NULL;
|
||||||
|
kfree(mvm->nd_ies);
|
||||||
|
mvm->nd_ies = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
iwl_trans_op_mode_leave(mvm->trans);
|
iwl_trans_op_mode_leave(mvm->trans);
|
||||||
|
@@ -505,10 +505,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
|
|||||||
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, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
|
IWL_DEBUG_RATE(mvm,
|
||||||
|
"%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n",
|
||||||
prefix, rs_pretty_lq_type(rate->type),
|
prefix, rs_pretty_lq_type(rate->type),
|
||||||
rate->index, rs_pretty_ant(rate->ant),
|
rate->index, rs_pretty_ant(rate->ant),
|
||||||
rate->bw, rate->sgi, rate->ldpc);
|
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)
|
||||||
@@ -741,6 +742,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
|
|||||||
IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
|
IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_siso(rate) && rate->stbc) {
|
||||||
|
/* To enable STBC we need to set both a flag and ANT_AB */
|
||||||
|
ucode_rate |= RATE_MCS_ANT_AB_MSK;
|
||||||
|
ucode_rate |= RATE_MCS_VHT_STBC_MSK;
|
||||||
|
}
|
||||||
|
|
||||||
ucode_rate |= rate->bw;
|
ucode_rate |= rate->bw;
|
||||||
if (rate->sgi)
|
if (rate->sgi)
|
||||||
ucode_rate |= RATE_MCS_SGI_MSK;
|
ucode_rate |= RATE_MCS_SGI_MSK;
|
||||||
@@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
|
|||||||
rate->sgi = true;
|
rate->sgi = true;
|
||||||
if (ucode_rate & RATE_MCS_LDPC_MSK)
|
if (ucode_rate & RATE_MCS_LDPC_MSK)
|
||||||
rate->ldpc = true;
|
rate->ldpc = true;
|
||||||
|
if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
|
||||||
|
rate->stbc = true;
|
||||||
|
|
||||||
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
|
rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
|
||||||
|
|
||||||
@@ -794,7 +803,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
|
|||||||
|
|
||||||
if (nss == 1) {
|
if (nss == 1) {
|
||||||
rate->type = LQ_HT_SISO;
|
rate->type = LQ_HT_SISO;
|
||||||
WARN_ON_ONCE(num_of_ant != 1);
|
WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
|
||||||
} else if (nss == 2) {
|
} else if (nss == 2) {
|
||||||
rate->type = LQ_HT_MIMO2;
|
rate->type = LQ_HT_MIMO2;
|
||||||
WARN_ON_ONCE(num_of_ant != 2);
|
WARN_ON_ONCE(num_of_ant != 2);
|
||||||
@@ -992,7 +1001,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
|
|||||||
static inline bool rs_rate_match(struct rs_rate *a,
|
static inline bool rs_rate_match(struct rs_rate *a,
|
||||||
struct rs_rate *b)
|
struct rs_rate *b)
|
||||||
{
|
{
|
||||||
return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi);
|
bool ant_match;
|
||||||
|
|
||||||
|
if (a->stbc)
|
||||||
|
ant_match = (b->ant == ANT_A || b->ant == ANT_B);
|
||||||
|
else
|
||||||
|
ant_match = (a->ant == b->ant);
|
||||||
|
|
||||||
|
return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi)
|
||||||
|
&& ant_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
|
static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
|
||||||
@@ -1225,7 +1242,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||||||
IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
|
IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
|
||||||
done:
|
done:
|
||||||
/* See if there's a better rate or modulation mode to try. */
|
/* See if there's a better rate or modulation mode to try. */
|
||||||
if (sta && sta->supp_rates[info->band])
|
if (sta->supp_rates[info->band])
|
||||||
rs_rate_scale_perform(mvm, sta, lq_sta, tid);
|
rs_rate_scale_perform(mvm, sta, lq_sta, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
|
|||||||
else
|
else
|
||||||
rate->type = LQ_LEGACY_G;
|
rate->type = LQ_LEGACY_G;
|
||||||
|
|
||||||
|
rate->bw = RATE_MCS_CHAN_WIDTH_20;
|
||||||
|
rate->ldpc = false;
|
||||||
rate_mask = lq_sta->active_legacy_rate;
|
rate_mask = lq_sta->active_legacy_rate;
|
||||||
} else if (column->mode == RS_SISO) {
|
} else if (column->mode == RS_SISO) {
|
||||||
rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
|
rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
|
||||||
@@ -1634,8 +1653,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
|
|||||||
WARN_ON_ONCE("Bad column mode");
|
WARN_ON_ONCE("Bad column mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (column->mode != RS_LEGACY) {
|
||||||
rate->bw = rs_bw_from_sta_bw(sta);
|
rate->bw = rs_bw_from_sta_bw(sta);
|
||||||
rate->ldpc = lq_sta->ldpc;
|
rate->ldpc = lq_sta->ldpc;
|
||||||
|
}
|
||||||
|
|
||||||
search_tbl->column = col_id;
|
search_tbl->column = col_id;
|
||||||
rs_set_expected_tpt_table(lq_sta, search_tbl);
|
rs_set_expected_tpt_table(lq_sta, search_tbl);
|
||||||
|
|
||||||
@@ -1754,6 +1776,29 @@ out:
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||||
|
struct iwl_lq_sta *lq_sta)
|
||||||
|
{
|
||||||
|
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||||
|
struct ieee80211_vif *vif = mvmsta->vif;
|
||||||
|
bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
|
||||||
|
!vif->bss_conf.ps);
|
||||||
|
|
||||||
|
/* Our chip supports Tx STBC and the peer is an HT/VHT STA which
|
||||||
|
* supports STBC of at least 1*SS
|
||||||
|
*/
|
||||||
|
if (!lq_sta->stbc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mvm->ps_disabled && !sta_ps_disabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
|
static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
|
||||||
int *weaker, int *stronger)
|
int *weaker, int *stronger)
|
||||||
{
|
{
|
||||||
@@ -2675,6 +2720,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||||||
if (mvm->cfg->ht_params->ldpc &&
|
if (mvm->cfg->ht_params->ldpc &&
|
||||||
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
|
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
|
||||||
lq_sta->ldpc = true;
|
lq_sta->ldpc = true;
|
||||||
|
|
||||||
|
if (mvm->cfg->ht_params->stbc &&
|
||||||
|
(num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
|
||||||
|
(ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
|
||||||
|
lq_sta->stbc = true;
|
||||||
} else {
|
} else {
|
||||||
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
|
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
|
||||||
lq_sta->is_vht = true;
|
lq_sta->is_vht = true;
|
||||||
@@ -2682,8 +2732,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||||||
if (mvm->cfg->ht_params->ldpc &&
|
if (mvm->cfg->ht_params->ldpc &&
|
||||||
(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
|
(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
|
||||||
lq_sta->ldpc = true;
|
lq_sta->ldpc = true;
|
||||||
|
|
||||||
|
if (mvm->cfg->ht_params->stbc &&
|
||||||
|
(num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
|
||||||
|
(vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
|
||||||
|
lq_sta->stbc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IWL_MVM_RS_DISABLE_MIMO)
|
||||||
|
lq_sta->active_mimo2_rate = 0;
|
||||||
|
|
||||||
lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
|
lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
|
||||||
BITS_PER_LONG);
|
BITS_PER_LONG);
|
||||||
lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
|
lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
|
||||||
@@ -2692,11 +2750,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||||||
BITS_PER_LONG);
|
BITS_PER_LONG);
|
||||||
|
|
||||||
IWL_DEBUG_RATE(mvm,
|
IWL_DEBUG_RATE(mvm,
|
||||||
"RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
|
"RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
|
||||||
lq_sta->active_legacy_rate,
|
lq_sta->active_legacy_rate,
|
||||||
lq_sta->active_siso_rate,
|
lq_sta->active_siso_rate,
|
||||||
lq_sta->active_mimo2_rate,
|
lq_sta->active_mimo2_rate,
|
||||||
lq_sta->is_vht, lq_sta->ldpc);
|
lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
|
||||||
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
|
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
|
||||||
lq_sta->max_legacy_rate_idx,
|
lq_sta->max_legacy_rate_idx,
|
||||||
lq_sta->max_siso_rate_idx,
|
lq_sta->max_siso_rate_idx,
|
||||||
@@ -2820,6 +2878,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
|
|||||||
* rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
|
* rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
|
||||||
*/
|
*/
|
||||||
static void rs_build_rates_table(struct iwl_mvm *mvm,
|
static void rs_build_rates_table(struct iwl_mvm *mvm,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
struct iwl_lq_sta *lq_sta,
|
struct iwl_lq_sta *lq_sta,
|
||||||
const struct rs_rate *initial_rate)
|
const struct rs_rate *initial_rate)
|
||||||
{
|
{
|
||||||
@@ -2832,6 +2891,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
|
|||||||
memcpy(&rate, initial_rate, sizeof(rate));
|
memcpy(&rate, initial_rate, sizeof(rate));
|
||||||
|
|
||||||
valid_tx_ant = mvm->fw->valid_tx_ant;
|
valid_tx_ant = mvm->fw->valid_tx_ant;
|
||||||
|
rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
|
||||||
|
|
||||||
if (is_siso(&rate)) {
|
if (is_siso(&rate)) {
|
||||||
num_rates = RS_INITIAL_SISO_NUM_RATES;
|
num_rates = RS_INITIAL_SISO_NUM_RATES;
|
||||||
@@ -2903,7 +2963,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
|
|||||||
if (WARN_ON_ONCE(!sta || !initial_rate))
|
if (WARN_ON_ONCE(!sta || !initial_rate))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rs_build_rates_table(mvm, lq_sta, initial_rate);
|
rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
|
||||||
|
|
||||||
if (num_of_ant(initial_rate->ant) == 1)
|
if (num_of_ant(initial_rate->ant) == 1)
|
||||||
lq_cmd->single_stream_ant_msk = initial_rate->ant;
|
lq_cmd->single_stream_ant_msk = initial_rate->ant;
|
||||||
|
@@ -208,6 +208,7 @@ struct rs_rate {
|
|||||||
u32 bw;
|
u32 bw;
|
||||||
bool sgi;
|
bool sgi;
|
||||||
bool ldpc;
|
bool ldpc;
|
||||||
|
bool stbc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -331,6 +332,7 @@ struct iwl_lq_sta {
|
|||||||
u64 last_tx;
|
u64 last_tx;
|
||||||
bool is_vht;
|
bool is_vht;
|
||||||
bool ldpc; /* LDPC Rx is supported by the STA */
|
bool ldpc; /* LDPC Rx is supported by the STA */
|
||||||
|
bool stbc; /* Tx STBC is supported by chip and Rx by STA */
|
||||||
enum ieee80211_band band;
|
enum ieee80211_band band;
|
||||||
|
|
||||||
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
|
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
|
||||||
|
@@ -270,7 +270,8 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
|
|||||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||||
bool *global_bound = data;
|
bool *global_bound = data;
|
||||||
|
|
||||||
if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
|
if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
|
||||||
|
mvmvif->phy_ctxt->id < MAX_PHYS)
|
||||||
*global_bound = true;
|
*global_bound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,7 +460,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|||||||
basic_ssid ? 1 : 0);
|
basic_ssid ? 1 : 0);
|
||||||
|
|
||||||
cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
|
cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
|
||||||
TX_CMD_FLG_BT_DIS);
|
3 << TX_CMD_FLG_BT_PRIO_POS);
|
||||||
|
|
||||||
cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
|
cmd->tx_cmd.sta_id = mvm->aux_sta.sta_id;
|
||||||
cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
|
cmd->tx_cmd.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
|
||||||
cmd->tx_cmd.rate_n_flags =
|
cmd->tx_cmd.rate_n_flags =
|
||||||
@@ -671,6 +673,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
|||||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||||
ieee80211_scan_completed(mvm->hw,
|
ieee80211_scan_completed(mvm->hw,
|
||||||
status == IWL_SCAN_OFFLOAD_ABORTED);
|
status == IWL_SCAN_OFFLOAD_ABORTED);
|
||||||
|
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
mvm->last_ebs_successful = !ebs_status;
|
mvm->last_ebs_successful = !ebs_status;
|
||||||
@@ -1006,6 +1009,31 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
|||||||
sizeof(scan_req), &scan_req);
|
sizeof(scan_req), &scan_req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
|
||||||
|
struct ieee80211_vif *vif,
|
||||||
|
struct cfg80211_sched_scan_request *req,
|
||||||
|
struct ieee80211_scan_ies *ies)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
|
||||||
|
ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
|
||||||
|
} else {
|
||||||
|
ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = iwl_mvm_sched_scan_start(mvm, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
|
static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1080,8 +1108,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
|
|||||||
/*
|
/*
|
||||||
* Clear the scan status so the next scan requests will succeed. This
|
* Clear the scan status so the next scan requests will succeed. This
|
||||||
* also ensures the Rx handler doesn't do anything, as the scan was
|
* also ensures the Rx handler doesn't do anything, as the scan was
|
||||||
* stopped from above.
|
* stopped from above. Since the rx handler won't do anything now,
|
||||||
|
* we have to release the scan reference here.
|
||||||
*/
|
*/
|
||||||
|
if (mvm->scan_status == IWL_MVM_SCAN_OS)
|
||||||
|
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||||
|
|
||||||
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
|
@@ -609,7 +609,7 @@ int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||||||
|
|
||||||
lockdep_assert_held(&mvm->mutex);
|
lockdep_assert_held(&mvm->mutex);
|
||||||
|
|
||||||
qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
|
qmask = iwl_mvm_mac_get_queues_mask(vif);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The firmware defines the TFD queue mask to only be relevant
|
* The firmware defines the TFD queue mask to only be relevant
|
||||||
|
@@ -305,8 +305,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
|
|||||||
te_data->running = false;
|
te_data->running = false;
|
||||||
te_data->vif = NULL;
|
te_data->vif = NULL;
|
||||||
te_data->uid = 0;
|
te_data->uid = 0;
|
||||||
|
te_data->id = TE_MAX;
|
||||||
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
|
} else if (le32_to_cpu(notif->action) == TE_V2_NOTIF_HOST_EVENT_START) {
|
||||||
set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
|
|
||||||
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
|
set_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status);
|
||||||
te_data->running = true;
|
te_data->running = true;
|
||||||
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
|
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
|
||||||
|
@@ -64,10 +64,6 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#include "mvm.h"
|
#include "mvm.h"
|
||||||
#include "iwl-config.h"
|
|
||||||
#include "iwl-io.h"
|
|
||||||
#include "iwl-csr.h"
|
|
||||||
#include "iwl-prph.h"
|
|
||||||
|
|
||||||
#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
|
#define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ
|
||||||
|
|
||||||
|
@@ -175,14 +175,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* for data packets, rate info comes from the table inside the fw. This
|
* for data packets, rate info comes from the table inside the fw. This
|
||||||
* table is controlled by LINK_QUALITY commands. Exclude ctrl port
|
* table is controlled by LINK_QUALITY commands
|
||||||
* frames like EAPOLs which should be treated as mgmt frames. This
|
|
||||||
* avoids them being sent initially in high rates which increases the
|
|
||||||
* chances for completion of the 4-Way handshake.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ieee80211_is_data(fc) && sta &&
|
if (ieee80211_is_data(fc) && sta) {
|
||||||
!(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
|
|
||||||
tx_cmd->initial_rate_index = 0;
|
tx_cmd->initial_rate_index = 0;
|
||||||
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
|
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
|
||||||
return;
|
return;
|
||||||
@@ -193,8 +189,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
|
|||||||
|
|
||||||
/* HT rate doesn't make sense for a non data frame */
|
/* HT rate doesn't make sense for a non data frame */
|
||||||
WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
|
WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
|
||||||
"Got an HT rate for a non data frame 0x%x\n",
|
"Got an HT rate (flags:0x%x/mcs:%d) for a non data frame (fc:0x%x)\n",
|
||||||
info->control.rates[0].flags);
|
info->control.rates[0].flags,
|
||||||
|
info->control.rates[0].idx,
|
||||||
|
le16_to_cpu(fc));
|
||||||
|
|
||||||
rate_idx = info->control.rates[0].idx;
|
rate_idx = info->control.rates[0].idx;
|
||||||
/* if the rate isn't a well known legacy rate, take the lowest one */
|
/* if the rate isn't a well known legacy rate, take the lowest one */
|
||||||
|
@@ -734,3 +734,40 @@ bool iwl_mvm_is_idle(struct iwl_mvm *mvm)
|
|||||||
|
|
||||||
return idle;
|
return idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct iwl_bss_iter_data {
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
|
bool error;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac,
|
||||||
|
struct ieee80211_vif *vif)
|
||||||
|
{
|
||||||
|
struct iwl_bss_iter_data *data = _data;
|
||||||
|
|
||||||
|
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (data->vif) {
|
||||||
|
data->error = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->vif = vif;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
|
||||||
|
{
|
||||||
|
struct iwl_bss_iter_data bss_iter_data = {};
|
||||||
|
|
||||||
|
ieee80211_iterate_active_interfaces_atomic(
|
||||||
|
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||||
|
iwl_mvm_bss_iface_iterator, &bss_iter_data);
|
||||||
|
|
||||||
|
if (bss_iter_data.error) {
|
||||||
|
IWL_ERR(mvm, "More than one managed interface active!\n");
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bss_iter_data.vif;
|
||||||
|
}
|
||||||
|
@@ -133,7 +133,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!page)
|
if (WARN_ON_ONCE(!page))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
trans_pcie->fw_mon_page = page;
|
trans_pcie->fw_mon_page = page;
|
||||||
@@ -174,6 +174,7 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
|
|||||||
{
|
{
|
||||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||||
u16 lctl;
|
u16 lctl;
|
||||||
|
u16 cap;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HW bug W/A for instability in PCIe bus L0S->L1 transition.
|
* HW bug W/A for instability in PCIe bus L0S->L1 transition.
|
||||||
@@ -184,16 +185,17 @@ static void iwl_pcie_apm_config(struct iwl_trans *trans)
|
|||||||
* power savings, even without L1.
|
* power savings, even without L1.
|
||||||
*/
|
*/
|
||||||
pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl);
|
pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl);
|
||||||
if (lctl & PCI_EXP_LNKCTL_ASPM_L1) {
|
if (lctl & PCI_EXP_LNKCTL_ASPM_L1)
|
||||||
/* L1-ASPM enabled; disable(!) L0S */
|
|
||||||
iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||||
dev_info(trans->dev, "L1 Enabled; Disabling L0S\n");
|
else
|
||||||
} else {
|
|
||||||
/* L1-ASPM disabled; enable(!) L0S */
|
|
||||||
iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||||
dev_info(trans->dev, "L1 Disabled; Enabling L0S\n");
|
|
||||||
}
|
|
||||||
trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S);
|
trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S);
|
||||||
|
|
||||||
|
pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap);
|
||||||
|
trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN;
|
||||||
|
dev_info(trans->dev, "L1 %sabled - LTR %sabled\n",
|
||||||
|
(lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis",
|
||||||
|
trans->ltr_enabled ? "En" : "Dis");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -428,7 +430,7 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
|
|||||||
ret = iwl_poll_bit(trans, CSR_RESET,
|
ret = iwl_poll_bit(trans, CSR_RESET,
|
||||||
CSR_RESET_REG_FLAG_MASTER_DISABLED,
|
CSR_RESET_REG_FLAG_MASTER_DISABLED,
|
||||||
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
|
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
|
||||||
if (ret)
|
if (ret < 0)
|
||||||
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
|
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n");
|
||||||
|
|
||||||
IWL_DEBUG_INFO(trans, "stop master\n");
|
IWL_DEBUG_INFO(trans, "stop master\n");
|
||||||
@@ -544,7 +546,7 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
|
|||||||
msleep(25);
|
msleep(25);
|
||||||
}
|
}
|
||||||
|
|
||||||
IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter);
|
IWL_ERR(trans, "Couldn't prepare the card\n");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -744,15 +746,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
int first_ucode_section;
|
int first_ucode_section;
|
||||||
|
|
||||||
IWL_DEBUG_FW(trans,
|
|
||||||
"working with %s image\n",
|
|
||||||
image->is_secure ? "Secured" : "Non Secured");
|
|
||||||
IWL_DEBUG_FW(trans,
|
IWL_DEBUG_FW(trans,
|
||||||
"working with %s CPU\n",
|
"working with %s CPU\n",
|
||||||
image->is_dual_cpus ? "Dual" : "Single");
|
image->is_dual_cpus ? "Dual" : "Single");
|
||||||
|
|
||||||
/* configure the ucode to be ready to get the secured image */
|
/* configure the ucode to be ready to get the secured image */
|
||||||
if (image->is_secure) {
|
if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
|
||||||
/* set secure boot inspector addresses */
|
/* set secure boot inspector addresses */
|
||||||
iwl_write_prph(trans,
|
iwl_write_prph(trans,
|
||||||
LMPM_SECURE_INSPECTOR_CODE_ADDR,
|
LMPM_SECURE_INSPECTOR_CODE_ADDR,
|
||||||
@@ -788,7 +787,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
|||||||
LMPM_SECURE_CPU2_HDR_MEM_SPACE);
|
LMPM_SECURE_CPU2_HDR_MEM_SPACE);
|
||||||
|
|
||||||
/* load to FW the binary sections of CPU2 */
|
/* load to FW the binary sections of CPU2 */
|
||||||
if (image->is_secure)
|
if (iwl_has_secure_boot(trans->hw_rev,
|
||||||
|
trans->cfg->device_family))
|
||||||
ret = iwl_pcie_load_cpu_secured_sections(
|
ret = iwl_pcie_load_cpu_secured_sections(
|
||||||
trans, image, 2,
|
trans, image, 2,
|
||||||
&first_ucode_section);
|
&first_ucode_section);
|
||||||
@@ -819,7 +819,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
|||||||
else
|
else
|
||||||
iwl_write32(trans, CSR_RESET, 0);
|
iwl_write32(trans, CSR_RESET, 0);
|
||||||
|
|
||||||
if (image->is_secure) {
|
if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
|
||||||
/* wait for image verification to complete */
|
/* wait for image verification to complete */
|
||||||
ret = iwl_poll_prph_bit(trans,
|
ret = iwl_poll_prph_bit(trans,
|
||||||
LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
|
LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
|
||||||
@@ -1021,14 +1021,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
iwl_pcie_set_pwr(trans, false);
|
|
||||||
|
|
||||||
val = iwl_read32(trans, CSR_RESET);
|
|
||||||
if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
|
|
||||||
*status = IWL_D3_STATUS_RESET;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Also enables interrupts - none will happen as the device doesn't
|
* Also enables interrupts - none will happen as the device doesn't
|
||||||
* know we're waking it up, only when the opmode actually tells it
|
* know we're waking it up, only when the opmode actually tells it
|
||||||
@@ -1043,11 +1035,13 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
|||||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||||
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
|
||||||
25000);
|
25000);
|
||||||
if (ret) {
|
if (ret < 0) {
|
||||||
IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
|
IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iwl_pcie_set_pwr(trans, false);
|
||||||
|
|
||||||
iwl_trans_pcie_tx_reset(trans);
|
iwl_trans_pcie_tx_reset(trans);
|
||||||
|
|
||||||
ret = iwl_pcie_rx_init(trans);
|
ret = iwl_pcie_rx_init(trans);
|
||||||
@@ -1056,7 +1050,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val = iwl_read32(trans, CSR_RESET);
|
||||||
|
if (val & CSR_RESET_REG_FLAG_NEVO_RESET)
|
||||||
|
*status = IWL_D3_STATUS_RESET;
|
||||||
|
else
|
||||||
*status = IWL_D3_STATUS_ALIVE;
|
*status = IWL_D3_STATUS_ALIVE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1765,6 +1764,13 @@ err:
|
|||||||
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
|
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
||||||
|
struct dentry *dir)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /*CONFIG_IWLWIFI_DEBUGFS */
|
||||||
|
|
||||||
static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
|
static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
|
||||||
{
|
{
|
||||||
@@ -2043,13 +2049,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
|||||||
|
|
||||||
return dump_data;
|
return dump_data;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
|
|
||||||
struct dentry *dir)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /*CONFIG_IWLWIFI_DEBUGFS */
|
|
||||||
|
|
||||||
static const struct iwl_trans_ops trans_ops_pcie = {
|
static const struct iwl_trans_ops trans_ops_pcie = {
|
||||||
.start_hw = iwl_trans_pcie_start_hw,
|
.start_hw = iwl_trans_pcie_start_hw,
|
||||||
@@ -2086,9 +2085,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
|
|||||||
.release_nic_access = iwl_trans_pcie_release_nic_access,
|
.release_nic_access = iwl_trans_pcie_release_nic_access,
|
||||||
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
|
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
|
||||||
|
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
|
||||||
.dump_data = iwl_trans_pcie_dump_data,
|
.dump_data = iwl_trans_pcie_dump_data,
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
||||||
|
Reference in New Issue
Block a user