aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-scan.c
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-01-22 17:22:43 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-25 16:36:19 -0500
commitafbdd69af0e6a0c40676d4d4b94a0a4414708eaa (patch)
tree08218339f6b9a3eb3ff690a9aa94777913fe4cba /drivers/net/wireless/iwlwifi/iwl-scan.c
parenta13d276f1e49ae0bc4ad18ce8ea3c90656c9e8d4 (diff)
iwlwifi: add function to reset/tune radio if needed
Adding "radio reset" function to help reset and stabilize the radio. During normal operation, sometime for unknown reason, radio encounter problem and can not recover by itself; the best way to recover from it is to reset and re-tune the radio. Currently, there is no RF reset command available, but since radio will get reset when switching channel, use internal hw scan request to force radio reset and get back to normal operation state. The internal hw scan will only perform passive scan on the first available channel (not the channel being used) in associated state. The request should be ignored if already performing scan operation or STA is not in associated state. Also include an "internal_scan" debugfs file to help trigger the internal scan from user mode. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c155
1 files changed, 141 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index ceb91f969e45..fd6bafbddfca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -314,6 +314,72 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
314} 314}
315EXPORT_SYMBOL(iwl_get_passive_dwell_time); 315EXPORT_SYMBOL(iwl_get_passive_dwell_time);
316 316
317static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
318 enum ieee80211_band band,
319 struct iwl_scan_channel *scan_ch)
320{
321 const struct ieee80211_supported_band *sband;
322 const struct iwl_channel_info *ch_info;
323 u16 passive_dwell = 0;
324 u16 active_dwell = 0;
325 int i, added = 0;
326 u16 channel = 0;
327
328 sband = iwl_get_hw_mode(priv, band);
329 if (!sband) {
330 IWL_ERR(priv, "invalid band\n");
331 return added;
332 }
333
334 active_dwell = iwl_get_active_dwell_time(priv, band, 0);
335 passive_dwell = iwl_get_passive_dwell_time(priv, band);
336
337 if (passive_dwell <= active_dwell)
338 passive_dwell = active_dwell + 1;
339
340 /* only scan single channel, good enough to reset the RF */
341 /* pick the first valid not in-use channel */
342 if (band == IEEE80211_BAND_5GHZ) {
343 for (i = 14; i < priv->channel_count; i++) {
344 if (priv->channel_info[i].channel !=
345 le16_to_cpu(priv->staging_rxon.channel)) {
346 channel = priv->channel_info[i].channel;
347 ch_info = iwl_get_channel_info(priv,
348 band, channel);
349 if (is_channel_valid(ch_info))
350 break;
351 }
352 }
353 } else {
354 for (i = 0; i < 14; i++) {
355 if (priv->channel_info[i].channel !=
356 le16_to_cpu(priv->staging_rxon.channel)) {
357 channel =
358 priv->channel_info[i].channel;
359 ch_info = iwl_get_channel_info(priv,
360 band, channel);
361 if (is_channel_valid(ch_info))
362 break;
363 }
364 }
365 }
366 if (channel) {
367 scan_ch->channel = cpu_to_le16(channel);
368 scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
369 scan_ch->active_dwell = cpu_to_le16(active_dwell);
370 scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
371 /* Set txpower levels to defaults */
372 scan_ch->dsp_atten = 110;
373 if (band == IEEE80211_BAND_5GHZ)
374 scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
375 else
376 scan_ch->tx_gain = ((1 << 5) | (5 << 3));
377 added++;
378 } else
379 IWL_ERR(priv, "no valid channel found\n");
380 return added;
381}
382
317static int iwl_get_channels_for_scan(struct iwl_priv *priv, 383static int iwl_get_channels_for_scan(struct iwl_priv *priv,
318 enum ieee80211_band band, 384 enum ieee80211_band band,
319 u8 is_active, u8 n_probes, 385 u8 is_active, u8 n_probes,
@@ -421,6 +487,7 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
421 487
422 IWL_DEBUG_INFO(priv, "Starting scan...\n"); 488 IWL_DEBUG_INFO(priv, "Starting scan...\n");
423 set_bit(STATUS_SCANNING, &priv->status); 489 set_bit(STATUS_SCANNING, &priv->status);
490 priv->is_internal_short_scan = false;
424 priv->scan_start = jiffies; 491 priv->scan_start = jiffies;
425 priv->scan_pass_start = priv->scan_start; 492 priv->scan_pass_start = priv->scan_start;
426 493
@@ -488,6 +555,45 @@ out_unlock:
488} 555}
489EXPORT_SYMBOL(iwl_mac_hw_scan); 556EXPORT_SYMBOL(iwl_mac_hw_scan);
490 557
558/*
559 * internal short scan, this function should only been called while associated.
560 * It will reset and tune the radio to prevent possible RF related problem
561 */
562int iwl_internal_short_hw_scan(struct iwl_priv *priv)
563{
564 int ret = 0;
565
566 if (!iwl_is_ready_rf(priv)) {
567 ret = -EIO;
568 IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
569 goto out;
570 }
571 if (test_bit(STATUS_SCANNING, &priv->status)) {
572 IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
573 ret = -EAGAIN;
574 goto out;
575 }
576 if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
577 IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n");
578 ret = -EAGAIN;
579 goto out;
580 }
581 priv->scan_bands = 0;
582 if (priv->band == IEEE80211_BAND_5GHZ)
583 priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
584 else
585 priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
586
587 IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
588 set_bit(STATUS_SCANNING, &priv->status);
589 priv->is_internal_short_scan = true;
590 queue_work(priv->workqueue, &priv->request_scan);
591
592out:
593 return ret;
594}
595EXPORT_SYMBOL(iwl_internal_short_hw_scan);
596
491#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) 597#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
492 598
493void iwl_bg_scan_check(struct work_struct *data) 599void iwl_bg_scan_check(struct work_struct *data)
@@ -551,7 +657,8 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
551 if (WARN_ON(left < ie_len)) 657 if (WARN_ON(left < ie_len))
552 return len; 658 return len;
553 659
554 memcpy(pos, ies, ie_len); 660 if (ies)
661 memcpy(pos, ies, ie_len);
555 len += ie_len; 662 len += ie_len;
556 left -= ie_len; 663 left -= ie_len;
557 664
@@ -654,7 +761,6 @@ static void iwl_bg_request_scan(struct work_struct *data)
654 unsigned long flags; 761 unsigned long flags;
655 762
656 IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); 763 IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
657
658 spin_lock_irqsave(&priv->lock, flags); 764 spin_lock_irqsave(&priv->lock, flags);
659 interval = priv->beacon_int; 765 interval = priv->beacon_int;
660 spin_unlock_irqrestore(&priv->lock, flags); 766 spin_unlock_irqrestore(&priv->lock, flags);
@@ -672,7 +778,9 @@ static void iwl_bg_request_scan(struct work_struct *data)
672 scan_suspend_time, interval); 778 scan_suspend_time, interval);
673 } 779 }
674 780
675 if (priv->scan_request->n_ssids) { 781 if (priv->is_internal_short_scan) {
782 IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
783 } else if (priv->scan_request->n_ssids) {
676 int i, p = 0; 784 int i, p = 0;
677 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); 785 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
678 for (i = 0; i < priv->scan_request->n_ssids; i++) { 786 for (i = 0; i < priv->scan_request->n_ssids; i++) {
@@ -753,24 +861,38 @@ static void iwl_bg_request_scan(struct work_struct *data)
753 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; 861 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
754 rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; 862 rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
755 scan->rx_chain = cpu_to_le16(rx_chain); 863 scan->rx_chain = cpu_to_le16(rx_chain);
756 cmd_len = iwl_fill_probe_req(priv, 864 if (!priv->is_internal_short_scan) {
757 (struct ieee80211_mgmt *)scan->data, 865 cmd_len = iwl_fill_probe_req(priv,
758 priv->scan_request->ie, 866 (struct ieee80211_mgmt *)scan->data,
759 priv->scan_request->ie_len, 867 priv->scan_request->ie,
760 IWL_MAX_SCAN_SIZE - sizeof(*scan)); 868 priv->scan_request->ie_len,
869 IWL_MAX_SCAN_SIZE - sizeof(*scan));
870 } else {
871 cmd_len = iwl_fill_probe_req(priv,
872 (struct ieee80211_mgmt *)scan->data,
873 NULL, 0,
874 IWL_MAX_SCAN_SIZE - sizeof(*scan));
761 875
876 }
762 scan->tx_cmd.len = cpu_to_le16(cmd_len); 877 scan->tx_cmd.len = cpu_to_le16(cmd_len);
763
764 if (iwl_is_monitor_mode(priv)) 878 if (iwl_is_monitor_mode(priv))
765 scan->filter_flags = RXON_FILTER_PROMISC_MSK; 879 scan->filter_flags = RXON_FILTER_PROMISC_MSK;
766 880
767 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | 881 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
768 RXON_FILTER_BCON_AWARE_MSK); 882 RXON_FILTER_BCON_AWARE_MSK);
769 883
770 scan->channel_count = 884 if (priv->is_internal_short_scan) {
771 iwl_get_channels_for_scan(priv, band, is_active, n_probes, 885 scan->channel_count =
772 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 886 iwl_get_single_channel_for_scan(priv, band,
773 887 (void *)&scan->data[le16_to_cpu(
888 scan->tx_cmd.len)]);
889 } else {
890 scan->channel_count =
891 iwl_get_channels_for_scan(priv, band,
892 is_active, n_probes,
893 (void *)&scan->data[le16_to_cpu(
894 scan->tx_cmd.len)]);
895 }
774 if (scan->channel_count == 0) { 896 if (scan->channel_count == 0) {
775 IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); 897 IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
776 goto done; 898 goto done;
@@ -831,7 +953,12 @@ void iwl_bg_scan_completed(struct work_struct *work)
831 953
832 cancel_delayed_work(&priv->scan_check); 954 cancel_delayed_work(&priv->scan_check);
833 955
834 ieee80211_scan_completed(priv->hw, false); 956 if (!priv->is_internal_short_scan)
957 ieee80211_scan_completed(priv->hw, false);
958 else {
959 priv->is_internal_short_scan = false;
960 IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
961 }
835 962
836 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 963 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
837 return; 964 return;