summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-rxon.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c235
1 files changed, 204 insertions, 31 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 09f679d6046f..d42ef1763a71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -30,6 +30,7 @@
#include "iwl-core.h"
#include "iwl-agn-calib.h"
#include "iwl-helpers.h"
+#include "iwl-trans.h"
static int iwlagn_disable_bss(struct iwl_priv *priv,
struct iwl_rxon_context *ctx,
@@ -39,7 +40,8 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
int ret;
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+ ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd,
+ CMD_SYNC, sizeof(*send), send);
send->filter_flags = old_filter;
@@ -64,7 +66,8 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
send->dev_type = RXON_DEV_TYPE_P2P;
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+ ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd,
+ CMD_SYNC, sizeof(*send), send);
send->filter_flags = old_filter;
send->dev_type = old_dev_type;
@@ -81,6 +84,22 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
return ret;
}
+static int iwlagn_disconn_pan(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct iwl_rxon_cmd *send)
+{
+ __le32 old_filter = send->filter_flags;
+ int ret;
+
+ send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, CMD_SYNC,
+ sizeof(*send), send);
+
+ send->filter_flags = old_filter;
+
+ return ret;
+}
+
static void iwlagn_update_qos(struct iwl_priv *priv,
struct iwl_rxon_context *ctx)
{
@@ -102,7 +121,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
ctx->qos_data.qos_active,
ctx->qos_data.def_qos_parm.qos_flags);
- ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd,
+ ret = trans_send_cmd_pdu(&priv->trans, ctx->qos_cmd, CMD_SYNC,
sizeof(struct iwl_qosparam_cmd),
&ctx->qos_data.def_qos_parm);
if (ret)
@@ -161,11 +180,8 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
ctx->staging.ofdm_ht_triple_stream_basic_rates;
rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
- ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
- sizeof(rxon_assoc), &rxon_assoc, NULL);
- if (ret)
- return ret;
-
+ ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_assoc_cmd,
+ CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc);
return ret;
}
@@ -175,10 +191,21 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv,
int ret;
struct iwl_rxon_cmd *active = (void *)&ctx->active;
- if (ctx->ctxid == IWL_RXON_CTX_BSS)
+ if (ctx->ctxid == IWL_RXON_CTX_BSS) {
ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
- else
+ } else {
ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+ if (ret)
+ return ret;
+ if (ctx->vif) {
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+ return ret;
+ }
+ ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
+ }
+ }
if (ret)
return ret;
@@ -187,6 +214,8 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv,
* keys, so we have to restore those afterwards.
*/
iwl_clear_ucode_stations(priv, ctx);
+ /* update -- might need P2P now */
+ iwl_update_bcast_station(priv, ctx);
iwl_restore_stations(priv, ctx);
ret = iwl_restore_default_wep_keys(priv, ctx);
if (ret) {
@@ -205,10 +234,12 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
struct iwl_rxon_cmd *active = (void *)&ctx->active;
/* RXON timing must be before associated RXON */
- ret = iwl_send_rxon_timing(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
- return ret;
+ if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+ return ret;
+ }
}
/* QoS info may be cleared by previous un-assoc RXON */
iwlagn_update_qos(priv, ctx);
@@ -235,7 +266,7 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
* Associated RXON doesn't clear the station table in uCode,
* so we don't need to restore stations etc. after this.
*/
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, CMD_SYNC,
sizeof(struct iwl_rxon_cmd), &ctx->staging);
if (ret) {
IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
@@ -263,9 +294,107 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
return ret;
}
+
+ if ((ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) &&
+ priv->cfg->ht_params->smps_mode)
+ ieee80211_request_smps(ctx->vif,
+ priv->cfg->ht_params->smps_mode);
+
return 0;
}
+int iwlagn_set_pan_params(struct iwl_priv *priv)
+{
+ struct iwl_wipan_params_cmd cmd;
+ struct iwl_rxon_context *ctx_bss, *ctx_pan;
+ int slot0 = 300, slot1 = 0;
+ int ret;
+
+ if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS))
+ return 0;
+
+ BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+ lockdep_assert_held(&priv->mutex);
+
+ ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS];
+ ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN];
+
+ /*
+ * If the PAN context is inactive, then we don't need
+ * to update the PAN parameters, the last thing we'll
+ * have done before it goes inactive is making the PAN
+ * parameters be WLAN-only.
+ */
+ if (!ctx_pan->is_active)
+ return 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ /* only 2 slots are currently allowed */
+ cmd.num_slots = 2;
+
+ cmd.slots[0].type = 0; /* BSS */
+ cmd.slots[1].type = 1; /* PAN */
+
+ if (priv->hw_roc_channel) {
+ /* both contexts must be used for this to happen */
+ slot1 = priv->hw_roc_duration;
+ slot0 = IWL_MIN_SLOT_TIME;
+ } else if (ctx_bss->vif && ctx_pan->vif) {
+ int bcnint = ctx_pan->beacon_int;
+ int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1;
+
+ /* should be set, but seems unused?? */
+ cmd.flags |= cpu_to_le16(IWL_WIPAN_PARAMS_FLG_SLOTTED_MODE);
+
+ if (ctx_pan->vif->type == NL80211_IFTYPE_AP &&
+ bcnint &&
+ bcnint != ctx_bss->beacon_int) {
+ IWL_ERR(priv,
+ "beacon intervals don't match (%d, %d)\n",
+ ctx_bss->beacon_int, ctx_pan->beacon_int);
+ } else
+ bcnint = max_t(int, bcnint,
+ ctx_bss->beacon_int);
+ if (!bcnint)
+ bcnint = DEFAULT_BEACON_INTERVAL;
+ slot0 = bcnint / 2;
+ slot1 = bcnint - slot0;
+
+ if (test_bit(STATUS_SCAN_HW, &priv->status) ||
+ (!ctx_bss->vif->bss_conf.idle &&
+ !ctx_bss->vif->bss_conf.assoc)) {
+ slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
+ slot1 = IWL_MIN_SLOT_TIME;
+ } else if (!ctx_pan->vif->bss_conf.idle &&
+ !ctx_pan->vif->bss_conf.assoc) {
+ slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME;
+ slot0 = IWL_MIN_SLOT_TIME;
+ }
+ } else if (ctx_pan->vif) {
+ slot0 = 0;
+ slot1 = max_t(int, 1, ctx_pan->vif->bss_conf.dtim_period) *
+ ctx_pan->beacon_int;
+ slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1);
+
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME;
+ slot1 = IWL_MIN_SLOT_TIME;
+ }
+ }
+
+ cmd.slots[0].width = cpu_to_le16(slot0);
+ cmd.slots[1].width = cpu_to_le16(slot1);
+
+ ret = trans_send_cmd_pdu(&priv->trans, REPLY_WIPAN_PARAMS, CMD_SYNC,
+ sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret);
+
+ return ret;
+}
+
/**
* iwlagn_commit_rxon - commit staging_rxon to hardware
*
@@ -308,8 +437,8 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
/* always get timestamp with Rx frame */
ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK;
- if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->_agn.hw_roc_channel) {
- struct ieee80211_channel *chan = priv->_agn.hw_roc_channel;
+ if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->hw_roc_channel) {
+ struct ieee80211_channel *chan = priv->hw_roc_channel;
iwl_set_rxon_channel(priv, chan, ctx);
iwl_set_flags_for_band(priv, ctx, chan->band, NULL);
@@ -375,13 +504,11 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
* do it now if after settings changed.
*/
iwl_set_tx_power(priv, priv->tx_power_next, false);
- return 0;
- }
- if (priv->cfg->ops->hcmd->set_pan_params) {
- ret = priv->cfg->ops->hcmd->set_pan_params(priv);
- if (ret)
- return ret;
+ /* make sure we are in the right PS state */
+ iwl_power_update_mode(priv, true);
+
+ return 0;
}
iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto);
@@ -405,6 +532,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
if (ret)
return ret;
+ ret = iwlagn_set_pan_params(priv);
+ if (ret)
+ return ret;
+
if (new_assoc)
return iwlagn_rxon_connect(priv, ctx);
@@ -446,9 +577,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
* set up the SM PS mode to OFF if an HT channel is
* configured.
*/
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- for_each_context(priv, ctx)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ for_each_context(priv, ctx)
+ iwlagn_set_rxon_chain(priv, ctx);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -636,6 +766,38 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv,
ht_conf->single_chain_sufficient = !need_multiple;
}
+static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
+{
+ struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+ int ret;
+
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+ iwl_is_any_associated(priv)) {
+ struct iwl_calib_chain_noise_reset_cmd cmd;
+
+ /* clear data for chain noise calibration algorithm */
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+
+ memset(&cmd, 0, sizeof(cmd));
+ iwl_set_calib_hdr(&cmd.hdr,
+ priv->phy_calib_chain_noise_reset_cmd);
+ ret = trans_send_cmd_pdu(&priv->trans,
+ REPLY_PHY_CALIBRATION_CMD,
+ CMD_SYNC, sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(priv,
+ "Could not send REPLY_PHY_CALIBRATION_CMD\n");
+ data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+ IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
+ }
+}
+
void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -692,7 +854,12 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
iwl_wake_any_queue(priv, ctx);
}
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ if (ctx->ctxid == IWL_RXON_CTX_BSS)
+ priv->have_rekey_data = false;
}
+
+ iwlagn_bt_coex_rssi_monitor(priv);
}
if (ctx->ht.enabled) {
@@ -704,8 +871,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
iwl_set_rxon_ht(priv, &priv->current_ht_config);
}
- if (priv->cfg->ops->hcmd->set_rxon_chain)
- priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
+ iwlagn_set_rxon_chain(priv, ctx);
if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ))
ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK;
@@ -743,7 +909,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
iwl_power_update_mode(priv, false);
/* Enable RX differential gain and sensitivity calibrations */
- iwl_chain_noise_reset(priv);
+ if (!priv->disable_chain_noise_cal)
+ iwlagn_chain_noise_reset(priv);
priv->start_calib = 1;
}
@@ -770,6 +937,13 @@ void iwlagn_post_scan(struct iwl_priv *priv)
struct iwl_rxon_context *ctx;
/*
+ * We do not commit power settings while scan is pending,
+ * do it now if the settings changed.
+ */
+ iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
+ iwl_set_tx_power(priv, priv->tx_power_next, false);
+
+ /*
* Since setting the RXON may have been deferred while
* performing the scan, fire one off if needed
*/
@@ -777,6 +951,5 @@ void iwlagn_post_scan(struct iwl_priv *priv)
if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging)))
iwlagn_commit_rxon(priv, ctx);
- if (priv->cfg->ops->hcmd->set_pan_params)
- priv->cfg->ops->hcmd->set_pan_params(priv);
+ iwlagn_set_pan_params(priv);
}