aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c155
6 files changed, 193 insertions, 14 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index bb3ed25f8438..645bc133577a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -3343,6 +3343,30 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
3343} 3343}
3344EXPORT_SYMBOL(iwl_dump_fh); 3344EXPORT_SYMBOL(iwl_dump_fh);
3345 3345
3346void iwl_force_rf_reset(struct iwl_priv *priv)
3347{
3348 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
3349 return;
3350
3351 if (!iwl_is_associated(priv)) {
3352 IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
3353 return;
3354 }
3355 /*
3356 * There is no easy and better way to force reset the radio,
3357 * the only known method is switching channel which will force to
3358 * reset and tune the radio.
3359 * Use internal short scan (single channel) operation to should
3360 * achieve this objective.
3361 * Driver should reset the radio when number of consecutive missed
3362 * beacon, or any other uCode error condition detected.
3363 */
3364 IWL_DEBUG_INFO(priv, "perform radio reset.\n");
3365 iwl_internal_short_hw_scan(priv);
3366 return;
3367}
3368EXPORT_SYMBOL(iwl_force_rf_reset);
3369
3346#ifdef CONFIG_PM 3370#ifdef CONFIG_PM
3347 3371
3348int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) 3372int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 785331a98aa5..6de83d1e1eb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -494,6 +494,8 @@ void iwl_init_scan_params(struct iwl_priv *priv);
494int iwl_scan_cancel(struct iwl_priv *priv); 494int iwl_scan_cancel(struct iwl_priv *priv);
495int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); 495int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
496int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); 496int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
497int iwl_internal_short_hw_scan(struct iwl_priv *priv);
498void iwl_force_rf_reset(struct iwl_priv *priv);
497u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, 499u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
498 const u8 *ie, int ie_len, int left); 500 const u8 *ie, int ie_len, int left);
499void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); 501void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 36b558f23325..d81b4f39bb1d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -113,6 +113,7 @@ struct iwl_debugfs {
113 struct dentry *file_ucode_tracing; 113 struct dentry *file_ucode_tracing;
114 struct dentry *file_fh_reg; 114 struct dentry *file_fh_reg;
115 struct dentry *file_missed_beacon; 115 struct dentry *file_missed_beacon;
116 struct dentry *file_internal_scan;
116 } dbgfs_debug_files; 117 } dbgfs_debug_files;
117 u32 sram_offset; 118 u32 sram_offset;
118 u32 sram_len; 119 u32 sram_len;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 02f80bc21307..4944fdb31ba8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -2174,6 +2174,27 @@ static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
2174 return count; 2174 return count;
2175} 2175}
2176 2176
2177static ssize_t iwl_dbgfs_internal_scan_write(struct file *file,
2178 const char __user *user_buf,
2179 size_t count, loff_t *ppos)
2180{
2181 struct iwl_priv *priv = file->private_data;
2182 char buf[8];
2183 int buf_size;
2184 int scan;
2185
2186 memset(buf, 0, sizeof(buf));
2187 buf_size = min(count, sizeof(buf) - 1);
2188 if (copy_from_user(buf, user_buf, buf_size))
2189 return -EFAULT;
2190 if (sscanf(buf, "%d", &scan) != 1)
2191 return -EINVAL;
2192
2193 iwl_internal_short_hw_scan(priv);
2194
2195 return count;
2196}
2197
2177DEBUGFS_READ_FILE_OPS(rx_statistics); 2198DEBUGFS_READ_FILE_OPS(rx_statistics);
2178DEBUGFS_READ_FILE_OPS(tx_statistics); 2199DEBUGFS_READ_FILE_OPS(tx_statistics);
2179DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); 2200DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -2192,6 +2213,7 @@ DEBUGFS_WRITE_FILE_OPS(csr);
2192DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); 2213DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
2193DEBUGFS_READ_FILE_OPS(fh_reg); 2214DEBUGFS_READ_FILE_OPS(fh_reg);
2194DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); 2215DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
2216DEBUGFS_WRITE_FILE_OPS(internal_scan);
2195 2217
2196/* 2218/*
2197 * Create the debugfs files and directories 2219 * Create the debugfs files and directories
@@ -2245,6 +2267,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
2245 DEBUGFS_ADD_FILE(csr, debug, S_IWUSR); 2267 DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
2246 DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR); 2268 DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR);
2247 DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR); 2269 DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR);
2270 DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR);
2248 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { 2271 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
2249 DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR); 2272 DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
2250 DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR); 2273 DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
@@ -2306,6 +2329,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
2306 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr); 2329 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
2307 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg); 2330 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg);
2308 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon); 2331 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon);
2332 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan);
2309 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) { 2333 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
2310 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files. 2334 DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
2311 file_ucode_rx_stats); 2335 file_ucode_rx_stats);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 5e06e666f176..502d7a6b0904 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1080,6 +1080,7 @@ struct iwl_priv {
1080 void *scan; 1080 void *scan;
1081 int scan_bands; 1081 int scan_bands;
1082 struct cfg80211_scan_request *scan_request; 1082 struct cfg80211_scan_request *scan_request;
1083 bool is_internal_short_scan;
1083 u8 scan_tx_ant[IEEE80211_NUM_BANDS]; 1084 u8 scan_tx_ant[IEEE80211_NUM_BANDS];
1084 u8 mgmt_tx_ant; 1085 u8 mgmt_tx_ant;
1085 1086
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;