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);
 
                }
        }
 
+       /* 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);
 
        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);
 
 
        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
  *
 {
        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;
 
 
 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 {
 
 /* 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 */
 
 /*
  * 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 */
                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)
 /* 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);
 
 
 
 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);