iwlwifi: seperate disconnected antenna function

Disconnected antenna algorithm is seperated into its own function from chain noise
calibration routine for better code management.

Signed-off-by: Shanyu Zhao <shanyu.zhao@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Shanyu Zhao 2010-11-10 09:56:48 -08:00 committed by John W. Linville
parent b2769b84d8
commit 3031242b31
1 changed files with 123 additions and 108 deletions

View File

@ -732,8 +732,128 @@ static inline u8 find_first_chain(u8 mask)
return CHAIN_C;
}
/**
* Run disconnected antenna algorithm to find out which antennas are
* disconnected.
*/
static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
struct iwl_chain_noise_data *data)
{
u32 active_chains = 0;
u32 max_average_sig;
u16 max_average_sig_antenna_i;
u8 num_tx_chains;
u8 first_chain;
u16 i = 0;
average_sig[0] = data->chain_signal_a /
priv->cfg->base_params->chain_noise_num_beacons;
average_sig[1] = data->chain_signal_b /
priv->cfg->base_params->chain_noise_num_beacons;
average_sig[2] = data->chain_signal_c /
priv->cfg->base_params->chain_noise_num_beacons;
if (average_sig[0] >= average_sig[1]) {
max_average_sig = average_sig[0];
max_average_sig_antenna_i = 0;
active_chains = (1 << max_average_sig_antenna_i);
} else {
max_average_sig = average_sig[1];
max_average_sig_antenna_i = 1;
active_chains = (1 << max_average_sig_antenna_i);
}
if (average_sig[2] >= max_average_sig) {
max_average_sig = average_sig[2];
max_average_sig_antenna_i = 2;
active_chains = (1 << max_average_sig_antenna_i);
}
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.
*/
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
priv->bt_full_concurrent) {
/* operated as 1x1 in full concurrency mode */
active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
} else
active_chains &= priv->hw_params.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->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 == 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->cfg->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->hw_params.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->hw_params.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);
}
/*
* Accumulate 20 beacons of signal and noise statistics for each of
* 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.
@ -750,8 +870,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
u32 chain_sig_c;
u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
u32 max_average_sig;
u16 max_average_sig_antenna_i;
u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
u16 i = 0;
@ -759,11 +877,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
u16 stat_chnum = INITIALIZATION_VALUE;
u8 rxon_band24;
u8 stat_band24;
u32 active_chains = 0;
u8 num_tx_chains;
unsigned long flags;
struct statistics_rx_non_phy *rx_info;
u8 first_chain;
/*
* MULTI-FIXME:
* When we support multiple interfaces on different channels,
@ -869,108 +985,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
return;
/* Analyze signal for disconnected antenna */
average_sig[0] = data->chain_signal_a /
priv->cfg->base_params->chain_noise_num_beacons;
average_sig[1] = data->chain_signal_b /
priv->cfg->base_params->chain_noise_num_beacons;
average_sig[2] = data->chain_signal_c /
priv->cfg->base_params->chain_noise_num_beacons;
if (average_sig[0] >= average_sig[1]) {
max_average_sig = average_sig[0];
max_average_sig_antenna_i = 0;
active_chains = (1 << max_average_sig_antenna_i);
} else {
max_average_sig = average_sig[1];
max_average_sig_antenna_i = 1;
active_chains = (1 << max_average_sig_antenna_i);
}
if (average_sig[2] >= max_average_sig) {
max_average_sig = average_sig[2];
max_average_sig_antenna_i = 2;
active_chains = (1 << max_average_sig_antenna_i);
}
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.
*/
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist &&
priv->bt_full_concurrent) {
/* operated as 1x1 in full concurrency mode */
active_chains &= first_antenna(priv->hw_params.valid_rx_ant);
} else
active_chains &= priv->hw_params.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->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 == 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->cfg->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->hw_params.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->hw_params.valid_rx_ant);
/* Save for use within RXON, TX, SCAN commands, etc. */
priv->chain_noise_data.active_chains = active_chains;
IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n",
active_chains);
iwl_find_disconn_antenna(priv, average_sig, data);
/* Analyze noise for rx balance */
average_noise[0] = data->chain_noise_a /