mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUUNpzAAoJEC0Llv5uNjIBnaAP+gJnot33UeAAy2fx1OaMucBQ 493ZGs3COPYD5n7qrrJxQIdkZoa2Jy2nI/rbXrOe/J3g36DBaaycXe0jcrFkB0bJ ae+8d494M/ektl0F3MKefwHDRz2FFUD03BmgsGXXI3sfwB63Vbjr8eKL/uPfYA+3 5TXUxQOo2Y0OwUOoogszgzlUff3tuchGVXOLxXNOSapPmcvTXL9xtUuH7WIR92qb Nho1PVirZhVQQ4JsRc/SljhmSny9BEEZ0PbLVlwQBW6AdgRiFTHIO6aeFfy8go2Q 849S/XvCQqnSfpfi9jQ1y9RAlsU8dSmPEmzuVpQja3IgklW1CXPkDU0BGZMuCm1B fK0kz79ykMvrPTTzCZkyB1Ulgg5CsZuntCUVlMM8aio0GevCNLSIQaniDg7/z37n HqegRGxHYmxnTqseBHopz+N6HgBrXLJ+xzq9CBGdAPA6ez/znNvjv5zuCbXxrIt2 fvhtwrL1FhfwruwRY5Gd7XocpdDDHY6enX9tnZY0PZbNhXEb/XnZDyVGDVD7Y0tC Cg+OYFXhJr+jc/b3ErtymN2jfh8ADansFi7lPn2FnxRC2kaC1hCjYTq2sr63as3E XCrVfvs59wgWuMh8ArAvSY39JXU+Hss0JLgrQlE8IDh2/wvcIv1+gJGG8oc+kMv6 TUk7pVMHC6fbNkWOyevL =GpBe -----END PGP SIGNATURE----- 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:
commit
47cb759ff7
@ -59,6 +59,7 @@ config IWLDVM
|
||||
|
||||
config IWLMVM
|
||||
tristate "Intel Wireless WiFi MVM Firmware support"
|
||||
select BACKPORT_WANT_DEV_COREDUMP
|
||||
help
|
||||
This is the driver that supports the MVM firmware which is
|
||||
currently only available for 7260 and 3160 devices.
|
||||
|
@ -418,8 +418,8 @@ 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)
|
||||
{
|
||||
return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
|
||||
BT_UART_MSG_FRAME3SCOESCO_POS;
|
||||
return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
|
||||
BT_UART_MSG_FRAME3SCOESCO_POS;
|
||||
}
|
||||
|
||||
static void iwlagn_bt_traffic_change_work(struct work_struct *work)
|
||||
|
@ -1095,6 +1095,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u32 queues, bool drop)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
u32 scd_queues;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* mac80211 will not push any more frames for transmit
|
||||
* until the flush is completed
|
||||
*/
|
||||
if (drop) {
|
||||
IWL_DEBUG_MAC80211(priv, "send flush command\n");
|
||||
if (iwlagn_txfifo_flush(priv, 0)) {
|
||||
IWL_ERR(priv, "flush request fail\n");
|
||||
goto done;
|
||||
}
|
||||
scd_queues = BIT(priv->cfg->base_params->num_of_queues) - 1;
|
||||
scd_queues &= ~(BIT(IWL_IPAN_CMD_QUEUE_NUM) |
|
||||
BIT(IWL_DEFAULT_CMD_QUEUE_NUM));
|
||||
|
||||
if (vif)
|
||||
scd_queues &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
|
||||
|
||||
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");
|
||||
goto done;
|
||||
}
|
||||
IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
|
||||
IWL_DEBUG_TX_QUEUES(priv, "wait transmit/flush all frames\n");
|
||||
iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff);
|
||||
done:
|
||||
mutex_unlock(&priv->mutex);
|
||||
|
@ -82,7 +82,8 @@
|
||||
#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */
|
||||
|
||||
#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 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 = {
|
||||
.stbc = true,
|
||||
.ldpc = true,
|
||||
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
|
||||
};
|
||||
|
@ -87,6 +87,16 @@ enum iwl_device_family {
|
||||
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
|
||||
* 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
|
||||
* @pwr_tx_backoffs: translation table between power limits and backoffs
|
||||
* @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.
|
||||
* API differences in uCode shouldn't be handled here but through TLVs
|
||||
@ -285,6 +296,7 @@ struct iwl_cfg {
|
||||
const char *default_nvm_file;
|
||||
unsigned int max_rx_agg_size;
|
||||
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,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_INIT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.img[IWL_UCODE_INIT].is_secure = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
|
||||
break;
|
||||
case IWL_UCODE_TLV_NUM_OF_CPU:
|
||||
if (tlv_len != sizeof(u32))
|
||||
|
@ -227,7 +227,6 @@ struct fw_desc {
|
||||
|
||||
struct fw_img {
|
||||
struct fw_desc sec[IWL_UCODE_SECTION_MAX];
|
||||
bool is_secure;
|
||||
bool is_dual_cpus;
|
||||
};
|
||||
|
||||
|
@ -535,9 +535,7 @@ struct iwl_trans_ops {
|
||||
void (*ref)(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);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -563,6 +561,7 @@ enum iwl_trans_state {
|
||||
* 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
|
||||
* @ltr_enabled: set to true if the LTR is enabled
|
||||
* @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
|
||||
* The user should use iwl_trans_{alloc,free}_tx_cmd.
|
||||
* @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;
|
||||
|
||||
bool pm_support;
|
||||
bool ltr_enabled;
|
||||
|
||||
/* The following fields are internal only */
|
||||
struct kmem_cache *dev_cmd_pool;
|
||||
@ -702,7 +702,6 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
|
||||
trans->ops->unref(trans);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
static inline struct iwl_trans_dump_data *
|
||||
iwl_trans_dump_data(struct iwl_trans *trans)
|
||||
{
|
||||
@ -710,7 +709,6 @@ iwl_trans_dump_data(struct iwl_trans *trans)
|
||||
return NULL;
|
||||
return trans->ops->dump_data(trans);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
|
||||
struct iwl_host_cmd *cmd)
|
||||
|
@ -72,8 +72,6 @@
|
||||
#include "mvm.h"
|
||||
#include "iwl-debug.h"
|
||||
|
||||
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
|
||||
|
||||
const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
|
||||
[BT_KILL_MSK_DEFAULT] = 0xfffffc00,
|
||||
[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 {
|
||||
u8 range;
|
||||
__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->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_rx_max_freq0 = cpu_to_le32(15);
|
||||
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,
|
||||
sizeof(iwl_bt_prio_boost));
|
||||
memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut,
|
||||
sizeof(iwl_bt_mprio_lut));
|
||||
bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
|
||||
bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
|
||||
|
||||
send_cmd:
|
||||
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
|
||||
|
||||
#define BT_ANTENNA_COUPLING_THRESHOLD (30)
|
||||
|
||||
static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
|
||||
{
|
||||
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 {
|
||||
u8 range;
|
||||
__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->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_tx_tx_delta_freq_thr = 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,
|
||||
sizeof(iwl_bt_prio_boost));
|
||||
memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
|
||||
sizeof(iwl_bt_mprio_lut));
|
||||
bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
|
||||
bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
|
||||
|
||||
send_cmd:
|
||||
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_CORUNNING 0
|
||||
#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_BCAST_FILTER_PASS_ALL 0
|
||||
#define IWL_MVM_QUOTA_THRESHOLD 8
|
||||
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
|
||||
#define IWL_MVM_RS_DISABLE_MIMO 0
|
||||
|
||||
#endif /* __MVM_CONSTANTS_H */
|
||||
|
@ -601,33 +601,6 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
|
||||
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,
|
||||
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");
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
|
||||
const struct iwl_wowlan_config_cmd_v3 *cmd)
|
||||
static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
|
||||
{
|
||||
/* 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_trans_stop_device(mvm->trans);
|
||||
@ -945,13 +782,109 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
mvm->ptk_ivlen = 0;
|
||||
mvm->ptk_icvlen = 0;
|
||||
|
||||
ret = iwl_mvm_load_d3_fw(mvm);
|
||||
if (ret)
|
||||
goto out;
|
||||
return iwl_mvm_load_d3_fw(mvm);
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
/*
|
||||
@ -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)
|
||||
goto out;
|
||||
|
||||
@ -1023,8 +956,93 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
goto out;
|
||||
|
||||
ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
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)
|
||||
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);
|
||||
if (ret)
|
||||
@ -1060,8 +1078,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
if (ret < 0)
|
||||
ieee80211_restart_hw(mvm->hw);
|
||||
out_noreset:
|
||||
kfree(key_data.rsc_tsc);
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
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)
|
||||
{
|
||||
struct iwl_d3_iter_data resume_iter_data = {
|
||||
.mvm = mvm,
|
||||
};
|
||||
struct ieee80211_vif *vif = NULL;
|
||||
int ret;
|
||||
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);
|
||||
|
||||
/* get the BSS vif pointer again */
|
||||
ieee80211_iterate_active_interfaces_atomic(
|
||||
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_d3_iface_iterator, &resume_iter_data);
|
||||
|
||||
if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
|
||||
vif = iwl_mvm_get_bss_vif(mvm);
|
||||
if (IS_ERR_OR_NULL(vif))
|
||||
goto out_unlock;
|
||||
|
||||
vif = resume_iter_data.vif;
|
||||
|
||||
ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
@ -1741,7 +1749,9 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
|
||||
int remaining_time = 10;
|
||||
|
||||
mvm->d3_test_active = false;
|
||||
rtnl_lock();
|
||||
__iwl_mvm_resume(mvm, true);
|
||||
rtnl_unlock();
|
||||
iwl_abort_notification_waits(&mvm->notif_wait);
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#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(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
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 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
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
|
||||
MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384);
|
||||
#endif
|
||||
|
||||
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);
|
||||
MVM_DEBUGFS_ADD_FILE(nic_temp, 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_cmd, dbgfs_dir, S_IRUSR);
|
||||
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,
|
||||
mvm->debugfs_dir, &mvm->d3_wake_sysassert))
|
||||
goto err;
|
||||
MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
|
||||
#endif
|
||||
|
||||
if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
|
||||
|
@ -68,13 +68,46 @@
|
||||
|
||||
/* 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 */
|
||||
#define POWER_LPRX_RSSI_THRESHOLD 75
|
||||
#define POWER_LPRX_RSSI_THRESHOLD_MAX 94
|
||||
#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
|
||||
* receiver and transmitter. '0' - does not allow.
|
||||
* @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
|
||||
|
@ -157,6 +157,7 @@ enum {
|
||||
/* Power - legacy power table command */
|
||||
POWER_TABLE_CMD = 0x77,
|
||||
PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78,
|
||||
LTR_CONFIG = 0xee,
|
||||
|
||||
/* Thermal Throttling*/
|
||||
REPLY_THERMAL_MNG_BACKOFF = 0x7e,
|
||||
|
@ -480,6 +480,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
||||
/* Initialize tx backoffs to the minimal possible */
|
||||
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);
|
||||
if (ret)
|
||||
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
|
||||
*/
|
||||
u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
|
||||
{
|
||||
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 */
|
||||
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
|
||||
* (below) mark TSFs as used if their existing use is not
|
||||
|
@ -69,6 +69,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/devcoredump.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ieee80211_radiotap.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 &&
|
||||
!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;
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
|
||||
struct iwl_fw_error_dump_file *dump_file;
|
||||
struct iwl_fw_error_dump_data *dump_data;
|
||||
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);
|
||||
|
||||
if (mvm->fw_error_dump)
|
||||
return;
|
||||
|
||||
fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
|
||||
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
|
||||
if (!fw_error_dump)
|
||||
return;
|
||||
|
||||
@ -772,12 +812,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
|
||||
if (fw_error_dump->trans_ptr)
|
||||
file_len += fw_error_dump->trans_ptr->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 */
|
||||
kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
|
||||
dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
|
||||
GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
|
||||
}
|
||||
#endif
|
||||
|
||||
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,
|
||||
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) {
|
||||
mutex_lock(&mvm->mutex);
|
||||
@ -1381,6 +1419,9 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
|
||||
.cmd = cmd,
|
||||
};
|
||||
|
||||
if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
|
||||
return false;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
|
||||
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 &&
|
||||
iwl_mvm_mac_ctxt_beacon_changed(mvm, vif))
|
||||
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,
|
||||
@ -2162,25 +2210,9 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
|
||||
|
||||
mvm->scan_status = IWL_MVM_SCAN_SCHED;
|
||||
|
||||
if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
|
||||
ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
|
||||
ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
|
||||
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:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return ret;
|
||||
@ -2367,14 +2399,19 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
|
||||
/* Set the node address */
|
||||
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->duration = duration;
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -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,
|
||||
duration, type);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
/* Use aux roc framework (HS20) */
|
||||
ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
|
||||
vif, duration);
|
||||
return ret;
|
||||
goto out_unlock;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
/* handle below */
|
||||
break;
|
||||
default:
|
||||
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++) {
|
||||
phy_ctxt = &mvm->phy_ctxts[i];
|
||||
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);
|
||||
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
|
||||
|
||||
if (WARN_ON_ONCE(!mvmsta))
|
||||
goto done;
|
||||
if (WARN_ON_ONCE(!mvmsta)) {
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (drop) {
|
||||
if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
|
||||
IWL_ERR(mvm, "flush request fail\n");
|
||||
mutex_unlock(&mvm->mutex);
|
||||
} else {
|
||||
iwl_trans_wait_tx_queue_empty(mvm->trans,
|
||||
mvmsta->tfd_queue_msk);
|
||||
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);
|
||||
}
|
||||
done:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
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 */
|
||||
s8 restart_fw;
|
||||
struct work_struct fw_error_dump_wk;
|
||||
struct iwl_mvm_dump_ptrs *fw_error_dump;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
struct led_classdev led;
|
||||
@ -659,6 +658,10 @@ struct iwl_mvm {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct wiphy_wowlan_support wowlan;
|
||||
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
|
||||
u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
|
||||
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,
|
||||
bool force_assoc_off, const u8 *bssid_override);
|
||||
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,
|
||||
struct ieee80211_vif *vif);
|
||||
u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);
|
||||
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif);
|
||||
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);
|
||||
int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
|
||||
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_rx_scan_offload_results(struct iwl_mvm *mvm,
|
||||
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,
|
||||
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);
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
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__ */
|
||||
|
@ -336,6 +336,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
|
||||
CMD(DTS_MEASUREMENT_NOTIFICATION),
|
||||
CMD(REPLY_THERMAL_MNG_BACKOFF),
|
||||
CMD(MAC_PM_POWER_TABLE),
|
||||
CMD(LTR_CONFIG),
|
||||
CMD(BT_COEX_CI),
|
||||
CMD(BT_COEX_UPDATE_SW_BOOST),
|
||||
CMD(BT_COEX_UPDATE_CORUN_LUT),
|
||||
@ -402,6 +403,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
if (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->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);
|
||||
|
||||
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);
|
||||
mvm->mcast_filter_cmd = NULL;
|
||||
|
||||
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
|
||||
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
|
||||
|
||||
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,
|
||||
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),
|
||||
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)
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (rate->sgi)
|
||||
ucode_rate |= RATE_MCS_SGI_MSK;
|
||||
@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
|
||||
rate->sgi = true;
|
||||
if (ucode_rate & RATE_MCS_LDPC_MSK)
|
||||
rate->ldpc = true;
|
||||
if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
|
||||
rate->stbc = true;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
rate->type = LQ_HT_MIMO2;
|
||||
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,
|
||||
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)
|
||||
@ -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);
|
||||
done:
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
|
||||
else
|
||||
rate->type = LQ_LEGACY_G;
|
||||
|
||||
rate->bw = RATE_MCS_CHAN_WIDTH_20;
|
||||
rate->ldpc = false;
|
||||
rate_mask = lq_sta->active_legacy_rate;
|
||||
} else if (column->mode == RS_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");
|
||||
}
|
||||
|
||||
rate->bw = rs_bw_from_sta_bw(sta);
|
||||
rate->ldpc = lq_sta->ldpc;
|
||||
if (column->mode != RS_LEGACY) {
|
||||
rate->bw = rs_bw_from_sta_bw(sta);
|
||||
rate->ldpc = lq_sta->ldpc;
|
||||
}
|
||||
|
||||
search_tbl->column = col_id;
|
||||
rs_set_expected_tpt_table(lq_sta, search_tbl);
|
||||
|
||||
@ -1754,6 +1776,29 @@ out:
|
||||
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,
|
||||
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 &&
|
||||
(ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
|
||||
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 {
|
||||
rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
|
||||
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 &&
|
||||
(vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
|
||||
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,
|
||||
BITS_PER_LONG);
|
||||
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);
|
||||
|
||||
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_siso_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",
|
||||
lq_sta->max_legacy_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
|
||||
*/
|
||||
static void rs_build_rates_table(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
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));
|
||||
|
||||
valid_tx_ant = mvm->fw->valid_tx_ant;
|
||||
rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
|
||||
|
||||
if (is_siso(&rate)) {
|
||||
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))
|
||||
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)
|
||||
lq_cmd->single_stream_ant_msk = initial_rate->ant;
|
||||
|
@ -208,6 +208,7 @@ struct rs_rate {
|
||||
u32 bw;
|
||||
bool sgi;
|
||||
bool ldpc;
|
||||
bool stbc;
|
||||
};
|
||||
|
||||
|
||||
@ -331,6 +332,7 @@ struct iwl_lq_sta {
|
||||
u64 last_tx;
|
||||
bool is_vht;
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -459,7 +460,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
||||
basic_ssid ? 1 : 0);
|
||||
|
||||
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.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
|
||||
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;
|
||||
ieee80211_scan_completed(mvm->hw,
|
||||
status == IWL_SCAN_OFFLOAD_ABORTED);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
* 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;
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
@ -305,8 +305,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm,
|
||||
te_data->running = false;
|
||||
te_data->vif = NULL;
|
||||
te_data->uid = 0;
|
||||
te_data->id = TE_MAX;
|
||||
} 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);
|
||||
te_data->running = true;
|
||||
ieee80211_ready_on_channel(mvm->hw); /* Start TE */
|
||||
|
@ -64,10 +64,6 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#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
|
||||
|
||||
|
@ -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
|
||||
* table is controlled by LINK_QUALITY commands. Exclude ctrl port
|
||||
* 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.
|
||||
* table is controlled by LINK_QUALITY commands
|
||||
*/
|
||||
|
||||
if (ieee80211_is_data(fc) && sta &&
|
||||
!(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) {
|
||||
if (ieee80211_is_data(fc) && sta) {
|
||||
tx_cmd->initial_rate_index = 0;
|
||||
tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
|
||||
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 */
|
||||
WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
|
||||
"Got an HT rate for a non data frame 0x%x\n",
|
||||
info->control.rates[0].flags);
|
||||
"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].idx,
|
||||
le16_to_cpu(fc));
|
||||
|
||||
rate_idx = info->control.rates[0].idx;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!page)
|
||||
if (WARN_ON_ONCE(!page))
|
||||
return;
|
||||
|
||||
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);
|
||||
u16 lctl;
|
||||
u16 cap;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl);
|
||||
if (lctl & PCI_EXP_LNKCTL_ASPM_L1) {
|
||||
/* L1-ASPM enabled; disable(!) L0S */
|
||||
if (lctl & PCI_EXP_LNKCTL_ASPM_L1)
|
||||
iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
|
||||
dev_info(trans->dev, "L1 Enabled; Disabling L0S\n");
|
||||
} else {
|
||||
/* L1-ASPM disabled; enable(!) L0S */
|
||||
else
|
||||
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);
|
||||
|
||||
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,
|
||||
CSR_RESET_REG_FLAG_MASTER_DISABLED,
|
||||
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
|
||||
if (ret)
|
||||
if (ret < 0)
|
||||
IWL_WARN(trans, "Master Disable Timed Out, 100 usec\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);
|
||||
}
|
||||
|
||||
IWL_DEBUG_INFO(trans, "got NIC after %d iterations\n", iter);
|
||||
IWL_ERR(trans, "Couldn't prepare the card\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -744,15 +746,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
||||
int ret = 0;
|
||||
int first_ucode_section;
|
||||
|
||||
IWL_DEBUG_FW(trans,
|
||||
"working with %s image\n",
|
||||
image->is_secure ? "Secured" : "Non Secured");
|
||||
IWL_DEBUG_FW(trans,
|
||||
"working with %s CPU\n",
|
||||
image->is_dual_cpus ? "Dual" : "Single");
|
||||
|
||||
/* 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 */
|
||||
iwl_write_prph(trans,
|
||||
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);
|
||||
|
||||
/* 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(
|
||||
trans, image, 2,
|
||||
&first_ucode_section);
|
||||
@ -819,7 +819,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
||||
else
|
||||
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 */
|
||||
ret = iwl_poll_prph_bit(trans,
|
||||
LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
|
||||
@ -1021,14 +1021,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
||||
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
|
||||
* 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,
|
||||
25000);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
IWL_ERR(trans, "Failed to resume the device (mac ready)\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
iwl_pcie_set_pwr(trans, false);
|
||||
|
||||
iwl_trans_pcie_tx_reset(trans);
|
||||
|
||||
ret = iwl_pcie_rx_init(trans);
|
||||
@ -1056,7 +1050,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
*status = IWL_D3_STATUS_ALIVE;
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1765,6 +1764,13 @@ err:
|
||||
IWL_ERR(trans, "failed to create the trans debugfs entry\n");
|
||||
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)
|
||||
{
|
||||
@ -2043,13 +2049,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
|
||||
|
||||
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 = {
|
||||
.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,
|
||||
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
.dump_data = iwl_trans_pcie_dump_data,
|
||||
#endif
|
||||
};
|
||||
|
||||
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
|
||||
|
Loading…
Reference in New Issue
Block a user