|
@@ -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 /
|