aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-09-20 18:37:22 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-21 16:19:42 -0400
commit390808db4ab5c658dc1eb8078d82027ce7d0ea78 (patch)
tree4e584861dfdd93b6ace23b63e10678b7e7f0042e
parentc68929060181eb088bef252c5f493a66a44e77b1 (diff)
iwlagn: split remain-on-channel
If we're associated and want to do P2P at the same time, the scan for remain-on-channel is currently limited to 80ms because of the way the device will behave in that case. Instead of doing that, split up the dwell times into little pieces. It will not actually be a single big dwell time then, but will be close enough. This improves robustness of P2P in such scenarios. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c99
3 files changed, 62 insertions, 49 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index fcfb410aca90..baaf48616cc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2770,15 +2770,6 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
2770 2770
2771 mutex_lock(&priv->shrd->mutex); 2771 mutex_lock(&priv->shrd->mutex);
2772 2772
2773 /*
2774 * TODO: Remove this hack! Firmware needs to be updated
2775 * to allow longer off-channel periods in scanning for
2776 * this use case, based on a flag (and we'll need an API
2777 * flag in the firmware when it has that).
2778 */
2779 if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && duration > 80)
2780 duration = 80;
2781
2782 if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { 2773 if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
2783 err = -EBUSY; 2774 err = -EBUSY;
2784 goto out; 2775 goto out;
@@ -2787,6 +2778,7 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
2787 priv->hw_roc_channel = channel; 2778 priv->hw_roc_channel = channel;
2788 priv->hw_roc_chantype = channel_type; 2779 priv->hw_roc_chantype = channel_type;
2789 priv->hw_roc_duration = duration; 2780 priv->hw_roc_duration = duration;
2781 priv->hw_roc_start_notified = false;
2790 cancel_delayed_work(&priv->hw_roc_disable_work); 2782 cancel_delayed_work(&priv->hw_roc_disable_work);
2791 2783
2792 if (!ctx->is_active) { 2784 if (!ctx->is_active) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index fabfc8bf4971..7f534c45d1fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1029,7 +1029,7 @@ struct iwl_priv {
1029 struct delayed_work hw_roc_disable_work; 1029 struct delayed_work hw_roc_disable_work;
1030 enum nl80211_channel_type hw_roc_chantype; 1030 enum nl80211_channel_type hw_roc_chantype;
1031 int hw_roc_duration; 1031 int hw_roc_duration;
1032 bool hw_roc_setup; 1032 bool hw_roc_setup, hw_roc_start_notified;
1033 1033
1034 /* bt coex */ 1034 /* bt coex */
1035 u8 bt_enable_flag; 1035 u8 bt_enable_flag;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 8ac6b05c6c78..8386a86e2ca2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -218,8 +218,11 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
218 le32_to_cpu(notif->tsf_low), 218 le32_to_cpu(notif->tsf_low),
219 notif->status, notif->beacon_timer); 219 notif->status, notif->beacon_timer);
220 220
221 if (priv->scan_type == IWL_SCAN_ROC) 221 if (priv->scan_type == IWL_SCAN_ROC &&
222 !priv->hw_roc_start_notified) {
222 ieee80211_ready_on_channel(priv->hw); 223 ieee80211_ready_on_channel(priv->hw);
224 priv->hw_roc_start_notified = true;
225 }
223} 226}
224 227
225/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ 228/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -310,34 +313,38 @@ static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
310 IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); 313 IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
311} 314}
312 315
316static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
317{
318 struct iwl_rxon_context *ctx;
319
320 /*
321 * If we're associated, we clamp the dwell time 98%
322 * of the smallest beacon interval (minus 2 * channel
323 * tune time)
324 */
325 for_each_context(priv, ctx) {
326 u16 value;
327
328 if (!iwl_is_associated_ctx(ctx))
329 continue;
330 value = ctx->beacon_int;
331 if (!value)
332 value = IWL_PASSIVE_DWELL_BASE;
333 value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
334 dwell_time = min(value, dwell_time);
335 }
336
337 return dwell_time;
338}
339
313static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, 340static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
314 enum ieee80211_band band) 341 enum ieee80211_band band)
315{ 342{
316 struct iwl_rxon_context *ctx;
317 u16 passive = (band == IEEE80211_BAND_2GHZ) ? 343 u16 passive = (band == IEEE80211_BAND_2GHZ) ?
318 IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : 344 IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
319 IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; 345 IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
320 346
321 if (iwl_is_any_associated(priv)) { 347 return iwl_limit_dwell(priv, passive);
322 /*
323 * If we're associated, we clamp the maximum passive
324 * dwell time to be 98% of the smallest beacon interval
325 * (minus 2 * channel tune time)
326 */
327 for_each_context(priv, ctx) {
328 u16 value;
329
330 if (!iwl_is_associated_ctx(ctx))
331 continue;
332 value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
333 if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
334 value = IWL_PASSIVE_DWELL_BASE;
335 value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
336 passive = min(value, passive);
337 }
338 }
339
340 return passive;
341} 348}
342 349
343static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, 350static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
@@ -716,29 +723,43 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
716 break; 723 break;
717 case IWL_SCAN_ROC: { 724 case IWL_SCAN_ROC: {
718 struct iwl_scan_channel *scan_ch; 725 struct iwl_scan_channel *scan_ch;
726 int n_chan, i;
727 u16 dwell;
728
729 dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
730 n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
719 731
720 scan->channel_count = 1; 732 scan->channel_count = n_chan;
721 733
722 scan_ch = (void *)&scan->data[cmd_len]; 734 scan_ch = (void *)&scan->data[cmd_len];
723 scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
724 scan_ch->channel =
725 cpu_to_le16(priv->hw_roc_channel->hw_value);
726 scan_ch->active_dwell =
727 scan_ch->passive_dwell =
728 cpu_to_le16(priv->hw_roc_duration);
729 735
730 /* Set txpower levels to defaults */ 736 for (i = 0; i < n_chan; i++) {
731 scan_ch->dsp_atten = 110; 737 scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
738 scan_ch->channel =
739 cpu_to_le16(priv->hw_roc_channel->hw_value);
732 740
733 /* NOTE: if we were doing 6Mb OFDM for scans we'd use 741 if (i == n_chan - 1)
734 * power level: 742 dwell = priv->hw_roc_duration - i * dwell;
735 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; 743
736 */ 744 scan_ch->active_dwell =
737 if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ) 745 scan_ch->passive_dwell = cpu_to_le16(dwell);
738 scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; 746
739 else 747 /* Set txpower levels to defaults */
740 scan_ch->tx_gain = ((1 << 5) | (5 << 3)); 748 scan_ch->dsp_atten = 110;
749
750 /* NOTE: if we were doing 6Mb OFDM for scans we'd use
751 * power level:
752 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
753 */
754 if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
755 scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
756 else
757 scan_ch->tx_gain = ((1 << 5) | (5 << 3));
758
759 scan_ch++;
741 } 760 }
761 }
762
742 break; 763 break;
743 } 764 }
744 765