Commit d72c7282 authored by John W. Linville's avatar John W. Linville
parents 655d8e23 2d055afd
...@@ -73,6 +73,8 @@ ...@@ -73,6 +73,8 @@
/* AUX (TX during scan dwell) queue */ /* AUX (TX during scan dwell) queue */
#define IWL_AUX_QUEUE 10 #define IWL_AUX_QUEUE 10
#define IWL_INVALID_STATION 255
/* device operations */ /* device operations */
extern struct iwl_lib_ops iwl1000_lib; extern struct iwl_lib_ops iwl1000_lib;
extern struct iwl_lib_ops iwl2000_lib; extern struct iwl_lib_ops iwl2000_lib;
...@@ -176,7 +178,7 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr); ...@@ -176,7 +178,7 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);
/* lib */ /* lib */
int iwlagn_send_tx_power(struct iwl_priv *priv); int iwlagn_send_tx_power(struct iwl_priv *priv);
void iwlagn_temperature(struct iwl_priv *priv); void iwlagn_temperature(struct iwl_priv *priv);
int iwlagn_txfifo_flush(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk);
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv);
int iwlagn_send_beacon_cmd(struct iwl_priv *priv); int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
int iwl_send_statistics_request(struct iwl_priv *priv, int iwl_send_statistics_request(struct iwl_priv *priv,
...@@ -210,6 +212,8 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, ...@@ -210,6 +212,8 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u8 buf_size); struct ieee80211_sta *sta, u16 tid, u8 buf_size);
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid); struct ieee80211_sta *sta, u16 tid);
int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd); struct iwl_device_cmd *cmd);
......
...@@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, ...@@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
* 1. acquire mutex before calling * 1. acquire mutex before calling
* 2. make sure rf is on and not in exit state * 2. make sure rf is on and not in exit state
*/ */
int iwlagn_txfifo_flush(struct iwl_priv *priv) int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk)
{ {
struct iwl_txfifo_flush_cmd flush_cmd; struct iwl_txfifo_flush_cmd flush_cmd;
struct iwl_host_cmd cmd = { struct iwl_host_cmd cmd = {
...@@ -162,6 +162,9 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv) ...@@ -162,6 +162,9 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv)
if (priv->nvm_data->sku_cap_11n_enable) if (priv->nvm_data->sku_cap_11n_enable)
flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK; flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK;
if (scd_q_msk)
flush_cmd.queue_control = cpu_to_le32(scd_q_msk);
IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", IWL_DEBUG_INFO(priv, "queue control: 0x%x\n",
flush_cmd.queue_control); flush_cmd.queue_control);
flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL); flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL);
...@@ -173,7 +176,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) ...@@ -173,7 +176,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv)
{ {
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
ieee80211_stop_queues(priv->hw); ieee80211_stop_queues(priv->hw);
if (iwlagn_txfifo_flush(priv)) { if (iwlagn_txfifo_flush(priv, 0)) {
IWL_ERR(priv, "flush request fail\n"); IWL_ERR(priv, "flush request fail\n");
goto done; goto done;
} }
...@@ -1084,7 +1087,14 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) ...@@ -1084,7 +1087,14 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd; struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {}; struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
struct iwlagn_d3_config_cmd d3_cfg_cmd = {}; struct iwlagn_d3_config_cmd d3_cfg_cmd = {
/*
* 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 wowlan_key_data key_data = { struct wowlan_key_data key_data = {
.ctx = ctx, .ctx = ctx,
.bssid = ctx->active.bssid_addr, .bssid = ctx->active.bssid_addr,
......
...@@ -777,9 +777,12 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, ...@@ -777,9 +777,12 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
IWL_DEBUG_HT(priv, "start Tx\n"); IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
break; break;
case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
IWL_DEBUG_HT(priv, "Flush Tx\n");
ret = iwlagn_tx_agg_flush(priv, vif, sta, tid);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
IWL_DEBUG_HT(priv, "stop Tx\n"); IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
if ((ret == 0) && (priv->agg_tids_count > 0)) { if ((ret == 0) && (priv->agg_tids_count > 0)) {
...@@ -1122,7 +1125,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop) ...@@ -1122,7 +1125,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
*/ */
if (drop) { if (drop) {
IWL_DEBUG_MAC80211(priv, "send flush command\n"); IWL_DEBUG_MAC80211(priv, "send flush command\n");
if (iwlagn_txfifo_flush(priv)) { if (iwlagn_txfifo_flush(priv, 0)) {
IWL_ERR(priv, "flush request fail\n"); IWL_ERR(priv, "flush request fail\n");
goto done; goto done;
} }
......
...@@ -674,6 +674,51 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, ...@@ -674,6 +674,51 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
return ret; return ret;
} }
int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid)
{
struct iwl_tid_data *tid_data;
enum iwl_agg_state agg_state;
int sta_id, txq_id;
sta_id = iwl_sta_id(sta);
/*
* First set the agg state to OFF to avoid calling
* ieee80211_stop_tx_ba_cb in iwlagn_check_ratid_empty.
*/
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
txq_id = tid_data->agg.txq_id;
agg_state = tid_data->agg.state;
IWL_DEBUG_TX_QUEUES(priv, "Flush AGG: sta %d tid %d q %d state %d\n",
sta_id, tid, txq_id, tid_data->agg.state);
tid_data->agg.state = IWL_AGG_OFF;
spin_unlock_bh(&priv->sta_lock);
if (iwlagn_txfifo_flush(priv, BIT(txq_id)))
IWL_ERR(priv, "Couldn't flush the AGG queue\n");
if (test_bit(txq_id, priv->agg_q_alloc)) {
/*
* If the transport didn't know that we wanted to start
* agreggation, don't tell it that we want to stop them.
* This can happen when we don't get the addBA response on
* time, or we hadn't time to drain the AC queues.
*/
if (agg_state == IWL_AGG_ON)
iwl_trans_txq_disable(priv->trans, txq_id);
else
IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
agg_state);
iwlagn_dealloc_agg_txq(priv, txq_id);
}
return 0;
}
int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u8 buf_size) struct ieee80211_sta *sta, u16 tid, u8 buf_size)
{ {
......
...@@ -912,8 +912,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) ...@@ -912,8 +912,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
} }
} }
IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version);
/* /*
* In mvm uCode there is no difference between data and instructions * In mvm uCode there is no difference between data and instructions
* sections. * sections.
...@@ -970,6 +968,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) ...@@ -970,6 +968,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
else else
op = &iwlwifi_opmode_table[DVM_OP_MODE]; op = &iwlwifi_opmode_table[DVM_OP_MODE];
IWL_INFO(drv, "loaded firmware version %s op_mode %s\n",
drv->fw.fw_version, op->name);
/* add this device to the list of devices using this op_mode */ /* add this device to the list of devices using this op_mode */
list_add_tail(&drv->list, &op->drv); list_add_tail(&drv->list, &op->drv);
...@@ -997,8 +998,13 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) ...@@ -997,8 +998,13 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
* else from proceeding if the module fails to load * else from proceeding if the module fails to load
* or hangs loading. * or hangs loading.
*/ */
if (load_module) if (load_module) {
request_module("%s", op->name); err = request_module("%s", op->name);
if (err)
IWL_ERR(drv,
"failed to load module %s (error %d), is dynamic loading enabled?\n",
op->name, err);
}
return; return;
try_again: try_again:
......
...@@ -305,7 +305,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) ...@@ -305,7 +305,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
* currently supports * currently supports
*/ */
#define IWL_MAX_HW_QUEUES 32 #define IWL_MAX_HW_QUEUES 32
#define IWL_INVALID_STATION 255
#define IWL_MAX_TID_COUNT 8 #define IWL_MAX_TID_COUNT 8
#define IWL_FRAME_LIMIT 64 #define IWL_FRAME_LIMIT 64
...@@ -682,7 +681,7 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, ...@@ -682,7 +681,7 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
int fifo) int fifo)
{ {
iwl_trans_txq_enable(trans, queue, fifo, IWL_INVALID_STATION, iwl_trans_txq_enable(trans, queue, fifo, -1,
IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0);
} }
......
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
* *
*****************************************************************************/ *****************************************************************************/
#include <net/mac80211.h>
#include "fw-api-bt-coex.h" #include "fw-api-bt-coex.h"
#include "iwl-modparams.h" #include "iwl-modparams.h"
#include "mvm.h" #include "mvm.h"
...@@ -96,6 +98,20 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = { ...@@ -96,6 +98,20 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
#undef EVENT_PRIO_ANT #undef EVENT_PRIO_ANT
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
#define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3)
#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62)
#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65)
#define BT_REDUCED_TX_POWER_BIT BIT(7)
static inline bool is_loose_coex(void)
{
return iwlwifi_mod_params.ant_coupling >
IWL_BT_ANTENNA_COUPLING_THRESHOLD;
}
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
{ {
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC,
...@@ -186,11 +202,6 @@ static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = { ...@@ -186,11 +202,6 @@ static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = {
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
}; };
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
#define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3)
int iwl_send_bt_init_conf(struct iwl_mvm *mvm) int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
{ {
struct iwl_bt_coex_cmd cmd = { struct iwl_bt_coex_cmd cmd = {
...@@ -203,8 +214,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -203,8 +214,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
cmd.flags = iwlwifi_mod_params.bt_coex_active ? cmd.flags = iwlwifi_mod_params.bt_coex_active ?
BT_COEX_NW : BT_COEX_DISABLE; BT_COEX_NW : BT_COEX_DISABLE;
cmd.flags |= iwlwifi_mod_params.bt_ch_announce ? BT_CH_PRIMARY_EN : 0; cmd.flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE;
cmd.flags |= BT_SYNC_2_BT_DISABLE;
cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE | cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE |
BT_VALID_BT_PRIO_BOOST | BT_VALID_BT_PRIO_BOOST |
...@@ -215,7 +225,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -215,7 +225,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
BT_VALID_REDUCED_TX_POWER | BT_VALID_REDUCED_TX_POWER |
BT_VALID_LUT); BT_VALID_LUT);
if (iwlwifi_mod_params.ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) if (is_loose_coex())
memcpy(&cmd.decision_lut, iwl_loose_lookup, memcpy(&cmd.decision_lut, iwl_loose_lookup,
sizeof(iwl_tight_lookup)); sizeof(iwl_tight_lookup));
else else
...@@ -228,6 +238,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -228,6 +238,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
cmd.kill_cts_msk = cmd.kill_cts_msk =
cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]); cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
/* go to CALIB state in internal BT-Coex state machine */ /* go to CALIB state in internal BT-Coex state machine */
ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN, ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
...@@ -243,19 +255,101 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm) ...@@ -243,19 +255,101 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
sizeof(cmd), &cmd); sizeof(cmd), &cmd);
} }
struct iwl_bt_notif_iterator_data { static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
struct iwl_mvm *mvm; bool reduced_tx_power)
{
enum iwl_bt_kill_msk bt_kill_msk;
struct iwl_bt_coex_cmd cmd = {};
struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
lockdep_assert_held(&mvm->mutex);
if (reduced_tx_power) {
/* Reduced Tx power has precedence on the type of the profile */
bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
} else {
/* Low latency BT profile is active: give higher prio to BT */
if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
BT_MBOX_MSG(notif, 3, SNIFF_STATE))
bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
else
bt_kill_msk = BT_KILL_MSK_DEFAULT;
}
IWL_DEBUG_COEX(mvm,
"Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
bt_kill_msk,
BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
/* Don't send HCMD if there is no update */
if (bt_kill_msk == mvm->bt_kill_msk)
return 0;
mvm->bt_kill_msk = bt_kill_msk;
cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS);
IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk);
return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC,
sizeof(cmd), &cmd);
}
static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
bool enable)
{
struct iwl_bt_coex_cmd cmd = {
.valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER),
.bt_reduced_tx_power = sta_id,
};
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
/* This can happen if the station has been removed right now */
if (sta_id == IWL_MVM_STATION_COUNT)
return 0;
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
lockdep_is_held(&mvm->mutex));
mvmsta = (void *)sta->drv_priv;
/* nothing to do */
if (mvmsta->bt_reduced_txpower == enable)
return 0;
if (enable)
cmd.bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT;
IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
enable ? "en" : "dis", sta_id);
mvmsta->bt_reduced_txpower = enable;
/* Send ASYNC since this can be sent from an atomic context */
return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_ASYNC,
sizeof(cmd), &cmd);
}
struct iwl_bt_iterator_data {
struct iwl_bt_coex_profile_notif *notif; struct iwl_bt_coex_profile_notif *notif;
struct iwl_mvm *mvm;
u32 num_bss_ifaces;
bool reduced_tx_power;
}; };
static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_notif_iterator_data *data = _data; struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_smps_mode smps_mode; enum ieee80211_smps_mode smps_mode;
enum ieee80211_band band; enum ieee80211_band band;
int ave_rssi;
if (vif->type != NL80211_IFTYPE_STATION) if (vif->type != NL80211_IFTYPE_STATION)
return; return;
...@@ -268,11 +362,13 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -268,11 +362,13 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
band = -1; band = -1;
rcu_read_unlock(); rcu_read_unlock();
if (band != IEEE80211_BAND_2GHZ)
return;
smps_mode = IEEE80211_SMPS_AUTOMATIC; smps_mode = IEEE80211_SMPS_AUTOMATIC;
if (band != IEEE80211_BAND_2GHZ) {
ieee80211_request_smps(vif, smps_mode);
return;
}
if (data->notif->bt_status) if (data->notif->bt_status)
smps_mode = IEEE80211_SMPS_DYNAMIC; smps_mode = IEEE80211_SMPS_DYNAMIC;
...@@ -285,20 +381,88 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, ...@@ -285,20 +381,88 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
data->notif->bt_traffic_load, smps_mode); data->notif->bt_traffic_load, smps_mode);
ieee80211_request_smps(vif, smps_mode); ieee80211_request_smps(vif, smps_mode);
/* don't reduce the Tx power if in loose scheme */
if (is_loose_coex())
return;
data->num_bss_ifaces++;
/* reduced Txpower only if there are open BT connections, so ...*/
if (!BT_MBOX_MSG(data->notif, 3, OPEN_CON_2)) {
/* ... cancel reduced Tx power ... */
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
data->reduced_tx_power = false;
/* ... and there is no need to get reports on RSSI any more. */
ieee80211_disable_rssi_reports(vif);
return;
}
ave_rssi = ieee80211_ave_rssi(vif);
/* if the RSSI isn't valid, fake it is very low */
if (!ave_rssi)
ave_rssi = -100;
if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
/*
* bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
* BSS / P2P clients have rssi above threshold.
* We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
* the iteration, if one interface's rssi isn't good enough,
* bt_kill_msk will be set to default values.
*/
} else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) {
if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
/*
* One interface hasn't rssi above threshold, bt_kill_msk must
* be set to default values.
*/
data->reduced_tx_power = false;
}
/* Begin to monitor the RSSI: it may influence the reduced Tx power */
ieee80211_enable_rssi_reports(vif, BT_DISABLE_REDUCED_TXPOWER_THRESHOLD,
BT_ENABLE_REDUCED_TXPOWER_THRESHOLD);
}
static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
{
struct iwl_bt_iterator_data data = {
.mvm = mvm,
.notif = &mvm->last_bt_notif,
.reduced_tx_power = true,
};
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bt_notif_iterator, &data);
/*
* If there are no BSS / P2P client interfaces, reduced Tx Power is
* irrelevant since it is based on the RSSI coming from the beacon.
* Use BT_KILL_MSK_DEFAULT in that case.
*/
data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
} }
/* upon association, the fw will send in BT Coex notification */
int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *dev_cmd) struct iwl_device_cmd *dev_cmd)
{ {
struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
struct iwl_bt_notif_iterator_data data = {
.mvm = mvm,
.notif = notif,
};
struct iwl_bt_coex_cmd cmd = {};
enum iwl_bt_kill_msk bt_kill_msk;
IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not "); IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not ");
...@@ -311,38 +475,115 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, ...@@ -311,38 +475,115 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
/* remember this notification for future use: rssi fluctuations */ /* remember this notification for future use: rssi fluctuations */
memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
ieee80211_iterate_active_interfaces_atomic( iwl_mvm_bt_coex_notif_handle(mvm);
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bt_notif_iterator, &data); /*
* This is an async handler for a notification, returning anything other
* than 0 doesn't make sense even if HCMD failed.
*/
return 0;
}
static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvmsta;
if (vif->type != NL80211_IFTYPE_STATION ||
mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
return;
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
lockdep_is_held(&mvm->mutex));
mvmsta = (void *)sta->drv_priv;
/*
* This interface doesn't support reduced Tx power (because of low
* RSSI probably), then set bt_kill_msk to default values.
*/
if (!mvmsta->bt_reduced_txpower)
data->reduced_tx_power = false;
/* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
}
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event)
{
struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
struct iwl_bt_iterator_data data = {
.mvm = mvm,
.reduced_tx_power = true,
};
int ret;
mutex_lock(&mvm->mutex);
/* Rssi update while not associated ?! */
if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
goto out_unlock;
/* Low latency BT profile is active: give higher prio to BT */ /* No open connection - reports should be disabled */
if (BT_MBOX_MSG(notif, 3, SCO_STATE) || if (!BT_MBOX_MSG(&mvm->last_bt_notif, 3, OPEN_CON_2))
BT_MBOX_MSG(notif, 3, A2DP_STATE) || goto out_unlock;
BT_MBOX_MSG(notif, 3, SNIFF_STATE))
bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP; IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
/*
* Check if rssi is good enough for reduced Tx power, but not in loose
* scheme.
*/
if (rssi_event == RSSI_EVENT_LOW || is_loose_coex())
ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
false);
else else
bt_kill_msk = BT_KILL_MSK_DEFAULT; ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
/* Don't send HCMD if there is no update */ if (ret)
if (bt_kill_msk == mvm->bt_kill_msk) IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
return 0;
IWL_DEBUG_COEX(mvm, ieee80211_iterate_active_interfaces_atomic(
"Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n", mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
bt_kill_msk, iwl_mvm_bt_rssi_iterator, &data);
BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
mvm->bt_kill_msk = bt_kill_msk; /*
cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]); * If there are no BSS / P2P client interfaces, reduced Tx Power is
cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]); * irrelevant since it is based on the RSSI coming from the beacon.
* Use BT_KILL_MSK_DEFAULT in that case.
*/
data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS); if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
if (iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, sizeof(cmd), &cmd)) out_unlock:
IWL_ERR(mvm, "Failed to sent BT Coex CMD\n"); mutex_unlock(&mvm->mutex);
}
/* This handler is ASYNC */ void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return 0; {
struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_band band;
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
if (chanctx_conf && chanctx_conf->def.chan)
band = chanctx_conf->def.chan->band;
else
band = -1;
rcu_read_unlock();
/* if we are in 2GHz we will get a notification from the fw */
if (band == IEEE80211_BAND_2GHZ)
return;
/* else, we can remove all the constraints */
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
iwl_mvm_bt_coex_notif_handle(mvm);
} }
...@@ -769,7 +769,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ...@@ -769,7 +769,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
struct iwl_d3_manager_config d3_cfg_cmd = {}; struct iwl_d3_manager_config d3_cfg_cmd = {
/*
* 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 wowlan_key_data key_data = { struct wowlan_key_data key_data = {
.use_rsc_tsc = false, .use_rsc_tsc = false,
.tkip = &tkip_cmd, .tkip = &tkip_cmd,
......
...@@ -300,6 +300,67 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file, ...@@ -300,6 +300,67 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
return count; return count;
} }
static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->dbgfs_data;
u8 ap_sta_id;
struct ieee80211_chanctx_conf *chanctx_conf;
char buf[512];
int bufsz = sizeof(buf);
int pos = 0;
int i;
mutex_lock(&mvm->mutex);
ap_sta_id = mvmvif->ap_sta_id;
pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
mvmvif->id, mvmvif->color);
pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
vif->bss_conf.bssid);
pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) {
pos += scnprintf(buf+pos, bufsz-pos,
"\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
i, mvmvif->queue_params[i].txop,
mvmvif->queue_params[i].cw_min,
mvmvif->queue_params[i].cw_max,
mvmvif->queue_params[i].aifs,
mvmvif->queue_params[i].uapsd);
}
if (vif->type == NL80211_IFTYPE_STATION &&
ap_sta_id != IWL_MVM_STATION_COUNT) {
struct ieee80211_sta *sta;
struct iwl_mvm_sta *mvm_sta;
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
lockdep_is_held(&mvm->mutex));
mvm_sta = (void *)sta->drv_priv;
pos += scnprintf(buf+pos, bufsz-pos,
"ap_sta_id %d - reduced Tx power %d\n",
ap_sta_id, mvm_sta->bt_reduced_txpower);
}
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
if (chanctx_conf) {
pos += scnprintf(buf+pos, bufsz-pos,
"idle rx chains %d, active rx chains: %d\n",
chanctx_conf->rx_chains_static,
chanctx_conf->rx_chains_dynamic);
}
rcu_read_unlock();
mutex_unlock(&mvm->mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
#define BT_MBOX_MSG(_notif, _num, _field) \ #define BT_MBOX_MSG(_notif, _num, _field) \
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
>> BT_MBOX##_num##_##_field##_POS) >> BT_MBOX##_num##_##_field##_POS)
...@@ -464,6 +525,9 @@ MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); ...@@ -464,6 +525,9 @@ MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
/* Interface specific debugfs entries */
MVM_DEBUGFS_READ_FILE_OPS(mac_params);
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)
{ {
char buf[100]; char buf[100];
...@@ -494,3 +558,58 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) ...@@ -494,3 +558,58 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
IWL_ERR(mvm, "Can't create the mvm debugfs directory\n"); IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
return -ENOMEM; return -ENOMEM;
} }
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct dentry *dbgfs_dir = vif->debugfs_dir;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
char buf[100];
if (!dbgfs_dir)
return;
mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
mvmvif->dbgfs_data = mvm;
if (!mvmvif->dbgfs_dir) {
IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
dbgfs_dir->d_name.name);
return;
}
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
S_IRUSR);
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
* /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
* find
* netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
*/
snprintf(buf, 100, "../../../%s/%s/%s/%s",
dbgfs_dir->d_parent->d_parent->d_name.name,
dbgfs_dir->d_parent->d_name.name,
dbgfs_dir->d_name.name,
mvmvif->dbgfs_dir->d_name.name);
mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
mvm->debugfs_dir, buf);
if (!mvmvif->dbgfs_slink)
IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
dbgfs_dir->d_name.name);
return;
err:
IWL_ERR(mvm, "Can't create debugfs entity\n");
}
void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
debugfs_remove(mvmvif->dbgfs_slink);
mvmvif->dbgfs_slink = NULL;
debugfs_remove_recursive(mvmvif->dbgfs_dir);
mvmvif->dbgfs_dir = NULL;
}
...@@ -68,73 +68,53 @@ ...@@ -68,73 +68,53 @@
/** /**
* enum iwl_scan_flags - masks for power table command flags * enum iwl_scan_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, * @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
* '1' Driver enables PM (use rest of parameters) * '1' Driver enables PM (use rest of parameters)
* @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM, * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM,
* '1' PM could sleep over DTIM till listen Interval. * '1' PM could sleep over DTIM till listen Interval.
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
* @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all
* access categories are both delivery and trigger enabled.
* @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and
* PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask * @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
*/ */
enum iwl_power_flags { enum iwl_power_flags {
POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(0), POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
POWER_FLAGS_SLEEP_OVER_DTIM_MSK = BIT(1), POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1),
POWER_FLAGS_LPRX_ENA_MSK = BIT(2), POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2),
POWER_FLAGS_SNOOZE_ENA_MSK = BIT(3), POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9),
POWER_FLAGS_BT_SCO_ENA = BIT(4), POWER_FLAGS_LPRX_ENA_MSK = BIT(11),
POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(5)
}; };
#define IWL_POWER_VEC_SIZE 5
/** /**
* struct iwl_powertable_cmd - Power Table Command * struct iwl_powertable_cmd - Power Table Command
* POWER_TABLE_CMD = 0x77 (command, has simple generic response) * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
* *
* @id_and_color: MAC contex identifier
* @action: Action on context - no action, add new,
* modify existent, remove
* @flags: Power table command flags from POWER_FLAGS_* * @flags: Power table command flags from POWER_FLAGS_*
* @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec.
* Minimum allowed:- 3 * DTIM * Minimum allowed:- 3 * DTIM. Keep alive period must be
* set regardless of power scheme or current power state.
* FW use this value also when PM is disabled.
* @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to * @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to
* PSM transition - legacy PM * PSM transition - legacy PM
* @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to
* PSM transition - legacy PM * PSM transition - legacy PM
* @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to * @sleep_interval: not in use
* PSM transition - uAPSD * @keep_alive_beacons: not in use
* @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to
* PSM transition - uAPSD
* @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled.
* Default: 80dbm * Default: 80dbm
* @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set
* @snooze_interval: TBD
* @snooze_window: TBD
* @snooze_step: TBD
* @qndp_tid: TBD
* @uapsd_ac_flags: TBD
* @uapsd_max_sp: TBD
*/ */
struct iwl_powertable_cmd { struct iwl_powertable_cmd {
/* COMMON_INDEX_HDR_API_S_VER_1 */ /* PM_POWER_TABLE_CMD_API_S_VER_5 */
__le32 id_and_color;
__le32 action;
__le16 flags; __le16 flags;
u8 reserved; u8 keep_alive_seconds;
__le16 keep_alive_seconds; u8 debug_flags;
__le32 rx_data_timeout; __le32 rx_data_timeout;
__le32 tx_data_timeout; __le32 tx_data_timeout;
__le32 rx_data_timeout_uapsd; __le32 sleep_interval[IWL_POWER_VEC_SIZE];
__le32 tx_data_timeout_uapsd; __le32 keep_alive_beacons;
u8 lprx_rssi_threshold; __le32 lprx_rssi_threshold;
u8 num_skip_dtim;
__le16 snooze_interval;
__le16 snooze_window;
u8 snooze_step;
u8 qndp_tid;
u8 uapsd_ac_flags;
u8 uapsd_max_sp;
} __packed; } __packed;
#endif #endif
...@@ -480,15 +480,34 @@ enum { ...@@ -480,15 +480,34 @@ enum {
TE_DEP_TSF = 2, TE_DEP_TSF = 2,
TE_EVENT_SOCIOPATHIC = 4, TE_EVENT_SOCIOPATHIC = 4,
}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ }; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */
/*
/* When to send Time Event notifications and to whom (internal = FW) */ * Supported Time event notifications configuration.
* A notification (both event and fragment) includes a status indicating weather
* the FW was able to schedule the event or not. For fragment start/end
* notification the status is always success. There is no start/end fragment
* notification for monolithic events.
*
* @TE_NOTIF_NONE: no notifications
* @TE_NOTIF_HOST_EVENT_START: request/receive notification on event start
* @TE_NOTIF_HOST_EVENT_END:request/receive notification on event end
* @TE_NOTIF_INTERNAL_EVENT_START: internal FW use
* @TE_NOTIF_INTERNAL_EVENT_END: internal FW use.
* @TE_NOTIF_HOST_FRAG_START: request/receive notification on frag start
* @TE_NOTIF_HOST_FRAG_END:request/receive notification on frag end
* @TE_NOTIF_INTERNAL_FRAG_START: internal FW use.
* @TE_NOTIF_INTERNAL_FRAG_END: internal FW use.
*/
enum { enum {
TE_NOTIF_NONE = 0, TE_NOTIF_NONE = 0,
TE_NOTIF_HOST_START = 0x1, TE_NOTIF_HOST_EVENT_START = 0x1,
TE_NOTIF_HOST_END = 0x2, TE_NOTIF_HOST_EVENT_END = 0x2,
TE_NOTIF_INTERNAL_START = 0x4, TE_NOTIF_INTERNAL_EVENT_START = 0x4,
TE_NOTIF_INTERNAL_END = 0x8 TE_NOTIF_INTERNAL_EVENT_END = 0x8,
}; /* MAC_EVENT_ACTION_API_E_VER_1 */ TE_NOTIF_HOST_FRAG_START = 0x10,
TE_NOTIF_HOST_FRAG_END = 0x20,
TE_NOTIF_INTERNAL_FRAG_START = 0x40,
TE_NOTIF_INTERNAL_FRAG_END = 0x80
}; /* MAC_EVENT_ACTION_API_E_VER_2 */
/* /*
* @TE_FRAG_NONE: fragmentation of the time event is NOT allowed. * @TE_FRAG_NONE: fragmentation of the time event is NOT allowed.
......
...@@ -502,11 +502,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ...@@ -502,11 +502,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
/* /*
* TODO: remove this temporary code. * TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC. * Currently MVM FW supports power management only on single MAC.
* Iterate and disable PM on all active interfaces. * If new interface added, disable PM on existing interface.
* P2P device is a special case, since it is handled by FW similary to
* scan. If P2P deviced is added, PM remains enabled on existing
* interface.
* Note: the method below does not count the new interface being added * Note: the method below does not count the new interface being added
* at this moment. * at this moment.
*/ */
mvm->vif_count++; if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count++;
if (mvm->vif_count > 1) { if (mvm->vif_count > 1) {
IWL_DEBUG_MAC80211(mvm, IWL_DEBUG_MAC80211(mvm,
"Disable power on existing interfaces\n"); "Disable power on existing interfaces\n");
...@@ -562,6 +566,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ...@@ -562,6 +566,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
mvm->p2p_device_vif = vif; mvm->p2p_device_vif = vif;
} }
iwl_mvm_vif_dbgfs_register(mvm, vif);
goto out_unlock; goto out_unlock;
out_unbind: out_unbind:
...@@ -575,10 +580,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, ...@@ -575,10 +580,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
/* /*
* TODO: remove this temporary code. * TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC. * Currently MVM FW supports power management only on single MAC.
* Check if only one additional interface remains after rereasing * Check if only one additional interface remains after releasing
* current one. Update power mode on the remaining interface. * current one. Update power mode on the remaining interface.
*/ */
mvm->vif_count--; if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
mvm->vif_count); mvm->vif_count);
if (mvm->vif_count == 1) { if (mvm->vif_count == 1) {
...@@ -640,6 +646,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, ...@@ -640,6 +646,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
iwl_mvm_vif_dbgfs_clean(mvm, vif);
/* /*
* For AP/GO interface, the tear down of the resources allocated to the * For AP/GO interface, the tear down of the resources allocated to the
* interface is be handled as part of the stop_ap flow. * interface is be handled as part of the stop_ap flow.
...@@ -663,7 +671,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, ...@@ -663,7 +671,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
* Check if only one additional interface remains after removing * Check if only one additional interface remains after removing
* current one. Update power mode on the remaining interface. * current one. Update power mode on the remaining interface.
*/ */
if (mvm->vif_count) if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--; mvm->vif_count--;
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
mvm->vif_count); mvm->vif_count);
...@@ -713,6 +721,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, ...@@ -713,6 +721,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm, "failed to update quotas\n"); IWL_ERR(mvm, "failed to update quotas\n");
return; return;
} }
iwl_mvm_bt_coex_vif_assoc(mvm, vif);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/* remove AP station now that the MAC is unassoc */ /* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
...@@ -931,7 +940,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, ...@@ -931,7 +940,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
*/ */
break; break;
case STA_NOTIFY_AWAKE: case STA_NOTIFY_AWAKE:
if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION)) if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
break; break;
iwl_mvm_sta_modify_ps_wake(mvm, sta); iwl_mvm_sta_modify_ps_wake(mvm, sta);
break; break;
...@@ -1326,6 +1335,15 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw, ...@@ -1326,6 +1335,15 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif); return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
} }
static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
iwl_mvm_bt_rssi_event(mvm, vif, rssi_event);
}
struct ieee80211_ops iwl_mvm_hw_ops = { struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx, .tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action, .ampdu_action = iwl_mvm_mac_ampdu_action,
...@@ -1349,6 +1367,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = { ...@@ -1349,6 +1367,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.update_tkip_key = iwl_mvm_mac_update_tkip_key, .update_tkip_key = iwl_mvm_mac_update_tkip_key,
.remain_on_channel = iwl_mvm_roc, .remain_on_channel = iwl_mvm_roc,
.cancel_remain_on_channel = iwl_mvm_cancel_roc, .cancel_remain_on_channel = iwl_mvm_cancel_roc,
.rssi_callback = iwl_mvm_mac_rssi_callback,
.add_chanctx = iwl_mvm_add_chanctx, .add_chanctx = iwl_mvm_add_chanctx,
.remove_chanctx = iwl_mvm_remove_chanctx, .remove_chanctx = iwl_mvm_remove_chanctx,
......
...@@ -212,6 +212,7 @@ struct iwl_mvm_vif { ...@@ -212,6 +212,7 @@ struct iwl_mvm_vif {
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *dbgfs_dir; struct dentry *dbgfs_dir;
struct dentry *dbgfs_slink;
void *dbgfs_data; void *dbgfs_data;
#endif #endif
}; };
...@@ -321,6 +322,13 @@ struct iwl_mvm { ...@@ -321,6 +322,13 @@ struct iwl_mvm {
* can hold 16 keys at most. Reflect this fact. * can hold 16 keys at most. Reflect this fact.
*/ */
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
/*
* This counter of created interfaces is referenced only in conjunction
* with FW limitation related to power management. Currently PM is
* supported only on a single interface.
* IMPORTANT: this variable counts all interfaces except P2P device.
*/
u8 vif_count; u8 vif_count;
struct led_classdev led; struct led_classdev led;
...@@ -471,16 +479,22 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); ...@@ -471,16 +479,22 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
/* MVM debugfs */ /* MVM debugfs */
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
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);
int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif, void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
struct dentry *dbgfs_dir); void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_powertable_cmd *cmd);
#else #else
static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm,
struct dentry *dbgfs_dir) struct dentry *dbgfs_dir)
{ {
return 0; return 0;
} }
static inline void
iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
}
static inline void
iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
}
#endif /* CONFIG_IWLWIFI_DEBUGFS */ #endif /* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */ /* rate scaling */
...@@ -490,6 +504,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, ...@@ -490,6 +504,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
/* power managment */ /* power managment */
int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_powertable_cmd *cmd);
int iwl_mvm_leds_init(struct iwl_mvm *mvm); int iwl_mvm_leds_init(struct iwl_mvm *mvm);
void iwl_mvm_leds_exit(struct iwl_mvm *mvm); void iwl_mvm_leds_exit(struct iwl_mvm *mvm);
...@@ -513,5 +529,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm); ...@@ -513,5 +529,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd); struct iwl_device_cmd *cmd);
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event);
void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
#endif /* __IWL_MVM_H__ */ #endif /* __IWL_MVM_H__ */
...@@ -75,23 +75,49 @@ ...@@ -75,23 +75,49 @@
#define POWER_KEEP_ALIVE_PERIOD_SEC 25 #define POWER_KEEP_ALIVE_PERIOD_SEC 25
static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, static void iwl_mvm_power_log(struct iwl_mvm *mvm,
struct iwl_powertable_cmd *cmd) struct iwl_powertable_cmd *cmd)
{
IWL_DEBUG_POWER(mvm,
"Sending power table command for power level %d, flags = 0x%X\n",
iwlmvm_mod_params.power_scheme,
le16_to_cpu(cmd->flags));
IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds);
if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
le32_to_cpu(cmd->rx_data_timeout));
IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
le32_to_cpu(cmd->tx_data_timeout));
IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
cmd->lprx_rssi_threshold);
}
}
void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_powertable_cmd *cmd)
{ {
struct ieee80211_hw *hw = mvm->hw; struct ieee80211_hw *hw = mvm->hw;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
int dtimper, dtimper_msec; int dtimper, dtimper_msec;
int keep_alive; int keep_alive;
bool radar_detect = false; bool radar_detect = false;
cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, /*
mvmvif->color)); * Regardless of power management state the driver must set
cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); * keep alive period. FW will use it for sending keep alive NDPs
* immediately after association.
*/
cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC;
if ((iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) ||
!iwlwifi_mod_params.power_save)
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
if ((!vif->bss_conf.ps) || if (!vif->bss_conf.ps)
(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM))
return; return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
...@@ -110,26 +136,23 @@ static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -110,26 +136,23 @@ static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* Check skip over DTIM conditions */ /* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) && if (!radar_detect && (dtimper <= 10) &&
(iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) { (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP))
cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK); cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
cmd->num_skip_dtim = 2;
}
/* Check that keep alive period is at least 3 * DTIM */ /* Check that keep alive period is at least 3 * DTIM */
dtimper_msec = dtimper * vif->bss_conf.beacon_int; dtimper_msec = dtimper * vif->bss_conf.beacon_int;
keep_alive = max_t(int, 3 * dtimper_msec, keep_alive = max_t(int, 3 * dtimper_msec,
MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC); MSEC_PER_SEC * cmd->keep_alive_seconds);
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
cmd->keep_alive_seconds = keep_alive;
cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) { if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) {
/* TODO: Also for D3 (device sleep / WoWLAN) */ /* TODO: Also for D3 (device sleep / WoWLAN) */
cmd->rx_data_timeout = cpu_to_le32(10); cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC);
cmd->tx_data_timeout = cpu_to_le32(10); cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC);
} else { } else {
cmd->rx_data_timeout = cpu_to_le32(50); cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
cmd->tx_data_timeout = cpu_to_le32(50); cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
} }
} }
...@@ -137,36 +160,11 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -137,36 +160,11 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{ {
struct iwl_powertable_cmd cmd = {}; struct iwl_powertable_cmd cmd = {};
if (!iwlwifi_mod_params.power_save) {
IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
return 0;
}
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0; return 0;
iwl_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_build_cmd(mvm, vif, &cmd);
iwl_mvm_power_log(mvm, &cmd);
IWL_DEBUG_POWER(mvm,
"Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
cmd.id_and_color, iwlmvm_mod_params.power_scheme,
le16_to_cpu(cmd.flags));
if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",
le16_to_cpu(cmd.keep_alive_seconds));
IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
le32_to_cpu(cmd.rx_data_timeout));
IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
le32_to_cpu(cmd.tx_data_timeout));
IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",
le32_to_cpu(cmd.rx_data_timeout_uapsd));
IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
le32_to_cpu(cmd.tx_data_timeout_uapsd));
IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
cmd.lprx_rssi_threshold);
IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim);
}
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
sizeof(cmd), &cmd); sizeof(cmd), &cmd);
...@@ -175,33 +173,16 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -175,33 +173,16 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{ {
struct iwl_powertable_cmd cmd = {}; struct iwl_powertable_cmd cmd = {};
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (!iwlwifi_mod_params.power_save) {
IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
return 0;
}
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0; return 0;
cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, if ((iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) &&
mvmvif->color)); iwlwifi_mod_params.power_save)
cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
IWL_DEBUG_POWER(mvm, iwl_mvm_power_log(mvm, &cmd);
"Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
cmd.id_and_color, iwlmvm_mod_params.power_scheme,
le16_to_cpu(cmd.flags));
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
sizeof(cmd), &cmd); sizeof(cmd), &cmd);
} }
#ifdef CONFIG_IWLWIFI_DEBUGFS
void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_powertable_cmd *cmd)
{
iwl_power_build_cmd(mvm, vif, cmd);
}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
...@@ -793,7 +793,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, ...@@ -793,7 +793,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
if (num_of_ant(tbl->ant_type) > 1) if (num_of_ant(tbl->ant_type) > 1)
tbl->ant_type = tbl->ant_type =
first_antenna(mvm->nvm_data->valid_tx_ant); first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
tbl->is_ht40 = 0; tbl->is_ht40 = 0;
tbl->is_SGI = 0; tbl->is_SGI = 0;
...@@ -1235,7 +1235,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, ...@@ -1235,7 +1235,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
return -1; return -1;
/* Need both Tx chains/antennas to support MIMO */ /* Need both Tx chains/antennas to support MIMO */
if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2) if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
return -1; return -1;
IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n"); IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
...@@ -1287,7 +1287,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, ...@@ -1287,7 +1287,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm,
return -1; return -1;
/* Need both Tx chains/antennas to support MIMO */ /* Need both Tx chains/antennas to support MIMO */
if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3) if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 3)
return -1; return -1;
IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n"); IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n");
...@@ -1381,7 +1381,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm, ...@@ -1381,7 +1381,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) - u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action; u8 start_action;
u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant); u8 tx_chains_num = num_of_ant(valid_tx_ant);
int ret; int ret;
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
...@@ -1514,7 +1514,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, ...@@ -1514,7 +1514,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) - u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action; u8 start_action;
u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant); u8 tx_chains_num = num_of_ant(valid_tx_ant);
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
int ret; int ret;
...@@ -1649,7 +1649,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, ...@@ -1649,7 +1649,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) - u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action; u8 start_action;
u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant); u8 tx_chains_num = num_of_ant(valid_tx_ant);
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
int ret; int ret;
...@@ -1786,7 +1786,7 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, ...@@ -1786,7 +1786,7 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) - u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action; u8 start_action;
u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant; u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant); u8 tx_chains_num = num_of_ant(valid_tx_ant);
int ret; int ret;
u8 update_search_tbl_counter = 0; u8 update_search_tbl_counter = 0;
...@@ -2449,7 +2449,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, ...@@ -2449,7 +2449,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
i = lq_sta->last_txrate_idx; i = lq_sta->last_txrate_idx;
valid_tx_ant = mvm->nvm_data->valid_tx_ant; valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
if (!lq_sta->search_better_tbl) if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl; active_tbl = lq_sta->active_tbl;
...@@ -2639,15 +2639,15 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -2639,15 +2639,15 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */ /* These values will be overridden later */
lq_sta->lq.single_stream_ant_msk = lq_sta->lq.single_stream_ant_msk =
first_antenna(mvm->nvm_data->valid_tx_ant); first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
lq_sta->lq.dual_stream_ant_msk = lq_sta->lq.dual_stream_ant_msk =
mvm->nvm_data->valid_tx_ant & iwl_fw_valid_tx_ant(mvm->fw) &
~first_antenna(mvm->nvm_data->valid_tx_ant); ~first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
if (!lq_sta->lq.dual_stream_ant_msk) { if (!lq_sta->lq.dual_stream_ant_msk) {
lq_sta->lq.dual_stream_ant_msk = ANT_AB; lq_sta->lq.dual_stream_ant_msk = ANT_AB;
} else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) { } else if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) == 2) {
lq_sta->lq.dual_stream_ant_msk = lq_sta->lq.dual_stream_ant_msk =
mvm->nvm_data->valid_tx_ant; iwl_fw_valid_tx_ant(mvm->fw);
} }
/* as default allow aggregation for all tids */ /* as default allow aggregation for all tids */
...@@ -2708,7 +2708,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, ...@@ -2708,7 +2708,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
index++; index++;
repeat_rate--; repeat_rate--;
if (mvm) if (mvm)
valid_tx_ant = mvm->nvm_data->valid_tx_ant; valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
/* Fill rest of rate table */ /* Fill rest of rate table */
while (index < LINK_QUAL_MAX_RETRY_NUM) { while (index < LINK_QUAL_MAX_RETRY_NUM) {
...@@ -2813,7 +2813,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, ...@@ -2813,7 +2813,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
u8 ant_sel_tx; u8 ant_sel_tx;
mvm = lq_sta->drv; mvm = lq_sta->drv;
valid_tx_ant = mvm->nvm_data->valid_tx_ant; valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
if (lq_sta->dbg_fixed_rate) { if (lq_sta->dbg_fixed_rate) {
ant_sel_tx = ant_sel_tx =
((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
...@@ -2884,9 +2884,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, ...@@ -2884,9 +2884,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
desc += sprintf(buff+desc, "fixed rate 0x%X\n", desc += sprintf(buff+desc, "fixed rate 0x%X\n",
lq_sta->dbg_fixed_rate); lq_sta->dbg_fixed_rate);
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
(mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "", (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "",
(mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "", (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "",
(mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : ""); (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : "");
desc += sprintf(buff+desc, "lq type %s\n", desc += sprintf(buff+desc, "lq type %s\n",
(is_legacy(tbl->lq_type)) ? "legacy" : "HT"); (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
if (is_Ht(tbl->lq_type)) { if (is_Ht(tbl->lq_type)) {
......
...@@ -945,7 +945,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, ...@@ -945,7 +945,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
return mvmvif->ap_sta_id; return mvmvif->ap_sta_id;
return IWL_INVALID_STATION; return IWL_MVM_STATION_COUNT;
} }
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
...@@ -1093,7 +1093,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, ...@@ -1093,7 +1093,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
/* Get the station id from the mvm local station table */ /* Get the station id from the mvm local station table */
sta_id = iwl_mvm_get_key_sta_id(vif, sta); sta_id = iwl_mvm_get_key_sta_id(vif, sta);
if (sta_id == IWL_INVALID_STATION) { if (sta_id == IWL_MVM_STATION_COUNT) {
IWL_ERR(mvm, "Failed to find station id\n"); IWL_ERR(mvm, "Failed to find station id\n");
return -EINVAL; return -EINVAL;
} }
...@@ -1188,7 +1188,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, ...@@ -1188,7 +1188,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
return -ENOENT; return -ENOENT;
} }
if (sta_id == IWL_INVALID_STATION) { if (sta_id == IWL_MVM_STATION_COUNT) {
IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
return 0; return 0;
} }
...@@ -1254,7 +1254,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, ...@@ -1254,7 +1254,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_sta *mvm_sta;
u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
return; return;
rcu_read_lock(); rcu_read_lock();
......
...@@ -271,6 +271,7 @@ struct iwl_mvm_tid_data { ...@@ -271,6 +271,7 @@ struct iwl_mvm_tid_data {
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid. * tid.
* @max_agg_bufsize: the maximal size of the AGG buffer for this station * @max_agg_bufsize: the maximal size of the AGG buffer for this station
* @bt_reduced_txpower: is reduced tx power enabled for this station
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx * @lock: lock to protect the whole struct. Since %tid_data is access from Tx
* and from Tx response flow, it needs a spinlock. * and from Tx response flow, it needs a spinlock.
* @pending_frames: number of frames for this STA on the shared Tx queues. * @pending_frames: number of frames for this STA on the shared Tx queues.
...@@ -287,6 +288,7 @@ struct iwl_mvm_sta { ...@@ -287,6 +288,7 @@ struct iwl_mvm_sta {
u32 mac_id_n_color; u32 mac_id_n_color;
u16 tid_disable_agg; u16 tid_disable_agg;
u8 max_agg_bufsize; u8 max_agg_bufsize;
bool bt_reduced_txpower;
spinlock_t lock; spinlock_t lock;
atomic_t pending_frames; atomic_t pending_frames;
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
......
...@@ -166,7 +166,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, ...@@ -166,7 +166,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
WARN_ONCE(!le32_to_cpu(notif->status), WARN_ONCE(!le32_to_cpu(notif->status),
"Failed to schedule time event\n"); "Failed to schedule time event\n");
if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) { if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) {
IWL_DEBUG_TE(mvm, IWL_DEBUG_TE(mvm,
"TE ended - current time %lu, estimated end %lu\n", "TE ended - current time %lu, estimated end %lu\n",
jiffies, te_data->end_jiffies); jiffies, te_data->end_jiffies);
...@@ -189,7 +189,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, ...@@ -189,7 +189,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
} }
iwl_mvm_te_clear_data(mvm, te_data); iwl_mvm_te_clear_data(mvm, te_data);
} else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
te_data->running = true; te_data->running = true;
te_data->end_jiffies = jiffies + te_data->end_jiffies = jiffies +
TU_TO_JIFFIES(te_data->duration); TU_TO_JIFFIES(te_data->duration);
...@@ -368,7 +368,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, ...@@ -368,7 +368,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1)); time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1));
time_cmd.duration = cpu_to_le32(duration); time_cmd.duration = cpu_to_le32(duration);
time_cmd.repeat = cpu_to_le32(1); time_cmd.repeat = cpu_to_le32(1);
time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START |
TE_NOTIF_HOST_EVENT_END);
iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
} }
...@@ -485,7 +486,8 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -485,7 +486,8 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2)); time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
time_cmd.repeat = cpu_to_le32(1); time_cmd.repeat = cpu_to_le32(1);
time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START |
TE_NOTIF_HOST_EVENT_END);
return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
} }
......
...@@ -205,7 +205,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, ...@@ -205,7 +205,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx); rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
mvm->mgmt_last_antenna_idx = mvm->mgmt_last_antenna_idx =
iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant, iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
mvm->mgmt_last_antenna_idx); mvm->mgmt_last_antenna_idx);
rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
...@@ -365,7 +365,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, ...@@ -365,7 +365,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
if (WARN_ON_ONCE(!mvmsta)) if (WARN_ON_ONCE(!mvmsta))
return -1; return -1;
if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION)) if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
return -1; return -1;
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id);
...@@ -641,10 +641,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, ...@@ -641,10 +641,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
} }
IWL_DEBUG_TX_REPLY(mvm, IWL_DEBUG_TX_REPLY(mvm,
"TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x " "TXQ %d status %s (0x%08x)\n",
"retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n", txq_id, iwl_mvm_get_tx_fail_reason(status), status);
txq_id, iwl_mvm_get_tx_fail_reason(status),
status, le32_to_cpu(tx_resp->initial_rate), IWL_DEBUG_TX_REPLY(mvm,
"\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n",
le32_to_cpu(tx_resp->initial_rate),
tx_resp->failure_frame, SEQ_TO_INDEX(sequence), tx_resp->failure_frame, SEQ_TO_INDEX(sequence),
ssn, next_reclaimed, seq_ctl); ssn, next_reclaimed, seq_ctl);
......
...@@ -462,7 +462,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, ...@@ -462,7 +462,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
.data = { lq, }, .data = { lq, },
}; };
if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT))
return -EINVAL; return -EINVAL;
if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
......
...@@ -241,6 +241,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { ...@@ -241,6 +241,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
{IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
{IWL_PCI_DEVICE(0x088F, 0x5260, iwl6035_2agn_cfg)},
/* 105 Series */ /* 105 Series */
{IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
......
...@@ -1063,7 +1063,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, ...@@ -1063,7 +1063,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
/* If this queue is mapped to a certain station: it is an AGG queue */ /* If this queue is mapped to a certain station: it is an AGG queue */
if (sta_id != IWL_INVALID_STATION) { if (sta_id >= 0) {
u16 ra_tid = BUILD_RAxTID(sta_id, tid); u16 ra_tid = BUILD_RAxTID(sta_id, tid);
/* Map receiver-address / traffic-ID to this queue */ /* Map receiver-address / traffic-ID to this queue */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment