void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); bool internal = false; IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); cancel_delayed_work(&priv->scan_check); mutex_lock(&priv->mutex); if (priv->is_internal_short_scan) { priv->is_internal_short_scan = false; IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); internal = true; } mutex_unlock(&priv->mutex); /* * Do not hold mutex here since this will cause mac80211 to call * into driver again into functions that will attempt to take * mutex. */ if (!internal) ieee80211_scan_completed(priv->hw, false); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; /* Since setting the TXPOWER may have been deferred while * performing the scan, fire one off */ mutex_lock(&priv->mutex); iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); mutex_unlock(&priv->mutex); }
static int wl1271_event_scan_complete(struct wl1271 *wl, struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { /* 2.4 GHz band scanned, scan 5 GHz band, pretend * to the wl1271_cmd_scan function that we are not * scanning as it checks that. */ clear_bit(WL1271_FLAG_SCANNING, &wl->flags); /* FIXME: ie missing! */ wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, NULL, 0, wl->scan.active, wl->scan.high_prio, WL1271_SCAN_BAND_5_GHZ, wl->scan.probe_requests); } else { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); clear_bit(WL1271_FLAG_SCANNING, &wl->flags); } } return 0; }
int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) { int ret; struct iwl_notification_wait wait_scan_done; static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED; lockdep_assert_held(&mvm->mutex); if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN, notify); if (mvm->scan_status == IWL_MVM_SCAN_NONE) return 0; if (iwl_mvm_is_radio_killed(mvm)) { ret = 0; goto out; } iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, scan_done_notif, ARRAY_SIZE(scan_done_notif), NULL, NULL); ret = iwl_mvm_send_scan_offload_abort(mvm); if (ret) { IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n", sched ? "offloaded " : "", ret); iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); goto out; } IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n", sched ? "offloaded " : ""); ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); out: /* * Clear the scan status so the next scan requests will succeed. This * also ensures the Rx handler doesn't do anything, as the scan was * stopped from above. Since the rx handler won't do anything now, * we have to release the scan reference here. */ if (mvm->scan_status == IWL_MVM_SCAN_OS) iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); mvm->scan_status = IWL_MVM_SCAN_NONE; if (notify) { if (sched) ieee80211_sched_scan_stopped(mvm->hw); else ieee80211_scan_completed(mvm->hw, true); } return ret; }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (unlikely(wl->state != WLCORE_STATE_ON)) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; vif = wl->scan_vif; wlvif = wl12xx_vif_to_data(vif); /* * Rearm the tx watchdog just before idling scan. This * prevents just-finished scans from triggering the watchdog */ wl12xx_rearm_tx_watchdog_locked(wl); wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } wlcore_cmd_regdomain_config_locked(wl); ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
static void wl1251_op_stop(struct ieee80211_hw *hw) { struct wl1251 *wl = hw->priv; wl1251_info("down"); wl1251_debug(DEBUG_MAC80211, "mac80211 stop"); mutex_lock(&wl->mutex); WARN_ON(wl->state != WL1251_STATE_ON); if (wl->scanning) { ieee80211_scan_completed(wl->hw, true); wl->scanning = false; } wl->state = WL1251_STATE_OFF; wl1251_disable_interrupts(wl); mutex_unlock(&wl->mutex); cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->ps_work); cancel_delayed_work_sync(&wl->elp_work); mutex_lock(&wl->mutex); /* let's notify MAC80211 about the remaining pending TX frames */ wl1251_tx_flush(wl); wl1251_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); wl->listen_int = 1; wl->bss_type = MAX_BSS_TYPE; wl->data_in_count = 0; wl->rx_counter = 0; wl->rx_handled = 0; wl->rx_current_buffer = 0; wl->rx_last_id = 0; wl->next_tx_complete = 0; wl->elp = false; wl->station_mode = STATION_ACTIVE_MODE; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; wl->channel = WL1251_DEFAULT_CHANNEL; wl->monitor_present = false; wl->joined = false; wl->long_doze_mode_set = false; wl1251_debugfs_reset(wl); mutex_unlock(&wl->mutex); }
static void wl1271_op_stop(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; int i; wl1271_info("down"); wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); mutex_lock(&wl->mutex); WARN_ON(wl->state != WL1271_STATE_ON); if (wl->scanning) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, true); mutex_lock(&wl->mutex); wl->scanning = false; } wl->state = WL1271_STATE_OFF; wl1271_disable_interrupts(wl); mutex_unlock(&wl->mutex); cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); cancel_work_sync(&wl->filter_work); mutex_lock(&wl->mutex); wl1271_tx_flush(wl); wl1271_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); wl->ssid_len = 0; wl->listen_int = 1; wl->bss_type = MAX_BSS_TYPE; wl->rx_counter = 0; wl->elp = false; wl->psm = 0; wl->tx_queue_stopped = false; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; wl->time_offset = 0; wl->session_counter = 0; for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; wl1271_debugfs_reset(wl); mutex_unlock(&wl->mutex); }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; int ret; bool is_sta, is_ibss; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { /* restore hardware connection monitoring template */ wl1271_cmd_build_ap_probe_req(wl, wl->probereq); } /* return to ROC if needed */ is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); is_ibss = (wl->bss_type == BSS_TYPE_IBSS); if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && !test_bit(wl->dev_role_id, wl->roc_map)) { /* restore remain on channel */ wl12xx_cmd_role_start_dev(wl); wl12xx_roc(wl, wl->dev_role_id); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; vif = wl->scan_vif; wlvif = wl12xx_vif_to_data(vif); wl12xx_rearm_tx_watchdog_locked(wl); wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; wl->scan_vif = NULL; ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) { wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq); } wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } ieee80211_scan_completed(wl->hw, false); out: mutex_unlock(&wl->mutex); }
static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { /* check if scan was requested from mac80211 */ if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); ieee80211_scan_completed(priv->hw, aborted); } priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; }
static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { if (wl->scanning) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw); mutex_lock(&wl->mutex); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; } return 0; }
void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); bool internal = false; IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); cancel_delayed_work(&priv->scan_check); mutex_lock(&priv->mutex); if (priv->is_internal_short_scan) { priv->is_internal_short_scan = false; IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); internal = true; } else { priv->scan_request = NULL; priv->scan_vif = NULL; } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) goto out; if (internal && priv->scan_request) iwl_scan_initiate(priv, priv->scan_vif); /* Since setting the TXPOWER may have been deferred while * performing the scan, fire one off */ iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); /* * Since setting the RXON may have been deferred while * performing the scan, fire one off if needed */ if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) iwlcore_commit_rxon(priv); out: mutex_unlock(&priv->mutex); /* * Do not hold mutex here since this will cause mac80211 to call * into driver again into functions that will attempt to take * mutex. */ if (!internal) ieee80211_scan_completed(priv->hw, false); }
static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", mbox->scheduled_scan_status, mbox->scheduled_scan_channels); if (wl->scanning) { ieee80211_scan_completed(wl->hw, false); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; } return 0; }
static int wl1271_event_scan_complete(struct wl1271 *wl, struct event_mailbox *mbox) { wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); if (wl->scanning) { mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); wl->scanning = false; } return 0; }
static int wl1251_event_scan_complete(struct wl1251 *wl, struct event_mailbox *mbox) { int ret = 0; wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d", mbox->scheduled_scan_status, mbox->scheduled_scan_channels); if (wl->scanning) { ieee80211_scan_completed(wl->hw, false); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl->scanning = false; if (wl->hw->conf.flags & IEEE80211_CONF_IDLE) ret = wl1251_ps_set_mode(wl, STATION_IDLE); } return ret; }
void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); wl1271_debug(DEBUG_SCAN, "Scanning complete"); mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) goto out; if (wl->scan.state == WL1271_SCAN_STATE_IDLE) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, false); /* restore hardware connection monitoring template */ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { if (wl1271_ps_elp_wakeup(wl) == 0) { wl1271_cmd_build_ap_probe_req(wl, wl->probereq); wl1271_ps_elp_sleep(wl); } } if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } out: mutex_unlock(&wl->mutex); }
static int wl1271_event_scan_complete(struct wl1271 *wl, struct event_mailbox *mbox) { int size = sizeof(struct wl12xx_probe_req_template); wl1271_debug(DEBUG_EVENT, "status: 0x%x", mbox->scheduled_scan_status); if (wl->scanning) { if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); /* 2.4 GHz band scanned, scan 5 GHz band, pretend * to the wl1271_cmd_scan function that we are not * scanning as it checks that. */ wl->scanning = false; wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.active, wl->scan.high_prio, WL1271_SCAN_BAND_5_GHZ, wl->scan.probe_requests); } else { if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ) wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, size); else wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, NULL, size); mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); wl->scanning = false; } } return 0; }
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_periodic_scan_complete *scan_notif; scan_notif = (void *)pkt->data; /* scan status must be locked for proper checking */ lockdep_assert_held(&mvm->mutex); IWL_DEBUG_SCAN(mvm, "%s completed, status %s, EBS status %s\n", mvm->scan_status == IWL_MVM_SCAN_SCHED ? "Scheduled scan" : "Scan", scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? "completed" : "aborted", scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? "success" : "failed"); /* only call mac80211 completion if the stop was initiated by FW */ if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_sched_scan_stopped(mvm->hw); } else if (mvm->scan_status == IWL_MVM_SCAN_OS) { mvm->scan_status = IWL_MVM_SCAN_NONE; ieee80211_scan_completed(mvm->hw, scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); } if (scan_notif->ebs_status) mvm->last_ebs_successful = false; return 0; }
void wl1271_scan_stm(struct wl1271 *wl) { int ret; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, wl->conf.tx.basic_rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl1271_11a_enabled()) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; else wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, wl->conf.tx.basic_rate_5); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, wl->conf.tx.basic_rate_5); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); } break; case WL1271_SCAN_STATE_DONE: mutex_unlock(&wl->mutex); ieee80211_scan_completed(wl->hw, false); mutex_lock(&wl->mutex); kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; wl->scan.state = WL1271_SCAN_STATE_IDLE; break; default: wl1271_error("invalid scan state"); break; } }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_SYNC | CMD_WANT_SKB, }; __le32 *status; if (!test_bit(STATUS_READY, &priv->status) || !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || !test_bit(STATUS_SCAN_HW, &priv->status) || test_bit(STATUS_FW_ERROR, &priv->shrd->status)) return -EIO; ret = iwl_dvm_send_cmd(priv, &cmd); if (ret) return ret; status = (void *)cmd.resp_pkt->data; if (*status != CAN_ABORT_STATUS) { IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", le32_to_cpu(*status)); ret = -EIO; } iwl_free_resp(&cmd); return ret; } static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); ieee80211_scan_completed(priv->hw, aborted); } if (priv->scan_type == IWL_SCAN_ROC) { ieee80211_remain_on_channel_expired(priv->hw); priv->hw_roc_channel = NULL; schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); } priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } static void iwl_process_scan_complete(struct iwl_priv *priv) { bool aborted; lockdep_assert_held(&priv->mutex); if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status)) return; IWL_DEBUG_SCAN(priv, "Completed scan.\n"); cancel_delayed_work(&priv->scan_check); aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status); if (aborted) IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); goto out_settings; } if (priv->scan_type == IWL_SCAN_ROC) { ieee80211_remain_on_channel_expired(priv->hw); priv->hw_roc_channel = NULL; schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); } if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { int err; if (priv->scan_request == NULL) goto out_complete; err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, priv->scan_request->channels[0]->band); if (err) { IWL_DEBUG_SCAN(priv, "failed to initiate pending scan: %d\n", err); aborted = true; goto out_complete; } return; } out_complete: iwl_complete_scan(priv, aborted); out_settings: if (!iwl_is_ready_rf(priv)) return; iwlagn_post_scan(priv); }
static void iwl_bg_request_scan(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, request_scan); struct iwl_host_cmd cmd = { .id = REPLY_SCAN_CMD, .len = sizeof(struct iwl_scan_cmd), .meta.flags = CMD_SIZE_HUGE, }; struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; int ret = 0; u32 rate_flags = 0; u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; u8 rx_chain = priv->hw_params.valid_rx_ant; u8 rate; DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); mutex_lock(&priv->mutex); if (!iwl_is_ready(priv)) { IWL_WARN(priv, "request scan called when driver not ready.\n"); goto done; } /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; /* This should never be called or scheduled if there is currently * a scan active in the hardware. */ if (test_bit(STATUS_SCAN_HW, &priv->status)) { IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests in parallel. " "Ignoring second request.\n"); ret = -EIO; goto done; } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n"); goto done; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { IWL_DEBUG_HC(priv, "Scan request while abort pending. Queuing.\n"); goto done; } if (iwl_is_rfkill(priv)) { IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n"); goto done; } if (!test_bit(STATUS_READY, &priv->status)) { IWL_DEBUG_HC(priv, "Scan request while uninitialized. Queuing.\n"); goto done; } if (!priv->scan_bands) { IWL_DEBUG_HC(priv, "Aborting scan due to no requested bands\n"); goto done; } if (!priv->scan) { priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE, GFP_KERNEL); if (!priv->scan) { ret = -ENOMEM; goto done; } } scan = priv->scan; memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; if (iwl_is_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; u32 scan_suspend_time = 100; unsigned long flags; IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); spin_lock_irqsave(&priv->lock, flags); interval = priv->beacon_int; spin_unlock_irqrestore(&priv->lock, flags); scan->suspend_time = 0; scan->max_out_time = cpu_to_le32(200 * 1024); if (!interval) interval = suspend_time; extra = (suspend_time / interval) << 22; scan_suspend_time = (extra | ((suspend_time % interval) * 1024)); scan->suspend_time = cpu_to_le32(scan_suspend_time); IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", scan_suspend_time, interval); } /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { IWL_DEBUG_SCAN(priv, "Start direct scan for '%s'\n", print_ssid(ssid, priv->direct_ssid, priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; } else { IWL_DEBUG_SCAN(priv, "Start indirect scan.\n"); } scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { rate = IWL_RATE_6M_PLCP; } else { rate = IWL_RATE_1M_PLCP; rate_flags = RATE_MCS_CCK_MSK; } scan->good_CRC_th = 0; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; /* Force use of chains B and C (0x6) for scan Rx for 4965 * Avoid A (0x1) because of its off-channel reception on A-band. */ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) rx_chain = 0x6; } else { IWL_WARN(priv, "Invalid scan band count\n"); goto done; } priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]); rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); /* MIMO is not used here, but value is required */ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); cmd_len = iwl_fill_probe_req(priv, band, (struct ieee80211_mgmt *)scan->data, IWL_MAX_SCAN_SIZE - sizeof(*scan)); scan->tx_cmd.len = cpu_to_le16(cmd_len); if (priv->iw_mode == NL80211_IFTYPE_MONITOR) scan->filter_flags = RXON_FILTER_PROMISC_MSK; scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | RXON_FILTER_BCON_AWARE_MSK); scan->channel_count = iwl_get_channels_for_scan(priv, band, 1, /* active */ n_probes, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); if (scan->channel_count == 0) { IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); goto done; } cmd.len += le16_to_cpu(scan->tx_cmd.len) + scan->channel_count * sizeof(struct iwl_scan_channel); cmd.data = scan; scan->len = cpu_to_le16(cmd.len); set_bit(STATUS_SCAN_HW, &priv->status); ret = iwl_send_cmd_sync(priv, &cmd); if (ret) goto done; queue_delayed_work(priv->workqueue, &priv->scan_check, IWL_SCAN_CHECK_WATCHDOG); mutex_unlock(&priv->mutex); return; done: /* Cannot perform scan. Make sure we clear scanning * bits from status so next scan request can be performed. * If we don't clear scanning status bit here all next scan * will fail */ clear_bit(STATUS_SCAN_HW, &priv->status); clear_bit(STATUS_SCANNING, &priv->status); /* inform mac80211 scan aborted */ queue_work(priv->workqueue, &priv->scan_completed); mutex_unlock(&priv->mutex); } void iwl_bg_abort_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); if (!iwl_is_ready(priv)) return; mutex_lock(&priv->mutex); set_bit(STATUS_SCAN_ABORTING, &priv->status); iwl_send_scan_abort(priv); mutex_unlock(&priv->mutex); } EXPORT_SYMBOL(iwl_bg_abort_scan); void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; ieee80211_scan_completed(priv->hw, false); /* Since setting the TXPOWER may have been deferred while * performing the scan, fire one off */ mutex_lock(&priv->mutex); iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); mutex_unlock(&priv->mutex); } EXPORT_SYMBOL(iwl_bg_scan_completed); void iwl_setup_scan_deferred_work(struct iwl_priv *priv) { INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); INIT_WORK(&priv->request_scan, iwl_bg_request_scan); INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_SYNC | CMD_WANT_SKB, }; /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * hardware scan currently */ if (!test_bit(STATUS_READY, &priv->status) || !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || !test_bit(STATUS_SCAN_HW, &priv->status) || test_bit(STATUS_FW_ERROR, &priv->status) || test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EIO; ret = trans_send_cmd(&priv->trans, &cmd); if (ret) return ret; pkt = (struct iwl_rx_packet *)cmd.reply_page; if (pkt->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_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status); ret = -EIO; } iwl_free_pages(priv, cmd.reply_page); return ret; } static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { /* check if scan was requested from mac80211 */ if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); ieee80211_scan_completed(priv->hw, aborted); } priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } void iwl_force_scan_end(struct iwl_priv *priv) { lockdep_assert_held(&priv->mutex); if (!test_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n"); return; } IWL_DEBUG_SCAN(priv, "Forcing scan end\n"); clear_bit(STATUS_SCANNING, &priv->status); clear_bit(STATUS_SCAN_HW, &priv->status); clear_bit(STATUS_SCAN_ABORTING, &priv->status); iwl_complete_scan(priv, true); }
void cw1200_scan_work(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, scan.work); struct ieee80211_channel **it; struct wsm_scan scan = { .scanType = WSM_SCAN_TYPE_FOREGROUND, .scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, }; bool first_run = priv->scan.begin == priv->scan.curr && priv->scan.begin != priv->scan.end; int i; mutex_lock(&priv->conf_mutex); if (first_run) { if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.pmMode = WSM_PSM_PS; cw1200_set_pm(priv, &pm); } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { /* FW bug: driver has to restart p2p-dev mode * after scan */ cw1200_disable_listening(priv); } } if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { if (priv->scan.output_power != priv->output_power) WARN_ON(wsm_set_output_power(priv, priv->output_power * 10)); if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) cw1200_set_pm(priv, &priv->powersave_mode); if (priv->scan.status < 0) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", priv->scan.status); else if (priv->scan.req) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan completed.\n"); else wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan canceled.\n"); priv->scan.req = NULL; cw1200_scan_restart_delayed(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0); up(&priv->scan.lock); return; } else { struct ieee80211_channel *first = *priv->scan.curr; for (it = priv->scan.curr + 1, i = 1; it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; ++it, ++i) { if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_PASSIVE_SCAN) break; if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && (*it)->max_power != first->max_power) break; } scan.band = first->band; if (priv->scan.req->no_cck) scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; else scan.maxTransmitRate = WSM_TRANSMIT_RATE_1; /* TODO: Is it optimal? */ scan.numOfProbeRequests = (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2; scan.numOfSSIDs = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.numOfChannels = it - priv->scan.curr; scan.probeDelay = 100; /* It is not stated in WSM specification, however * FW team says that driver may not use FG scan * when joined. */ if (priv->join_status == CW1200_JOIN_STATUS_STA) { scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } scan.ch = kzalloc( sizeof(struct wsm_scan_ch[it - priv->scan.curr]), GFP_KERNEL); if (!scan.ch) { priv->scan.status = -ENOMEM; goto fail; } for (i = 0; i < scan.numOfChannels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) { scan.ch[i].minChannelTime = 50; scan.ch[i].maxChannelTime = 100; } else { scan.ch[i].minChannelTime = 10; scan.ch[i].maxChannelTime = 25; } } if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; WARN_ON(wsm_set_output_power(priv, priv->scan.output_power * 10)); } priv->scan.status = cw1200_scan_start(priv, &scan); kfree(scan.ch); if (priv->scan.status) goto fail; priv->scan.curr = it; } mutex_unlock(&priv->conf_mutex); return; fail: priv->scan.curr = priv->scan.end; mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return; }
void cw1200_scan_work(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, scan.work); struct ieee80211_channel **it; struct wsm_scan scan = { .type = WSM_SCAN_TYPE_FOREGROUND, .flags = WSM_SCAN_FLAG_SPLIT_METHOD, }; bool first_run = (priv->scan.begin == priv->scan.curr && priv->scan.begin != priv->scan.end); int i; if (first_run) { /* Firmware gets crazy if scan request is sent * when STA is joined but not yet associated. * Force unjoin in this case. */ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) cw1200_join_timeout(&priv->join_timeout.work); } mutex_lock(&priv->conf_mutex); if (first_run) { if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.mode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.mode = WSM_PSM_PS; cw1200_set_pm(priv, &pm); } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { /* FW bug: driver has to restart p2p-dev mode * after scan */ cw1200_disable_listening(priv); } } if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { struct cfg80211_scan_info info = { .aborted = priv->scan.status ? 1 : 0, }; if (priv->scan.output_power != priv->output_power) wsm_set_output_power(priv, priv->output_power * 10); if (priv->join_status == CW1200_JOIN_STATUS_STA && !(priv->powersave_mode.mode & WSM_PSM_PS)) cw1200_set_pm(priv, &priv->powersave_mode); if (priv->scan.status < 0) wiphy_warn(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", priv->scan.status); else if (priv->scan.req) wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan completed.\n"); else wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan canceled.\n"); priv->scan.req = NULL; cw1200_scan_restart_delayed(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); ieee80211_scan_completed(priv->hw, &info); up(&priv->scan.lock); return; } else { struct ieee80211_channel *first = *priv->scan.curr; for (it = priv->scan.curr + 1, i = 1; it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; ++it, ++i) { if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_NO_IR) break; if (!(first->flags & IEEE80211_CHAN_NO_IR) && (*it)->max_power != first->max_power) break; } scan.band = first->band; if (priv->scan.req->no_cck) scan.max_tx_rate = WSM_TRANSMIT_RATE_6; else scan.max_tx_rate = WSM_TRANSMIT_RATE_1; scan.num_probes = (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; scan.num_ssids = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.num_channels = it - priv->scan.curr; /* TODO: Is it optimal? */ scan.probe_delay = 100; /* It is not stated in WSM specification, however * FW team says that driver may not use FG scan * when joined. */ if (priv->join_status == CW1200_JOIN_STATUS_STA) { scan.type = WSM_SCAN_TYPE_BACKGROUND; scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } scan.ch = kcalloc(it - priv->scan.curr, sizeof(struct wsm_scan_ch), GFP_KERNEL); if (!scan.ch) { priv->scan.status = -ENOMEM; goto fail; } for (i = 0; i < scan.num_channels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { scan.ch[i].min_chan_time = 50; scan.ch[i].max_chan_time = 100; } else { scan.ch[i].min_chan_time = 10; scan.ch[i].max_chan_time = 25; } } if (!(first->flags & IEEE80211_CHAN_NO_IR) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; wsm_set_output_power(priv, priv->scan.output_power * 10); } priv->scan.status = cw1200_scan_start(priv, &scan); kfree(scan.ch); if (priv->scan.status) goto fail; priv->scan.curr = it; } mutex_unlock(&priv->conf_mutex); return; fail: priv->scan.curr = priv->scan.end; mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return; }
static int iwl_send_scan_abort(struct iwl_priv *priv) { int ret; struct iwl_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .flags = CMD_SYNC | CMD_WANT_SKB, }; __le32 *status; /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * hardware scan currently */ if (!test_bit(STATUS_READY, &priv->status) || !test_bit(STATUS_SCAN_HW, &priv->status) || test_bit(STATUS_FW_ERROR, &priv->status)) return -EIO; ret = iwl_dvm_send_cmd(priv, &cmd); if (ret) return ret; status = (void *)cmd.resp_pkt->data; if (*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_SCAN(priv, "SCAN_ABORT ret %d.\n", le32_to_cpu(*status)); ret = -EIO; } iwl_free_resp(&cmd); return ret; } static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) { /* check if scan was requested from mac80211 */ if (priv->scan_request) { IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); ieee80211_scan_completed(priv->hw, aborted); } priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } static void iwl_process_scan_complete(struct iwl_priv *priv) { bool aborted; lockdep_assert_held(&priv->mutex); if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->status)) return; IWL_DEBUG_SCAN(priv, "Completed scan.\n"); cancel_delayed_work(&priv->scan_check); aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status); if (aborted) IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); goto out_settings; } if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { int err; /* Check if mac80211 requested scan during our internal scan */ if (priv->scan_request == NULL) goto out_complete; /* If so request a new scan */ err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, priv->scan_request->channels[0]->band); if (err) { IWL_DEBUG_SCAN(priv, "failed to initiate pending scan: %d\n", err); aborted = true; goto out_complete; } return; } out_complete: iwl_complete_scan(priv, aborted); out_settings: /* Can we still talk to firmware ? */ if (!iwl_is_ready_rf(priv)) return; iwlagn_post_scan(priv); }