aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2008-09-02 23:26:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-08 14:23:19 -0400
commitc90a74bae10dc2a4677d1bd06b6400db229d3e1e (patch)
treeb1cadc8cc67b4768a60fb566ebda091364d2b044
parente7b635814b640c6fd9dca1c254dc22fac6fb9a1a (diff)
iwlwifi: allow association on radar channel in power save
This patch disables power save upon association and enables it back after association. This allows to associate to AP on a radar channel if power save is enabled. Radar and passive channels are not allowed for TX (required for association) unless RX is received but PS may close the radio and no RX will be received effectively failing association. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Mohamed Abbas <mohamed.abbas@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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h4
4 files changed, 61 insertions, 7 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 250473138f30..ab92e19f0b6c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2486,6 +2486,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
2486 if (!priv->vif || !priv->is_open) 2486 if (!priv->vif || !priv->is_open)
2487 return; 2487 return;
2488 2488
2489 iwl_power_cancel_timeout(priv);
2489 iwl_scan_cancel_timeout(priv, 200); 2490 iwl_scan_cancel_timeout(priv, 200);
2490 2491
2491 conf = ieee80211_get_hw_conf(priv->hw); 2492 conf = ieee80211_get_hw_conf(priv->hw);
@@ -2550,10 +2551,6 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
2550 break; 2551 break;
2551 } 2552 }
2552 2553
2553 /* Enable Rx differential gain and sensitivity calibrations */
2554 iwl_chain_noise_reset(priv);
2555 priv->start_calib = 1;
2556
2557 if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) 2554 if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
2558 priv->assoc_station_added = 1; 2555 priv->assoc_station_added = 1;
2559 2556
@@ -2561,7 +2558,12 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
2561 iwl_activate_qos(priv, 0); 2558 iwl_activate_qos(priv, 0);
2562 spin_unlock_irqrestore(&priv->lock, flags); 2559 spin_unlock_irqrestore(&priv->lock, flags);
2563 2560
2564 iwl_power_update_mode(priv, 0); 2561 iwl_power_enable_management(priv);
2562
2563 /* Enable Rx differential gain and sensitivity calibrations */
2564 iwl_chain_noise_reset(priv);
2565 priv->start_calib = 1;
2566
2565 /* we have just associated, don't start scan too early */ 2567 /* we have just associated, don't start scan too early */
2566 priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; 2568 priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
2567} 2569}
@@ -3535,6 +3537,16 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
3535 /* Per mac80211.h: This is only used in IBSS mode... */ 3537 /* Per mac80211.h: This is only used in IBSS mode... */
3536 if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) { 3538 if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
3537 3539
3540 /* switch to CAM during association period.
3541 * the ucode will block any association/authentication
3542 * frome during assiciation period if it can not hear
3543 * the AP because of PM. the timer enable PM back is
3544 * association do not complete
3545 */
3546 if (priv->hw->conf.channel->flags & (IEEE80211_CHAN_PASSIVE_SCAN |
3547 IEEE80211_CHAN_RADAR))
3548 iwl_power_disable_management(priv, 3000);
3549
3538 IWL_DEBUG_MAC80211("leave - not in IBSS\n"); 3550 IWL_DEBUG_MAC80211("leave - not in IBSS\n");
3539 mutex_unlock(&priv->mutex); 3551 mutex_unlock(&priv->mutex);
3540 return; 3552 return;
@@ -4087,6 +4099,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
4087 /* FIXME : remove when resolved PENDING */ 4099 /* FIXME : remove when resolved PENDING */
4088 INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); 4100 INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
4089 iwl_setup_scan_deferred_work(priv); 4101 iwl_setup_scan_deferred_work(priv);
4102 iwl_setup_power_deferred_work(priv);
4090 4103
4091 if (priv->cfg->ops->lib->setup_deferred_work) 4104 if (priv->cfg->ops->lib->setup_deferred_work)
4092 priv->cfg->ops->lib->setup_deferred_work(priv); 4105 priv->cfg->ops->lib->setup_deferred_work(priv);
@@ -4106,6 +4119,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
4106 4119
4107 cancel_delayed_work_sync(&priv->init_alive_start); 4120 cancel_delayed_work_sync(&priv->init_alive_start);
4108 cancel_delayed_work(&priv->scan_check); 4121 cancel_delayed_work(&priv->scan_check);
4122 cancel_delayed_work_sync(&priv->set_power_save);
4109 cancel_delayed_work(&priv->alive_start); 4123 cancel_delayed_work(&priv->alive_start);
4110 cancel_work_sync(&priv->beacon_update); 4124 cancel_work_sync(&priv->beacon_update);
4111 del_timer_sync(&priv->statistics_periodic); 4125 del_timer_sync(&priv->statistics_periodic);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 5a55c876917d..edf3d0f3f9c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1024,6 +1024,7 @@ struct iwl_priv {
1024 1024
1025 struct tasklet_struct irq_tasklet; 1025 struct tasklet_struct irq_tasklet;
1026 1026
1027 struct delayed_work set_power_save;
1027 struct delayed_work init_alive_start; 1028 struct delayed_work init_alive_start;
1028 struct delayed_work alive_start; 1029 struct delayed_work alive_start;
1029 struct delayed_work scan_check; 1030 struct delayed_work scan_check;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index eb6312d867d1..16f834d0c486 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -319,7 +319,7 @@ EXPORT_SYMBOL(iwl_power_update_mode);
319 * this will be usefull for rate scale to disable PM during heavy 319 * this will be usefull for rate scale to disable PM during heavy
320 * Tx/Rx activities 320 * Tx/Rx activities
321 */ 321 */
322int iwl_power_disable_management(struct iwl_priv *priv) 322int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
323{ 323{
324 u16 prev_mode; 324 u16 prev_mode;
325 int ret = 0; 325 int ret = 0;
@@ -332,6 +332,11 @@ int iwl_power_disable_management(struct iwl_priv *priv)
332 ret = iwl_power_update_mode(priv, 0); 332 ret = iwl_power_update_mode(priv, 0);
333 priv->power_data.power_disabled = 1; 333 priv->power_data.power_disabled = 1;
334 priv->power_data.user_power_setting = prev_mode; 334 priv->power_data.user_power_setting = prev_mode;
335 cancel_delayed_work(&priv->set_power_save);
336 if (ms)
337 queue_delayed_work(priv->workqueue, &priv->set_power_save,
338 msecs_to_jiffies(ms));
339
335 340
336 return ret; 341 return ret;
337} 342}
@@ -426,3 +431,35 @@ int iwl_power_temperature_change(struct iwl_priv *priv)
426 return ret; 431 return ret;
427} 432}
428EXPORT_SYMBOL(iwl_power_temperature_change); 433EXPORT_SYMBOL(iwl_power_temperature_change);
434
435static void iwl_bg_set_power_save(struct work_struct *work)
436{
437 struct iwl_priv *priv = container_of(work,
438 struct iwl_priv, set_power_save.work);
439 IWL_DEBUG(IWL_DL_STATE, "update power\n");
440
441 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
442 return;
443
444 mutex_lock(&priv->mutex);
445
446 /* on starting association we disable power managment
447 * until association, if association failed then this
448 * timer will expire and enable PM again.
449 */
450 if (!iwl_is_associated(priv))
451 iwl_power_enable_management(priv);
452
453 mutex_unlock(&priv->mutex);
454}
455void iwl_setup_power_deferred_work(struct iwl_priv *priv)
456{
457 INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
458}
459EXPORT_SYMBOL(iwl_setup_power_deferred_work);
460
461void iwl_power_cancel_timeout(struct iwl_priv *priv)
462{
463 cancel_delayed_work(&priv->set_power_save);
464}
465EXPORT_SYMBOL(iwl_power_cancel_timeout);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index abcbbf96a84e..aa99f3647def 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -78,8 +78,10 @@ struct iwl_power_mgr {
78 u8 power_disabled; /* flag to disable using power saving level */ 78 u8 power_disabled; /* flag to disable using power saving level */
79}; 79};
80 80
81void iwl_setup_power_deferred_work(struct iwl_priv *priv);
82void iwl_power_cancel_timeout(struct iwl_priv *priv);
81int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh); 83int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh);
82int iwl_power_disable_management(struct iwl_priv *priv); 84int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
83int iwl_power_enable_management(struct iwl_priv *priv); 85int iwl_power_enable_management(struct iwl_priv *priv);
84int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode); 86int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
85int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode); 87int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode);