aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h2
6 files changed, 64 insertions, 30 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 78902da3d516..914a3ca54600 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2558,7 +2558,11 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
2558 iwl_activate_qos(priv, 0); 2558 iwl_activate_qos(priv, 0);
2559 spin_unlock_irqrestore(&priv->lock, flags); 2559 spin_unlock_irqrestore(&priv->lock, flags);
2560 2560
2561 iwl_power_enable_management(priv); 2561 /* the chain noise calibration will enabled PM upon completion
2562 * If chain noise has already been run, then we need to enable
2563 * power management here */
2564 if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
2565 iwl_power_enable_management(priv);
2562 2566
2563 /* Enable Rx differential gain and sensitivity calibrations */ 2567 /* Enable Rx differential gain and sensitivity calibrations */
2564 iwl_chain_noise_reset(priv); 2568 iwl_chain_noise_reset(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index 35fb4a4f737d..72fbf47229db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -808,13 +808,11 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
808 } 808 }
809 } 809 }
810 810
811 /* Save for use within RXON, TX, SCAN commands, etc. */
812 priv->chain_noise_data.active_chains = active_chains;
811 IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n", 813 IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
812 active_chains); 814 active_chains);
813 815
814 /* Save for use within RXON, TX, SCAN commands, etc. */
815 /*priv->valid_antenna = active_chains;*/
816 /*FIXME: should be reflected in RX chains in RXON */
817
818 /* Analyze noise for rx balance */ 816 /* Analyze noise for rx balance */
819 average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS); 817 average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
820 average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS); 818 average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
@@ -839,6 +837,15 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
839 837
840 priv->cfg->ops->utils->gain_computation(priv, average_noise, 838 priv->cfg->ops->utils->gain_computation(priv, average_noise,
841 min_average_noise_antenna_i, min_average_noise); 839 min_average_noise_antenna_i, min_average_noise);
840
841 /* Some power changes may have been made during the calibration.
842 * Update and commit the RXON
843 */
844 if (priv->cfg->ops->lib->update_chain_flags)
845 priv->cfg->ops->lib->update_chain_flags(priv);
846
847 data->state = IWL_CHAIN_NOISE_DONE;
848 iwl_power_enable_management(priv);
842} 849}
843EXPORT_SYMBOL(iwl_chain_noise_calibration); 850EXPORT_SYMBOL(iwl_chain_noise_calibration);
844 851
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index dbeaca15dda5..46683eacfdcd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -740,6 +740,17 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
740 return idle_cnt; 740 return idle_cnt;
741} 741}
742 742
743/* up to 4 chains */
744static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
745{
746 u8 res;
747 res = (chain_bitmap & BIT(0)) >> 0;
748 res += (chain_bitmap & BIT(1)) >> 1;
749 res += (chain_bitmap & BIT(2)) >> 2;
750 res += (chain_bitmap & BIT(4)) >> 4;
751 return res;
752}
753
743/** 754/**
744 * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image 755 * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
745 * 756 *
@@ -750,25 +761,35 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
750{ 761{
751 bool is_single = is_single_rx_stream(priv); 762 bool is_single = is_single_rx_stream(priv);
752 bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); 763 bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
753 u8 idle_rx_cnt, active_rx_cnt; 764 u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt;
765 u32 active_chains;
754 u16 rx_chain; 766 u16 rx_chain;
755 767
756 /* Tell uCode which antennas are actually connected. 768 /* Tell uCode which antennas are actually connected.
757 * Before first association, we assume all antennas are connected. 769 * Before first association, we assume all antennas are connected.
758 * Just after first association, iwl_chain_noise_calibration() 770 * Just after first association, iwl_chain_noise_calibration()
759 * checks which antennas actually *are* connected. */ 771 * checks which antennas actually *are* connected. */
760 rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; 772 if (priv->chain_noise_data.active_chains)
773 active_chains = priv->chain_noise_data.active_chains;
774 else
775 active_chains = priv->hw_params.valid_rx_ant;
776
777 rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS;
761 778
762 /* How many receivers should we use? */ 779 /* How many receivers should we use? */
763 active_rx_cnt = iwl_get_active_rx_chain_count(priv); 780 active_rx_cnt = iwl_get_active_rx_chain_count(priv);
764 idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); 781 idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
765 782
766 /* correct rx chain count accoridng hw settings */
767 if (priv->hw_params.rx_chains_num < active_rx_cnt)
768 active_rx_cnt = priv->hw_params.rx_chains_num;
769 783
770 if (priv->hw_params.rx_chains_num < idle_rx_cnt) 784 /* correct rx chain count according hw settings
771 idle_rx_cnt = priv->hw_params.rx_chains_num; 785 * and chain noise calibration
786 */
787 valid_rx_cnt = iwl_count_chain_bitmap(active_chains);
788 if (valid_rx_cnt < active_rx_cnt)
789 active_rx_cnt = valid_rx_cnt;
790
791 if (valid_rx_cnt < idle_rx_cnt)
792 idle_rx_cnt = valid_rx_cnt;
772 793
773 rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; 794 rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
774 rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; 795 rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 7934f56f7292..6e150f678c68 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -699,8 +699,9 @@ enum iwl4965_false_alarm_state {
699 699
700enum iwl4965_chain_noise_state { 700enum iwl4965_chain_noise_state {
701 IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ 701 IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */
702 IWL_CHAIN_NOISE_ACCUMULATE = 1, 702 IWL_CHAIN_NOISE_ACCUMULATE,
703 IWL_CHAIN_NOISE_CALIBRATED = 2, 703 IWL_CHAIN_NOISE_CALIBRATED,
704 IWL_CHAIN_NOISE_DONE,
704}; 705};
705 706
706enum iwl4965_calib_enabled_state { 707enum iwl4965_calib_enabled_state {
@@ -758,17 +759,18 @@ struct iwl_sensitivity_data {
758 759
759/* Chain noise (differential Rx gain) calib data */ 760/* Chain noise (differential Rx gain) calib data */
760struct iwl_chain_noise_data { 761struct iwl_chain_noise_data {
761 u8 state; 762 u32 active_chains;
762 u16 beacon_count;
763 u32 chain_noise_a; 763 u32 chain_noise_a;
764 u32 chain_noise_b; 764 u32 chain_noise_b;
765 u32 chain_noise_c; 765 u32 chain_noise_c;
766 u32 chain_signal_a; 766 u32 chain_signal_a;
767 u32 chain_signal_b; 767 u32 chain_signal_b;
768 u32 chain_signal_c; 768 u32 chain_signal_c;
769 u16 beacon_count;
769 u8 disconn_array[NUM_RX_CHAINS]; 770 u8 disconn_array[NUM_RX_CHAINS];
770 u8 delta_gain_code[NUM_RX_CHAINS]; 771 u8 delta_gain_code[NUM_RX_CHAINS];
771 u8 radio_write; 772 u8 radio_write;
773 u8 state;
772}; 774};
773 775
774#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ 776#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 16f834d0c486..bd6f600027d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -252,12 +252,21 @@ static int iwl_update_power_command(struct iwl_priv *priv,
252/* 252/*
253 * calucaute the final power mode index 253 * calucaute the final power mode index
254 */ 254 */
255int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) 255int iwl_power_update_mode(struct iwl_priv *priv, bool force)
256{ 256{
257 struct iwl_power_mgr *setting = &(priv->power_data); 257 struct iwl_power_mgr *setting = &(priv->power_data);
258 int ret = 0; 258 int ret = 0;
259 u16 uninitialized_var(final_mode); 259 u16 uninitialized_var(final_mode);
260 260
261 /* Don't update the RX chain when chain noise calibration is running */
262 if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE &&
263 priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) {
264 IWL_DEBUG_POWER("Cannot update the power, chain noise "
265 "calibration running: %d\n",
266 priv->chain_noise_data.state);
267 return -EAGAIN;
268 }
269
261 /* If on battery, set to 3, 270 /* If on battery, set to 3,
262 * if plugged into AC power, set to CAM ("continuously aware mode"), 271 * if plugged into AC power, set to CAM ("continuously aware mode"),
263 * else user level */ 272 * else user level */
@@ -285,7 +294,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
285 final_mode = IWL_POWER_MODE_CAM; 294 final_mode = IWL_POWER_MODE_CAM;
286 295
287 if (!iwl_is_rfkill(priv) && !setting->power_disabled && 296 if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
288 ((setting->power_mode != final_mode) || refresh)) { 297 ((setting->power_mode != final_mode) || force)) {
289 struct iwl_powertable_cmd cmd; 298 struct iwl_powertable_cmd cmd;
290 299
291 if (final_mode != IWL_POWER_MODE_CAM) 300 if (final_mode != IWL_POWER_MODE_CAM)
@@ -359,35 +368,26 @@ EXPORT_SYMBOL(iwl_power_enable_management);
359/* set user_power_setting */ 368/* set user_power_setting */
360int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) 369int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
361{ 370{
362 int ret = 0;
363
364 if (mode > IWL_POWER_LIMIT) 371 if (mode > IWL_POWER_LIMIT)
365 return -EINVAL; 372 return -EINVAL;
366 373
367 priv->power_data.user_power_setting = mode; 374 priv->power_data.user_power_setting = mode;
368 375
369 ret = iwl_power_update_mode(priv, 0); 376 return iwl_power_update_mode(priv, 0);
370
371 return ret;
372} 377}
373EXPORT_SYMBOL(iwl_power_set_user_mode); 378EXPORT_SYMBOL(iwl_power_set_user_mode);
374 379
375
376/* set system_power_setting. This should be set by over all 380/* set system_power_setting. This should be set by over all
377 * PM application. 381 * PM application.
378 */ 382 */
379int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) 383int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
380{ 384{
381 int ret = 0;
382
383 if (mode > IWL_POWER_LIMIT) 385 if (mode > IWL_POWER_LIMIT)
384 return -EINVAL; 386 return -EINVAL;
385 387
386 priv->power_data.system_power_setting = mode; 388 priv->power_data.system_power_setting = mode;
387 389
388 ret = iwl_power_update_mode(priv, 0); 390 return iwl_power_update_mode(priv, 0);
389
390 return ret;
391} 391}
392EXPORT_SYMBOL(iwl_power_set_system_mode); 392EXPORT_SYMBOL(iwl_power_set_system_mode);
393 393
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index aa99f3647def..a5c334f10e5d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -80,7 +80,7 @@ struct iwl_power_mgr {
80 80
81void iwl_setup_power_deferred_work(struct iwl_priv *priv); 81void iwl_setup_power_deferred_work(struct iwl_priv *priv);
82void iwl_power_cancel_timeout(struct iwl_priv *priv); 82void iwl_power_cancel_timeout(struct iwl_priv *priv);
83int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); 83int iwl_power_update_mode(struct iwl_priv *priv, bool force);
84int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); 84int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
85int iwl_power_enable_management(struct iwl_priv *priv); 85int iwl_power_enable_management(struct iwl_priv *priv);
86int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); 86int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);