/* "false alarms" are signals that our DSP tries to lock onto, * but then determines that they are either noise, or transmissions * from a distant wireless network (also "noise", really) that get * "stepped on" by stronger transmissions within our own network. * This algorithm attempts to set a sensitivity level that is high * enough to receive all of our own network traffic, but not so * high that our DSP gets too busy trying to lock onto non-network
* activity/noise. */ staticint iwl_sens_energy_cck(struct iwl_priv *priv,
u32 norm_fa,
u32 rx_enable_time, struct statistics_general_data *rx_info)
{
u32 max_nrg_cck = 0; int i = 0;
u8 max_silence_rssi = 0;
u32 silence_ref = 0;
u8 silence_rssi_a = 0;
u8 silence_rssi_b = 0;
u8 silence_rssi_c = 0;
u32 val;
/* "false_alarms" values below are cross-multiplications to assess the * numbers of false alarms within the measured period of actual Rx * (Rx is off when we're txing), vs the min/max expected false alarms * (some should be expected if rx is sensitive enough) in a * hypothetical listening period of 200 time units (TU), 204.8 msec: * * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time *
* */
u32 false_alarms = norm_fa * 200 * 1024;
u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; struct iwl_sensitivity_data *data = NULL; conststruct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
data = &(priv->sensitivity_data);
data->nrg_auto_corr_silence_diff = 0;
/* Find max silence rssi among all 3 receivers. * This is background noise, which may include transmissions from other
* networks, measured during silence before our network's beacon */
silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
ALL_BAND_FILTER) >> 8);
silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
ALL_BAND_FILTER) >> 8);
silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
ALL_BAND_FILTER) >> 8);
val = max(silence_rssi_b, silence_rssi_c);
max_silence_rssi = max(silence_rssi_a, (u8) val);
/* Store silence rssi in 20-beacon history table */
data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
data->nrg_silence_idx++; if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
data->nrg_silence_idx = 0;
/* Find max silence rssi across 20 beacon history */ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
val = data->nrg_silence_rssi[i];
silence_ref = max(silence_ref, val);
}
IWL_DEBUG_CALIB(priv, "silence a %u, b %u, c %u, 20-bcn max %u\n",
silence_rssi_a, silence_rssi_b, silence_rssi_c,
silence_ref);
/* Find max rx energy (min value!) among all 3 receivers, * measured during beacon frame.
* Save it in 10-beacon history table. */
i = data->nrg_energy_idx;
val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
data->nrg_energy_idx++; if (data->nrg_energy_idx >= 10)
data->nrg_energy_idx = 0;
/* Find min rx energy (max value) across 10 beacon history. * This is the minimum signal level that we want to receive well. * Add backoff (margin so we don't miss slightly lower energy frames).
* This establishes an upper bound (min value) for energy threshold. */
max_nrg_cck = data->nrg_value[0]; for (i = 1; i < 10; i++)
max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
max_nrg_cck += 6;
IWL_DEBUG_CALIB(priv, "rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
rx_info->beacon_energy_a, rx_info->beacon_energy_b,
rx_info->beacon_energy_c, max_nrg_cck - 6);
/* Count number of consecutive beacons with fewer-than-desired
* false alarms. */ if (false_alarms < min_false_alarms)
data->num_in_cck_no_fa++; else
data->num_in_cck_no_fa = 0;
IWL_DEBUG_CALIB(priv, "consecutive bcns with few false alarms = %u\n",
data->num_in_cck_no_fa);
/* If we got too many false alarms this time, reduce sensitivity */ if ((false_alarms > max_false_alarms) &&
(data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
IWL_DEBUG_CALIB(priv, "norm FA %u > max FA %u\n",
false_alarms, max_false_alarms);
IWL_DEBUG_CALIB(priv, "... reducing sensitivity\n");
data->nrg_curr_state = IWL_FA_TOO_MANY; /* Store for "fewer than desired" on later beacon */
data->nrg_silence_ref = silence_ref;
/* increase energy threshold (reduce nrg value)
* to decrease sensitivity */
data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK; /* Else if we got fewer than desired, increase sensitivity */
} elseif (false_alarms < min_false_alarms) {
data->nrg_curr_state = IWL_FA_TOO_FEW;
/* Compare silence level with silence level for most recent
* healthy number or too many false alarms */
data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
(s32)silence_ref;
IWL_DEBUG_CALIB(priv, "norm FA %u < min FA %u, silence diff %d\n",
false_alarms, min_false_alarms,
data->nrg_auto_corr_silence_diff);
/* Increase value to increase sensitivity, but only if: * 1a) previous beacon did *not* have *too many* false alarms * 1b) AND there's a significant difference in Rx levels * from a previous beacon with too many, or healthy # FAs * OR 2) We've seen a lot of beacons (100) with too few
* false alarms */ if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
IWL_DEBUG_CALIB(priv, "... increasing sensitivity\n"); /* Increase nrg value to increase sensitivity */
val = data->nrg_th_cck + NRG_STEP_CCK;
data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
} else {
IWL_DEBUG_CALIB(priv, "... but not changing sensitivity\n");
}
/* Else we got a healthy number of false alarms, keep status quo */
} else {
IWL_DEBUG_CALIB(priv, " FA in safe zone\n");
data->nrg_curr_state = IWL_FA_GOOD_RANGE;
/* Store for use in "fewer than desired" with later beacon */
data->nrg_silence_ref = silence_ref;
/* If previous beacon had too many false alarms, * give it some extra margin by reducing sensitivity again
* (but don't go below measured energy of desired Rx) */ if (data->nrg_prev_state == IWL_FA_TOO_MANY) {
IWL_DEBUG_CALIB(priv, "... increasing margin\n"); if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
data->nrg_th_cck -= NRG_MARGIN; else
data->nrg_th_cck = max_nrg_cck;
}
}
/* Make sure the energy threshold does not go above the measured * energy of the desired Rx signals (reduced by backoff margin), * or else we might start missing Rx frames. * Lower value is higher energy, so we use max()!
*/
data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
IWL_DEBUG_CALIB(priv, "new nrg_th_cck %u\n", data->nrg_th_cck);
data->nrg_prev_state = data->nrg_curr_state;
/* Auto-correlation CCK algorithm */ if (false_alarms > min_false_alarms) {
/* increase auto_corr values to decrease sensitivity * so the DSP won't be disturbed by the noise
*/ if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1; else {
val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
data->auto_corr_cck =
min((u32)ranges->auto_corr_max_cck, val);
}
val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
data->auto_corr_cck_mrc =
min((u32)ranges->auto_corr_max_cck_mrc, val);
} elseif ((false_alarms < min_false_alarms) &&
((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
/* Decrease auto_corr values to increase sensitivity */
val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
data->auto_corr_cck =
max((u32)ranges->auto_corr_min_cck, val);
val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
data->auto_corr_cck_mrc =
max((u32)ranges->auto_corr_min_cck_mrc, val);
}
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
/* Don't send command to uCode if nothing has changed */ if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), sizeof(u16)*HD_TABLE_SIZE)) {
IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n"); return 0;
}
/* Copy table for comparison next time */
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE);
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
/* Don't send command to uCode if nothing has changed */ if (!memcmp(&cmd.enhance_table[0], &(priv->sensitivity_tbl[0]), sizeof(u16)*HD_TABLE_SIZE) &&
!memcmp(&cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX],
&(priv->enhance_sensitivity_tbl[0]), sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES)) {
IWL_DEBUG_CALIB(priv, "No change in SENSITIVITY_CMD\n"); return 0;
}
/* Copy table for comparison next time */
memcpy(&(priv->sensitivity_tbl[0]), &(cmd.enhance_table[0]), sizeof(u16)*HD_TABLE_SIZE);
memcpy(&(priv->enhance_sensitivity_tbl[0]),
&(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]), sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES);
return iwl_dvm_send_cmd(priv, &cmd_out);
}
void iwl_init_sensitivity(struct iwl_priv *priv)
{ int ret = 0; int i; struct iwl_sensitivity_data *data = NULL; conststruct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
if (priv->calib_disabled & IWL_SENSITIVITY_CALIB_DISABLED) return;
if (priv->fw->enhance_sensitivity_table)
ret |= iwl_enhance_sensitivity_write(priv); else
ret |= iwl_sensitivity_write(priv);
IWL_DEBUG_CALIB(priv, "<, ret);
}
if (!rx_enable_time) {
IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n"); return;
}
/* These statistics increase monotonically, and do not reset * at each beacon. Calculate difference from last value, or just
* use the new statistics value if it has reset or wrapped around. */ if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
data->last_bad_plcp_cnt_cck = bad_plcp_cck; else {
bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
data->last_bad_plcp_cnt_cck += bad_plcp_cck;
}
IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n",
average_sig[0], average_sig[1], average_sig[2]);
IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n",
max_average_sig, max_average_sig_antenna_i);
/* Compare signal strengths for all 3 receivers. */ for (i = 0; i < NUM_RX_CHAINS; i++) { if (i != max_average_sig_antenna_i) {
s32 rssi_delta = (max_average_sig - average_sig[i]);
/* If signal is very weak, compared with
* strongest, mark it as disconnected. */ if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
data->disconn_array[i] = 1; else
active_chains |= (1 << i);
IWL_DEBUG_CALIB(priv, "i = %d rssiDelta = %d " "disconn_array[i] = %d\n",
i, rssi_delta, data->disconn_array[i]);
}
}
/* * The above algorithm sometimes fails when the ucode * reports 0 for all chains. It's not clear why that * happens to start with, but it is then causing trouble * because this can make us enable more chains than the * hardware really has. * * To be safe, simply mask out any chains that we know * are not on the device.
*/
active_chains &= priv->nvm_data->valid_rx_ant;
num_tx_chains = 0; for (i = 0; i < NUM_RX_CHAINS; i++) { /* loops on all the bits of
* priv->hw_setting.valid_tx_ant */
u8 ant_msk = (1 << i); if (!(priv->nvm_data->valid_tx_ant & ant_msk)) continue;
num_tx_chains++; if (data->disconn_array[i] == 0) /* there is a Tx antenna connected */ break; if (num_tx_chains == priv->hw_params.tx_chains_num &&
data->disconn_array[i]) { /* * If all chains are disconnected * connect the first valid tx chain
*/
first_chain =
find_first_chain(priv->nvm_data->valid_tx_ant);
data->disconn_array[first_chain] = 0;
active_chains |= BIT(first_chain);
IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n",
first_chain); break;
}
}
if (active_chains != priv->nvm_data->valid_rx_ant &&
active_chains != priv->chain_noise_data.active_chains)
IWL_DEBUG_CALIB(priv, "Detected that not all antennas are connected! " "Connected: %#x, valid: %#x.\n",
active_chains,
priv->nvm_data->valid_rx_ant);
/* Save for use within RXON, TX, SCAN commands, etc. */
data->active_chains = active_chains;
IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
active_chains);
}
/* * Find Gain Code for the chains based on "default chain"
*/ for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) { if ((data->disconn_array[i])) {
data->delta_gain_code[i] = 0; continue;
}
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
if (delta_g < 0) /* * set negative sign ... * note to Intel developers: This is uCode API format, * not the format of any internal device registers. * Do not change this format for e.g. 6050 or similar * devices. Change format only if more resolution * (i.e. more than 2 bits magnitude) is needed.
*/
data->delta_gain_code[i] |= (1 << 2);
}
/* * Accumulate 16 beacons of signal and noise statistics for each of * 3 receivers/antennas/rx-chains, then figure out: * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers.
*/ void iwl_chain_noise_calibration(struct iwl_priv *priv)
{ struct iwl_chain_noise_data *data = NULL;
/* * MULTI-FIXME: * When we support multiple interfaces on different channels, * this must be modified/fixed.
*/ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED) return;
data = &(priv->chain_noise_data);
/* * Accumulate just the first "chain_noise_num_beacons" after * the first association, then we're done forever.
*/ if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) { if (data->state == IWL_CHAIN_NOISE_ALIVE)
IWL_DEBUG_CALIB(priv, "Wait for noise calib reset\n"); return;
}
spin_lock_bh(&priv->statistics.lock);
rx_info = &priv->statistics.rx_non_phy;
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
spin_unlock_bh(&priv->statistics.lock); return;
}
/* Make sure we accumulate data for just the associated channel
* (even if scanning). */ if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n",
rxon_chnum, rxon_band24);
spin_unlock_bh(&priv->statistics.lock); return;
}
IWL_DEBUG_CALIB(priv, "chan=%d, band24=%d, beacon=%d\n",
rxon_chnum, rxon_band24, data->beacon_count);
IWL_DEBUG_CALIB(priv, "chain_sig: a %d b %d c %d\n",
chain_sig_a, chain_sig_b, chain_sig_c);
IWL_DEBUG_CALIB(priv, "chain_noise: a %d b %d c %d\n",
chain_noise_a, chain_noise_b, chain_noise_c);
/* If this is the "chain_noise_num_beacons", determine: * 1) Disconnected antennas (using signal strengths)
* 2) Differential gain (using silence noise) to balance receivers */ if (data->beacon_count != IWL_CAL_NUM_BEACONS) return;
/* Analyze signal for disconnected antenna */ if (priv->lib->bt_params &&
priv->lib->bt_params->advanced_bt_coexist) { /* Disable disconnected antenna algorithm for advanced
bt coex, assuming valid antennas are connected */
data->active_chains = priv->nvm_data->valid_rx_ant; for (i = 0; i < NUM_RX_CHAINS; i++) if (!(data->active_chains & (1<<i)))
data->disconn_array[i] = 1;
} else
iwl_find_disconn_antenna(priv, average_sig, data);
for (i = 0; i < NUM_RX_CHAINS; i++) { if (!(data->disconn_array[i]) &&
(average_noise[i] <= min_average_noise)) { /* This means that chain i is active and has
* lower noise values so far: */
min_average_noise = average_noise[i];
min_average_noise_antenna_i = i;
}
}
IWL_DEBUG_CALIB(priv, "average_noise: a %d b %d c %d\n",
average_noise[0], average_noise[1],
average_noise[2]);
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.