int iwlagn_send_tx_power(struct iwl_priv *priv)
{ struct iwlagn_tx_power_dbm_cmd tx_power_cmd;
u8 tx_ant_cfg_cmd;
if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), "TX Power requested while scanning!\n")) return -EAGAIN;
/* half dBm need to multiply */
tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
if (tx_power_cmd.global_lmt > priv->nvm_data->max_tx_pwr_half_dbm) { /* * For the newer devices which using enhanced/extend tx power * table in EEPROM, the format is in half dBm. driver need to * convert to dBm format before report to mac80211. * By doing so, there is a possibility of 1/2 dBm resolution * lost. driver will perform "round-up" operation before * reporting, but it will cause 1/2 dBm tx power over the * regulatory limit. Perform the checking here, if the * "tx_power_user_lmt" is higher than EEPROM value (in * half-dBm format), lower the tx power based on EEPROM
*/
tx_power_cmd.global_lmt =
priv->nvm_data->max_tx_pwr_half_dbm;
}
tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED;
tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO;
/* store temperature from correct statistics (in Celsius) */
priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
iwl_tt_handler(priv);
}
int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum nl80211_band band)
{ int idx = 0; int band_offset = 0;
/* HT rate format: mac80211 wants an MCS number, which is just LSB */ if (rate_n_flags & RATE_MCS_HT_MSK) {
idx = (rate_n_flags & 0xff); return idx; /* Legacy rate format, search for match in table */
} else { if (band == NL80211_BAND_5GHZ)
band_offset = IWL_FIRST_OFDM_RATE; for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) return idx - band_offset;
}
if (priv->lib->bt_params) { /* * newer generation of devices (2000 series and newer) * use the version 2 of the bt command * we need to make sure sending the host command * with correct data structure to avoid uCode assert
*/ if (priv->lib->bt_params->bt_session_2) {
bt_cmd_v2.prio_boost = cpu_to_le32(
priv->lib->bt_params->bt_prio_boost);
bt_cmd_v2.tx_prio_boost = 0;
bt_cmd_v2.rx_prio_boost = 0;
} else { /* older version only has 8 bits */
WARN_ON(priv->lib->bt_params->bt_prio_boost & ~0xFF);
bt_cmd_v1.prio_boost =
priv->lib->bt_params->bt_prio_boost;
bt_cmd_v1.tx_prio_boost = 0;
bt_cmd_v1.rx_prio_boost = 0;
}
} else {
IWL_ERR(priv, "failed to construct BT Coex Config\n"); return;
}
/* * Possible situations when BT needs to take over for receive, * at the same time where STA needs to response to AP's frame(s), * reduce the tx power of the required response frames, by that, * allow the concurrent BT receive & WiFi transmit * (BT - ANT A, WiFi -ANT B), without interference to one another * * Reduced tx power apply to control frames only (ACK/Back/CTS) * when indicated by the BT config command
*/
basic.kill_ack_mask = priv->kill_ack_mask;
basic.kill_cts_mask = priv->kill_cts_mask; if (priv->reduced_txpower)
basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
basic.valid = priv->bt_valid;
/* * Configure BT coex mode to "no coexistence" when the * user disabled BT coexistence, we have no interface * (might be in monitor mode), or the interface is in * IBSS mode (no proper uCode support for coex then).
*/ if (!iwlwifi_mod_params.bt_coex_active ||
priv->iw_mode == NL80211_IFTYPE_ADHOC) {
basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED;
} else {
basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W <<
IWLAGN_BT_FLAG_COEX_MODE_SHIFT;
if (!priv->bt_enable_pspoll)
basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; else
basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE;
/* Check whether AP or GO mode is active. */ if (rssi_ena) {
for_each_context(priv, ctx) { if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP &&
iwl_is_associated_ctx(ctx)) {
found_ap = true; break;
}
}
}
/* * If disable was received or If GO/AP mode, disable RSSI * measurements.
*/ if (!rssi_ena || found_ap) { if (priv->cur_rssi_ctx) {
ctx = priv->cur_rssi_ctx;
ieee80211_disable_rssi_reports(ctx->vif);
priv->cur_rssi_ctx = NULL;
} return;
}
/* * If rssi measurements need to be enabled, consider all cases now. * Figure out how many contexts are active.
*/
for_each_context(priv, ctx) { if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
iwl_is_associated_ctx(ctx)) {
found_ctx = ctx; break;
}
}
/* * rssi monitor already enabled for the correct interface...nothing * to do.
*/ if (found_ctx == priv->cur_rssi_ctx) return;
/* * Figure out if rssi monitor is currently enabled, and needs * to be changed. If rssi monitor is already enabled, disable * it first else just enable rssi measurements on the * interface found above.
*/ if (priv->cur_rssi_ctx) {
ctx = priv->cur_rssi_ctx; if (ctx->vif)
ieee80211_disable_rssi_reports(ctx->vif);
}
/* * Note: bt_traffic_load can be overridden by scan complete and * coex profile notifications. Ignore that since only bad consequence * can be not matching debug print with actual state.
*/
IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n",
priv->bt_traffic_load);
switch (priv->bt_traffic_load) { case IWL_BT_COEX_TRAFFIC_LOAD_NONE: if (priv->bt_status)
smps_request = IEEE80211_SMPS_DYNAMIC; else
smps_request = IEEE80211_SMPS_AUTOMATIC; break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
smps_request = IEEE80211_SMPS_DYNAMIC; break; case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
smps_request = IEEE80211_SMPS_STATIC; break; default:
IWL_ERR(priv, "Invalid BT traffic load: %d\n",
priv->bt_traffic_load); break;
}
mutex_lock(&priv->mutex);
/* * We can not send command to firmware while scanning. When the scan * complete we will schedule this work again. We do check with mutex * locked to prevent new scan request to arrive. We do not check * STATUS_SCANNING to avoid race when queue_work two times from * different notifications, but quit and not perform any work at all.
*/ if (test_bit(STATUS_SCAN_HW, &priv->status)) goto out;
/* * Dynamic PS poll related functionality. Adjust RSSI measurements if * necessary.
*/
iwlagn_bt_coex_rssi_monitor(priv);
out:
mutex_unlock(&priv->mutex);
}
/* * If BT sco traffic, and RSSI monitor is enabled, move measurements to the * correct interface or disable it if this is the last interface to be * removed.
*/ void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv)
{ if (priv->bt_is_sco &&
priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS)
iwlagn_bt_adjust_rssi_monitor(priv, true); else
iwlagn_bt_adjust_rssi_monitor(priv, false);
}
/* * Determine how many receiver/antenna chains to use. * * More provides better reception via diversity. Fewer saves power * at the expense of throughput, but only when not in powersave to * start with. * * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many.
*/ staticint iwl_get_active_rx_chain_count(struct iwl_priv *priv)
{ if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
(priv->bt_full_concurrent ||
priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* * only use chain 'A' in bt high traffic load or * full concurrency mode
*/ return IWL_NUM_RX_CHAINS_SINGLE;
} /* # of Rx chains to use when expecting MIMO. */ if (is_single_rx_stream(priv)) return IWL_NUM_RX_CHAINS_SINGLE; else return IWL_NUM_RX_CHAINS_MULTIPLE;
}
/* * When we are in power saving mode, unless device support spatial * multiplexing power save, use the active count for rx chain count.
*/ staticint iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
{ /* # Rx chains when idling, depending on SMPS mode */ switch (priv->current_ht_config.smps) { case IEEE80211_SMPS_STATIC: case IEEE80211_SMPS_DYNAMIC: return IWL_NUM_IDLE_CHAINS_SINGLE; case IEEE80211_SMPS_AUTOMATIC: case IEEE80211_SMPS_OFF: return active_cnt; default:
WARN(1, "invalid SMPS mode %d",
priv->current_ht_config.smps); return active_cnt;
}
}
/* up to 4 chains */ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
{
u8 res;
res = (chain_bitmap & BIT(0)) >> 0;
res += (chain_bitmap & BIT(1)) >> 1;
res += (chain_bitmap & BIT(2)) >> 2;
res += (chain_bitmap & BIT(3)) >> 3; return res;
}
/* * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image * * Selects how many and which Rx receivers/antennas/chains to use. * This should not be used for scan command ... it puts data in wrong place.
*/ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{ bool is_single = is_single_rx_stream(priv); bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
u32 active_chains;
u16 rx_chain;
/* Tell uCode which antennas are actually connected. * Before first association, we assume all antennas are connected. * Just after first association, iwl_chain_noise_calibration()
* checks which antennas actually *are* connected. */ if (priv->chain_noise_data.active_chains)
active_chains = priv->chain_noise_data.active_chains; else
active_chains = priv->nvm_data->valid_rx_ant;
if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist &&
(priv->bt_full_concurrent ||
priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { /* * only use chain 'A' in bt high traffic load or * full concurrency mode
*/
active_chains = first_antenna(active_chains);
}
/* How many receivers should we use? */
active_rx_cnt = iwl_get_active_rx_chain_count(priv);
idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
/* correct rx chain count according hw settings * and chain noise calibration
*/
valid_rx_cnt = iwl_count_chain_bitmap(active_chains); if (valid_rx_cnt < active_rx_cnt)
active_rx_cnt = valid_rx_cnt;
if (valid_rx_cnt < idle_rx_cnt)
idle_rx_cnt = valid_rx_cnt;
/* * For non-QoS this relies on the fact that both the uCode and * mac80211 use TID 0 (as they need to to avoid replay attacks) * for checking the IV in the frames.
*/ for (i = 0; i < IWLAGN_NUM_RSC; i++) {
ieee80211_get_key_rx_seq(key, i, &seq);
tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32); /* wrapping isn't allowed, AP must rekey */ if (seq.tkip.iv32 > cur_rx_iv32)
cur_rx_iv32 = seq.tkip.iv32;
}
/* * For non-QoS this relies on the fact that both the uCode and * mac80211 use TID 0 for checking the IV in the frames.
*/ for (i = 0; i < IWLAGN_NUM_RSC; i++) {
u8 *pn = seq.ccmp.pn;
/* * We know the last used seqno, and the uCode expects to know that * one, it will increment before TX.
*/
seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
/* * For QoS counters, we store the one to use next, so subtract 0x10 * since the uCode will add 0x10 before using the value.
*/ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
seq = priv->tid_data[IWL_AP_ID][i].seq_number;
seq -= 0x10;
wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
}
if (wowlan->disconnect)
wakeup_filter_cmd.enabled |=
cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE); if (wowlan->magic_pkt)
wakeup_filter_cmd.enabled |=
cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET); if (wowlan->gtk_rekey_failure)
wakeup_filter_cmd.enabled |=
cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL); if (wowlan->eap_identity_req)
wakeup_filter_cmd.enabled |=
cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ); if (wowlan->four_way_handshake)
wakeup_filter_cmd.enabled |=
cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE); if (wowlan->n_patterns)
wakeup_filter_cmd.enabled |=
cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
if (wowlan->rfkill_release)
d3_cfg_cmd.wakeup_flags |=
cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
iwl_scan_cancel_timeout(priv, 200);
memcpy(&rxon, &ctx->active, sizeof(rxon));
priv->ucode_loaded = false;
iwl_trans_stop_device(priv->trans);
ret = iwl_trans_start_hw(priv->trans); if (ret) goto out;
priv->wowlan = true;
ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN); if (ret) goto out;
/* now configure WoWLAN ucode */
ret = iwl_alive_start(priv); if (ret) goto out;
memcpy(&ctx->staging, &rxon, sizeof(rxon));
ret = iwlagn_commit_rxon(priv, ctx); if (ret) goto out;
ret = iwl_power_update_mode(priv, true); if (ret) goto out;
if (!iwlwifi_mod_params.swcrypto) { /* mark all keys clear */
priv->ucode_key_table = 0;
ctx->key_mapping_keys = 0;
/* * This needs to be unlocked due to lock ordering * constraints. Since we're in the suspend path * that isn't really a problem though.
*/
mutex_unlock(&priv->mutex);
ieee80211_iter_keys(priv->hw, ctx->vif,
iwlagn_wowlan_program_keys,
&key_data);
mutex_lock(&priv->mutex); if (key_data.error) {
ret = -EIO; goto out;
}
/* * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag * in iwl_down but cancel the workers only later.
*/ if (!priv->ucode_loaded) {
IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id); return -EIO;
}
/* * Synchronous commands from this op-mode must hold * the mutex, this ensures we don't try to send two * (or more) synchronous commands at a time.
*/ if (!(cmd->flags & CMD_ASYNC))
lockdep_assert_held(&priv->mutex);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.