iwlwifi: use the results from disconnected antenna algorithm
authorGrumbach, Emmanuel <emmanuel.grumbach@intel.com>
Wed, 3 Sep 2008 03:26:53 +0000 (11:26 +0800)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 11 Sep 2008 19:53:31 +0000 (15:53 -0400)
This patch makes usage of the results from disconnected antenna alg to
know how many antennas are connected.

It also synchronizes between the chain noise alg and the W/A that
disables power management during association. All the antennas must be
enables during the chain noise algorithm. Hence, power management is
restored only after the completion of the algorithm.

In the future, we will need to update the AP that we don't support MIMO
if there is only one antenna connected. We also need to update the rate
scaling algorithm.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-calib.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-power.h

index 78902da3d516296a0d83f42052ca410fb582223c..914a3ca54600e27b9989e7a590fd2510e66f47f4 100644 (file)
@@ -2558,7 +2558,11 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
        iwl_activate_qos(priv, 0);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl_power_enable_management(priv);
+       /* the chain noise calibration will enabled PM upon completion
+        * If chain noise has already been run, then we need to enable
+        * power management here */
+       if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
+               iwl_power_enable_management(priv);
 
        /* Enable Rx differential gain and sensitivity calibrations */
        iwl_chain_noise_reset(priv);
index 35fb4a4f737daba64f8c3a06eb6c7cb470343968..72fbf47229db7da9832c3eb05a6c2722df651b7e 100644 (file)
@@ -808,13 +808,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
                }
        }
 
+       /* Save for use within RXON, TX, SCAN commands, etc. */
+       priv->chain_noise_data.active_chains = active_chains;
        IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
                        active_chains);
 
-       /* Save for use within RXON, TX, SCAN commands, etc. */
-       /*priv->valid_antenna = active_chains;*/
-       /*FIXME: should be reflected in RX chains in RXON */
-
        /* Analyze noise for rx balance */
        average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
        average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
@@ -839,6 +837,15 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
 
        priv->cfg->ops->utils->gain_computation(priv, average_noise,
                min_average_noise_antenna_i, min_average_noise);
+
+       /* Some power changes may have been made during the calibration.
+        * Update and commit the RXON
+        */
+       if (priv->cfg->ops->lib->update_chain_flags)
+               priv->cfg->ops->lib->update_chain_flags(priv);
+
+       data->state = IWL_CHAIN_NOISE_DONE;
+       iwl_power_enable_management(priv);
 }
 EXPORT_SYMBOL(iwl_chain_noise_calibration);
 
index dbeaca15dda54f3ab9419e06afff59bd50611e2c..46683eacfdcdf7d2c0b242f8401c2dec845a54bd 100644 (file)
@@ -740,6 +740,17 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
        return idle_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(4)) >> 4;
+       return res;
+}
+
 /**
  * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
  *
@@ -750,25 +761,35 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
 {
        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;
+       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. */
-       rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+        if (priv->chain_noise_data.active_chains)
+               active_chains = priv->chain_noise_data.active_chains;
+       else
+               active_chains = priv->hw_params.valid_rx_ant;
+
+       rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
 
        /* 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 accoridng hw settings */
-       if (priv->hw_params.rx_chains_num < active_rx_cnt)
-               active_rx_cnt = priv->hw_params.rx_chains_num;
 
-       if (priv->hw_params.rx_chains_num < idle_rx_cnt)
-               idle_rx_cnt = priv->hw_params.rx_chains_num;
+       /* 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;
 
        rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
        rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
index 7934f56f729231ebab3bc016b157362cbf1adb38..6e150f678c686c3d1ddae0577e5b777efcc564e0 100644 (file)
@@ -699,8 +699,9 @@ enum iwl4965_false_alarm_state {
 
 enum iwl4965_chain_noise_state {
        IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
-       IWL_CHAIN_NOISE_ACCUMULATE = 1,
-       IWL_CHAIN_NOISE_CALIBRATED = 2,
+       IWL_CHAIN_NOISE_ACCUMULATE,
+       IWL_CHAIN_NOISE_CALIBRATED,
+       IWL_CHAIN_NOISE_DONE,
 };
 
 enum iwl4965_calib_enabled_state {
@@ -758,17 +759,18 @@ struct iwl_sensitivity_data {
 
 /* Chain noise (differential Rx gain) calib data */
 struct iwl_chain_noise_data {
-       u8 state;
-       u16 beacon_count;
+       u32 active_chains;
        u32 chain_noise_a;
        u32 chain_noise_b;
        u32 chain_noise_c;
        u32 chain_signal_a;
        u32 chain_signal_b;
        u32 chain_signal_c;
+       u16 beacon_count;
        u8 disconn_array[NUM_RX_CHAINS];
        u8 delta_gain_code[NUM_RX_CHAINS];
        u8 radio_write;
+       u8 state;
 };
 
 #define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
index 16f834d0c486cc64df1e88eaf0f7808a0bf2ac88..bd6f600027d14b127e60fdfe1b0709b85fdb4410 100644 (file)
@@ -252,12 +252,21 @@ static int iwl_update_power_command(struct iwl_priv *priv,
 /*
  * calucaute the final power mode index
  */
-int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
+int iwl_power_update_mode(struct iwl_priv *priv, bool force)
 {
        struct iwl_power_mgr *setting = &(priv->power_data);
        int ret = 0;
        u16 uninitialized_var(final_mode);
 
+       /* Don't update the RX chain when chain noise calibration is running */
+       if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE &&
+           priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) {
+               IWL_DEBUG_POWER("Cannot update the power, chain noise "
+                       "calibration running: %d\n",
+                       priv->chain_noise_data.state);
+               return -EAGAIN;
+       }
+
        /* If on battery, set to 3,
        * if plugged into AC power, set to CAM ("continuously aware mode"),
        * else user level */
@@ -285,7 +294,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
                final_mode = IWL_POWER_MODE_CAM;
 
        if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
-           ((setting->power_mode != final_mode) || refresh)) {
+           ((setting->power_mode != final_mode) || force)) {
                struct iwl_powertable_cmd cmd;
 
                if (final_mode != IWL_POWER_MODE_CAM)
@@ -359,35 +368,26 @@ EXPORT_SYMBOL(iwl_power_enable_management);
 /* set user_power_setting */
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
 {
-       int ret = 0;
-
        if (mode > IWL_POWER_LIMIT)
                return -EINVAL;
 
        priv->power_data.user_power_setting = mode;
 
-       ret = iwl_power_update_mode(priv, 0);
-
-       return ret;
+       return iwl_power_update_mode(priv, 0);
 }
 EXPORT_SYMBOL(iwl_power_set_user_mode);
 
-
 /* set system_power_setting. This should be set by over all
  * PM application.
  */
 int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
 {
-       int ret = 0;
-
        if (mode > IWL_POWER_LIMIT)
                return -EINVAL;
 
        priv->power_data.system_power_setting = mode;
 
-       ret = iwl_power_update_mode(priv, 0);
-
-       return ret;
+       return iwl_power_update_mode(priv, 0);
 }
 EXPORT_SYMBOL(iwl_power_set_system_mode);
 
index aa99f3647def8907166df4a54847dde985f9a000..a5c334f10e5d72c26353e68551e62f3eb70d2c47 100644 (file)
@@ -80,7 +80,7 @@ struct iwl_power_mgr {
 
 void iwl_setup_power_deferred_work(struct iwl_priv *priv);
 void iwl_power_cancel_timeout(struct iwl_priv *priv);
-int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh);
+int iwl_power_update_mode(struct iwl_priv *priv, bool force);
 int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
 int iwl_power_enable_management(struct iwl_priv *priv);
 int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);