aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGrumbach, Emmanuel <emmanuel.grumbach@intel.com>2008-09-02 23:26:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-11 15:53:31 -0400
commit04816448d8b77551834c9ea01e407ef5f0042f0f (patch)
treee3c1e019045e0d275f67f79b32ca3fae5e74c2ae /drivers
parent12837be1c127e6fba2e3f916a18fc202a9889af2 (diff)
iwlwifi: use the results from disconnected antenna algorithm
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>
Diffstat (limited to 'drivers')
-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);