diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-calib.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 35 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-power.h | 2 |
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 | } |
843 | EXPORT_SYMBOL(iwl_chain_noise_calibration); | 850 | EXPORT_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 */ | ||
744 | static 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 | ||
700 | enum iwl4965_chain_noise_state { | 700 | enum 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 | ||
706 | enum iwl4965_calib_enabled_state { | 707 | enum 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 */ |
760 | struct iwl_chain_noise_data { | 761 | struct 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 | */ |
255 | int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh) | 255 | int 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 */ |
360 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode) | 369 | int 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 | } |
373 | EXPORT_SYMBOL(iwl_power_set_user_mode); | 378 | EXPORT_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 | */ |
379 | int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) | 383 | int 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 | } |
392 | EXPORT_SYMBOL(iwl_power_set_system_mode); | 392 | EXPORT_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 | ||
81 | void iwl_setup_power_deferred_work(struct iwl_priv *priv); | 81 | void iwl_setup_power_deferred_work(struct iwl_priv *priv); |
82 | void iwl_power_cancel_timeout(struct iwl_priv *priv); | 82 | void iwl_power_cancel_timeout(struct iwl_priv *priv); |
83 | int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); | 83 | int iwl_power_update_mode(struct iwl_priv *priv, bool force); |
84 | int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); | 84 | int iwl_power_disable_management(struct iwl_priv *priv, u32 ms); |
85 | int iwl_power_enable_management(struct iwl_priv *priv); | 85 | int iwl_power_enable_management(struct iwl_priv *priv); |
86 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); | 86 | int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); |