int iwl_scan_initiate(struct iwl_priv *priv) { if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; } if (test_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN("Scan already in progress.\n"); return -EAGAIN; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { IWL_DEBUG_SCAN("Scan request while abort pending\n"); return -EAGAIN; } IWL_DEBUG_INFO("Starting scan...\n"); if (priv->cfg->sku & IWL_SKU_G) priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); if (priv->cfg->sku & IWL_SKU_A) priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); set_bit(STATUS_SCANNING, &priv->status); priv->scan_start = jiffies; priv->scan_pass_start = priv->scan_start; queue_work(priv->workqueue, &priv->request_scan); return 0; }
static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret; s8 prev_tx_power; bool defer; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED) return 0; lockdep_assert_held(&priv->mutex); if (priv->tx_power_user_lmt == tx_power && !force) return 0; if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", tx_power, IWLAGN_TX_POWER_TARGET_POWER_MIN); return -EINVAL; } if (tx_power > DIV_ROUND_UP(priv->nvm_data->max_tx_pwr_half_dbm, 2)) { IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", tx_power, priv->nvm_data->max_tx_pwr_half_dbm); return -EINVAL; } if (!iwl_is_ready_rf(priv)) return -EIO; /* scan complete and commit_rxon use tx_power_next value, * it always need to be updated for newest request */ priv->tx_power_next = tx_power; /* do not set tx power when scanning or channel changing */ defer = test_bit(STATUS_SCANNING, &priv->status) || memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); if (defer && !force) { IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); return 0; } prev_tx_power = priv->tx_power_user_lmt; priv->tx_power_user_lmt = tx_power; ret = iwlagn_send_tx_power(priv); /* if fail to set tx_power, restore the orig. tx power */ if (ret) { priv->tx_power_user_lmt = prev_tx_power; priv->tx_power_next = prev_tx_power; } return ret; }
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { struct iwl_priv *priv = hw->priv; int ret; IWL_DEBUG_MAC80211(priv, "enter\n"); if (req->n_channels == 0) return -EINVAL; mutex_lock(&priv->mutex); if (!iwl_is_ready_rf(priv)) { ret = -EIO; IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); goto out_unlock; } if (test_bit(STATUS_SCANNING, &priv->status) && !priv->is_internal_short_scan) { IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); ret = -EAGAIN; goto out_unlock; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); ret = -EAGAIN; goto out_unlock; } /* mac80211 will only ask for one band at a time */ priv->scan_band = req->channels[0]->band; priv->scan_request = req; priv->scan_vif = vif; /* * If an internal scan is in progress, just set * up the scan_request as per above. */ if (priv->is_internal_short_scan) ret = 0; else ret = iwl_scan_initiate(priv, vif); IWL_DEBUG_MAC80211(priv, "leave\n"); out_unlock: mutex_unlock(&priv->mutex); return ret; }
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); }
void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; unsigned long flags; /* IBSS can only be the IWL_RXON_CTX_BSS context */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; if (WARN_ON(!priv->cfg->ops->legacy)) return; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "enter\n"); spin_lock_irqsave(&priv->lock, flags); memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); spin_unlock_irqrestore(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags); /* new association get rid of ibss beacon skb */ if (priv->beacon_skb) dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; priv->timestamp = 0; spin_unlock_irqrestore(&priv->lock, flags); iwl_scan_cancel_timeout(priv, 100); if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); mutex_unlock(&priv->mutex); return; } /* we are restarting association process * clear RXON_FILTER_ASSOC_MSK bit */ ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; iwlcore_commit_rxon(priv, ctx); iwl_set_rate(priv); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); }
int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, bool force) { int ret; bool update_chains; lockdep_assert_held(&priv->mutex); /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force) return 0; if (!iwl_is_ready_rf(priv)) return -EIO; /* scan complete use sleep_power_next, need to be updated */ memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd)); if (test_bit(STATUS_SCANNING, &priv->status) && !force) { IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n"); return 0; } if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) set_bit(STATUS_POWER_PMI, &priv->status); ret = iwl_set_power(priv, cmd); if (!ret) { if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) clear_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); else if (priv->cfg->ops->lib->update_chain_flags) IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)); } else IWL_ERR(priv, "set power fail, ret = %d", ret); return ret; }
/* * compute the final power mode index */ int iwl_power_update_mode(struct iwl_priv *priv, bool force) { struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; u16 uninitialized_var(final_mode); bool update_chains; /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; final_mode = priv->power_data.user_power_setting; if (setting->power_disabled) final_mode = IWL_POWER_MODE_CAM; if (iwl_is_ready_rf(priv) && ((setting->power_mode != final_mode) || force)) { struct iwl_powertable_cmd cmd; if (final_mode != IWL_POWER_MODE_CAM) set_bit(STATUS_POWER_PMI, &priv->status); iwl_update_power_cmd(priv, &cmd, final_mode); cmd.keep_alive_beacons = 0; if (final_mode == IWL_POWER_INDEX_5) cmd.flags |= IWL_POWER_FAST_PD; ret = iwl_set_power(priv, &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); else IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); if (!ret) setting->power_mode = final_mode; } return ret; }
void iwl_bg_start_internal_scan(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, start_internal_scan); mutex_lock(&priv->mutex); if (priv->is_internal_short_scan == true) { IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); goto unlock; } if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); goto unlock; } if (test_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); goto unlock; } if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); goto unlock; } priv->scan_band = priv->band; IWL_DEBUG_SCAN(priv, "Start internal short scan...\n"); set_bit(STATUS_SCANNING, &priv->status); priv->is_internal_short_scan = true; if (WARN_ON(!priv->cfg->ops->utils->request_scan)) goto unlock; priv->cfg->ops->utils->request_scan(priv, NULL); unlock: mutex_unlock(&priv->mutex); }
int iwl_power_update_mode(struct iwl_priv *priv, bool force) { int ret = 0; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; bool enabled = (priv->iw_mode == NL80211_IFTYPE_STATION) && (priv->hw->conf.flags & IEEE80211_CONF_PS); bool update_chains; struct iwl_powertable_cmd cmd; int dtimper; /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; if (priv->vif) dtimper = priv->vif->bss_conf.dtim_period; else dtimper = 1; if (priv->cfg->broken_powersave) iwl_power_sleep_cam_cmd(priv, &cmd); else if (priv->cfg->supports_idle && priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20); else if (tt->state >= IWL_TI_1) iwl_static_sleep_cmd(priv, &cmd, tt->tt_power_mode, dtimper); else if (!enabled) iwl_power_sleep_cam_cmd(priv, &cmd); else if (priv->power_data.debug_sleep_level_override >= 0) iwl_static_sleep_cmd(priv, &cmd, priv->power_data.debug_sleep_level_override, dtimper); else if (no_sleep_autoadjust) iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); else iwl_power_fill_sleep_cmd(priv, &cmd, priv->hw->conf.dynamic_ps_timeout, priv->hw->conf.max_sleep_period); if (iwl_is_ready_rf(priv) && (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) set_bit(STATUS_POWER_PMI, &priv->status); ret = iwl_set_power(priv, &cmd); if (!ret) { if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) clear_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); else if (priv->cfg->ops->lib->update_chain_flags) IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); } else IWL_ERR(priv, "set power fail, ret = %d", ret); } return ret; }
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); }
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req) { unsigned long flags; struct iwl_priv *priv = hw->priv; int ret; u8 *ssid = NULL; size_t ssid_len = 0; if (req->n_ssids) { ssid = req->ssids[0].ssid; ssid_len = req->ssids[0].ssid_len; } IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->mutex); spin_lock_irqsave(&priv->lock, flags); if (!iwl_is_ready_rf(priv)) { ret = -EIO; IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); goto out_unlock; } /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n"); queue_work(priv->workqueue, &priv->scan_completed); ret = 0; goto out_unlock; } /* if we just finished scan ask for delay */ if (iwl_is_associated(priv) && priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); queue_work(priv->workqueue, &priv->scan_completed); ret = 0; goto out_unlock; } if (ssid_len) { priv->one_direct_scan = 1; priv->direct_ssid_len = ssid_len; memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); } else { priv->one_direct_scan = 0; } ret = iwl_scan_initiate(priv); IWL_DEBUG_MAC80211(priv, "leave\n"); out_unlock: spin_unlock_irqrestore(&priv->lock, flags); mutex_unlock(&priv->mutex); return ret; }
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); }