/* Find max silence rssi among all 3 receivers. *Thisisbackgroundnoise,whichmayincludetransmissionsfromother
* 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);
}
D_CALIB("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, *measuredduringbeaconframe.
* 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. *Thisistheminimumsignallevelthatwewanttoreceivewell. *Addbackoff(marginsowedon'tmissslightlylowerenergyframes).
* 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;
D_CALIB("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;
D_CALIB("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) {
D_CALIB("norm FA %u > max FA %u\n", false_alarms,
max_false_alarms);
D_CALIB("... reducing sensitivity\n");
data->nrg_curr_state = IL_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 = IL_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;
D_CALIB("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)previousbeacondid*not*have*toomany*falsealarms *1b)ANDthere'sasignificantdifferenceinRxlevels *fromapreviousbeaconwithtoomany,orhealthy#FAs *OR2)We'veseenalotofbeacons(100)withtoofew
* false alarms */ if (data->nrg_prev_state != IL_FA_TOO_MANY &&
(data->nrg_auto_corr_silence_diff > NRG_DIFF ||
data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA)) {
D_CALIB("... 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 {
D_CALIB("... but not changing sensitivity\n");
}
/* Else we got a healthy number of false alarms, keep status quo */
} else {
D_CALIB(" FA in safe zone\n");
data->nrg_curr_state = IL_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, *giveitsomeextramarginbyreducingsensitivityagain
* (but don't go below measured energy of desired Rx) */ if (IL_FA_TOO_MANY == data->nrg_prev_state) {
D_CALIB("... 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 *energyofthedesiredRxsignals(reducedbybackoffmargin), *orelsewemightstartmissingRxframes. *Lowervalueishigherenergy,soweusemax()!
*/
data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
D_CALIB("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) {
/* Update uCode's "work" table, and copy it to DSP */
cmd.control = C_SENSITIVITY_CONTROL_WORK_TBL;
/* Don't send command to uCode if nothing has changed */ if (!memcmp
(&cmd.table[0], &(il->sensitivity_tbl[0]), sizeof(u16) * HD_TBL_SIZE)) {
D_CALIB("No change in C_SENSITIVITY\n"); return0;
}
/* Copy table for comparison next time */
memcpy(&(il->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16) * HD_TBL_SIZE);
return il_send_cmd(il, &cmd_out);
}
void
il4965_init_sensitivity(struct il_priv *il)
{ int ret = 0; int i; struct il_sensitivity_data *data = NULL; conststruct il_sensitivity_ranges *ranges = il->hw_params.sens;
if (il->disable_sens_cal) return;
D_CALIB("Start il4965_init_sensitivity\n");
/* Clear driver's sensitivity algo data */
data = &(il->sensitivity_data);
if (!rx_enable_time) {
D_CALIB("<< RX Enable Time == 0!\n"); return;
}
/* These stats increase monotonically, and do not reset *ateachbeacon.Calculatedifferencefromlastvalue,orjust
* use the new stats 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;
}
D_CALIB("average_sig: a %d b %d c %d\n", average_sig[0], average_sig[1],
average_sig[2]);
D_CALIB("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);
D_CALIB("i = %d rssiDelta = %d " "disconn_array[i] = %d\n", i, rssi_delta,
data->disconn_array[i]);
}
}
num_tx_chains = 0; for (i = 0; i < NUM_RX_CHAINS; i++) { /* loops on all the bits of
* il->hw_setting.valid_tx_ant */
u8 ant_msk = (1 << i); if (!(il->hw_params.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 == il->hw_params.tx_chains_num &&
data->disconn_array[i]) { /* *Ifallchainsaredisconnected *connectthefirstvalidtxchain
*/
first_chain =
il4965_find_first_chain(il->cfg->valid_tx_ant);
data->disconn_array[first_chain] = 0;
active_chains |= BIT(first_chain);
D_CALIB("All Tx chains are disconnected" "- declare %d as connected\n", first_chain); break;
}
}
if (active_chains != il->hw_params.valid_rx_ant &&
active_chains != il->chain_noise_data.active_chains)
D_CALIB("Detected that not all antennas are connected! " "Connected: %#x, valid: %#x.\n", active_chains,
il->hw_params.valid_rx_ant);
/* Save for use within RXON, TX, SCAN commands, etc. */
data->active_chains = active_chains;
D_CALIB("active_chains (bitwise) = 0x%x\n", active_chains);
}
/* Make sure we accumulate data for just the associated channel
* (even if scanning). */ if (rxon_chnum != stat_chnum || rxon_band24 != stat_band24) {
D_CALIB("Stats not from chan=%d, band24=%d\n", rxon_chnum,
rxon_band24);
spin_unlock_irqrestore(&il->lock, flags); return;
}
D_CALIB("chan=%d, band24=%d, beacon=%d\n", rxon_chnum, rxon_band24,
data->beacon_count);
D_CALIB("chain_sig: a %d b %d c %d\n", chain_sig_a, chain_sig_b,
chain_sig_c);
D_CALIB("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)Disconnectedantennas(usingsignalstrengths)
* 2) Differential gain (using silence noise) to balance receivers */ if (data->beacon_count != il->cfg->chain_noise_num_beacons) return;
/* Analyze signal for disconnected antenna */
il4965_find_disconn_antenna(il, 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;
}
}
D_CALIB("average_noise: a %d b %d c %d\n", average_noise[0],
average_noise[1], average_noise[2]);
/* Some power changes may have been made during the calibration. *UpdateandcommittheRXON
*/ if (il->ops->update_chain_flags)
il->ops->update_chain_flags(il);
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.