/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", scan_notif->scanned_channels, scan_notif->tsf_low, scan_notif->tsf_high, scan_notif->status); #endif /* The HW is no longer scanning */ clear_bit(STATUS_SCAN_HW, &priv->status); IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n", (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", jiffies_to_msecs(elapsed_jiffies (priv->scan_start, jiffies))); /* * If a request to abort was given, or the scan did not succeed * then we reset the scan state machine and terminate, * re-queuing another scan if one has been requested */ if (test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status)) IWL_DEBUG_INFO(priv, "Aborted scan completed.\n"); IWL_DEBUG_INFO(priv, "Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); queue_work(priv->workqueue, &priv->scan_completed); }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret = 0; struct iwl_rx_packet *res; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, }; /* If there isn't a scan actively going on in the hardware * then we are in between scan bands and not actually * actively scanning, so don't send the abort command */ if (!test_bit(STATUS_SCAN_HW, &priv->status)) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return 0; } ret = iwl_send_cmd_sync(priv, &cmd); if (ret) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return ret; } res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be * due to simply not being in an active scan which * can occur if we send the scan abort before we * the microcode has notified us that a scan is * completed. */ IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); } priv->alloc_rxb_skb--; dev_kfree_skb_any(cmd.meta.u.skb); return ret; } /* Service response to REPLY_SCAN_CMD (0x80) */ static void iwl_rx_reply_scan(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_scanreq_notification *notif = (struct iwl_scanreq_notification *)pkt->u.raw; IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); #endif } /* Service SCAN_START_NOTIFICATION (0x82) */ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_scanstart_notification *notif = (struct iwl_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); IWL_DEBUG_SCAN("Scan start: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", notif->channel, notif->band ? "bg" : "a", le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), notif->status, notif->beacon_timer); } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_scanresults_notification *notif = (struct iwl_scanresults_notification *)pkt->u.raw; IWL_DEBUG_SCAN("Scan ch.res: " "%d [802.11%s] " "(TSF: 0x%08X:%08X) - %d " "elapsed=%lu usec (%dms since last)\n", notif->channel, notif->band ? "bg" : "a", le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), le32_to_cpu(notif->statistics[0]), le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, jiffies_to_msecs(elapsed_jiffies (priv->last_scan_jiffies, jiffies))); #endif priv->last_scan_jiffies = jiffies; priv->next_scan_jiffies = 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", scan_notif->scanned_channels, scan_notif->tsf_low, scan_notif->tsf_high, scan_notif->status); #endif /* The HW is no longer scanning */ clear_bit(STATUS_SCAN_HW, &priv->status); /* The scan completion notification came in, so kill that timer... */ cancel_delayed_work(&priv->scan_check); IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? "2.4" : "5.2", jiffies_to_msecs(elapsed_jiffies (priv->scan_pass_start, jiffies))); /* Remove this scanned band from the list of pending * bands to scan, band G precedes A in order of scanning * as seen in iwl_bg_request_scan */ if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ); else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ); /* If a request to abort was given, or the scan did not succeed * then we reset the scan state machine and terminate, * re-queuing another scan if one has been requested */ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { IWL_DEBUG_INFO("Aborted scan completed.\n"); clear_bit(STATUS_SCAN_ABORTING, &priv->status); } else { /* If there are more bands on this scan pass reschedule */ if (priv->scan_bands) goto reschedule; } priv->last_scan_jiffies = jiffies; priv->next_scan_jiffies = 0; IWL_DEBUG_INFO("Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); IWL_DEBUG_INFO("Scan took %dms\n", jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); queue_work(priv->workqueue, &priv->scan_completed); return; reschedule: priv->scan_pass_start = jiffies; queue_work(priv->workqueue, &priv->request_scan); } void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) { /* scan handlers */ priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = iwl_rx_scan_results_notif; priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = iwl_rx_scan_complete_notif; }