static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ar5416AniState *aniState; int32_t rssi; aniState = &ah->curchan->ani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1)) { return; } } if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } return; } rssi = BEACON_RSSI(ah); if (rssi > aniState->rssiThrLow) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } else { if ((conf->channel->band == IEEE80211_BAND_2GHZ) && !conf_is_ht(conf)) { if (aniState->firstepLevel > 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); } } }
/* * Calculate the RX filter to be set in the HW. */ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) { #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) struct ath_hw *ah = priv->ah; u32 rfilt; rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; if (priv->rxfilter & FIF_PROBE_REQ) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station * mode interface or when in monitor mode. AP mode does not need this * since it receives all in-BSS frames anyway. */ if (((ah->opmode != NL80211_IFTYPE_AP) && (priv->rxfilter & FIF_PROMISC_IN_BSS)) || ah->is_monitoring) rfilt |= ATH9K_RX_FILTER_PROM; if (priv->rxfilter & FIF_CONTROL) rfilt |= ATH9K_RX_FILTER_CONTROL; if ((ah->opmode == NL80211_IFTYPE_STATION) && !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) rfilt |= ATH9K_RX_FILTER_MYBEACON; else rfilt |= ATH9K_RX_FILTER_BEACON; if (conf_is_ht(&priv->hw->conf)) { rfilt |= ATH9K_RX_FILTER_COMP_BAR; rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR; } if (priv->rxfilter & FIF_PSPOLL) rfilt |= ATH9K_RX_FILTER_PSPOLL; return rfilt; #undef RX_FILTER_PRESERVE }
/* * Update internal channel flags. */ void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, struct ath9k_channel *ichan) { struct ieee80211_channel *chan = hw->conf.channel; struct ieee80211_conf *conf = &hw->conf; ichan->channel = chan->center_freq; ichan->chan = chan; if (chan->band == IEEE80211_BAND_2GHZ) { ichan->chanmode = CHANNEL_G; ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; } else { ichan->chanmode = CHANNEL_A; ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; } if (conf_is_ht(conf)) ichan->chanmode = ath9k_get_extchanmode(chan, conf->channel_type); }
static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; bool fastcc; struct ieee80211_channel *channel = hw->conf.chandef.chan; struct ath9k_hw_cal_data *caldata = NULL; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; int ret; if (test_bit(ATH_OP_INVALID, &common->op_flags)) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); ath9k_htc_stop_ani(priv); del_timer_sync(&priv->tx.cleanup_timer); ath9k_htc_tx_drain(priv); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); ath9k_wmi_event_drain(priv); ath_dbg(common, CONFIG, "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", priv->ah->curchan->channel, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), fastcc); if (!fastcc) caldata = &priv->caldata; ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, "Unable to reset channel (%u Mhz) reset status %d\n", channel->center_freq, ret); goto err; } ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, &priv->curtxpow); WMI_CMD(WMI_START_RECV_CMDID); if (ret) goto err; ath9k_host_rx_init(priv); mode = ath9k_htc_get_curmode(priv, hchan); htc_mode = cpu_to_be16(mode); WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); if (ret) goto err; WMI_CMD(WMI_ENABLE_INTR_CMDID); if (ret) goto err; htc_start(priv->htc); if (!test_bit(ATH_OP_SCANNING, &common->op_flags) && !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); mod_timer(&priv->tx.cleanup_timer, jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); err: ath9k_htc_ps_restore(priv); return ret; }
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, unsigned int ieee80211_flags) { struct rt2x00lib_conf libconf; u16 hw_value; u16 autowake_timeout; u16 beacon_int; u16 beacon_diff; memset(&libconf, 0, sizeof(libconf)); libconf.conf = conf; if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { if (!conf_is_ht(conf)) set_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags); else clear_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags); if (conf_is_ht40(conf)) { set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = rt2x00ht_center_channel(rt2x00dev, conf); } else { clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); hw_value = conf->channel->hw_value; } memcpy(&libconf.rf, &rt2x00dev->spec.channels[hw_value], sizeof(libconf.rf)); memcpy(&libconf.channel, &rt2x00dev->spec.channels_info[hw_value], sizeof(libconf.channel)); /* Used for VCO periodic calibration */ rt2x00dev->rf_channel = libconf.rf.channel; } else { return; } if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); /* * Start configuration. */ rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags); /* * Some configuration changes affect the link quality * which means we need to reset the link tuner. */ if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00link_reset_tuner(rt2x00dev, false); if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && (conf->flags & IEEE80211_CONF_PS)) { beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); if (beacon_diff > beacon_int) beacon_diff = 0; autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; queue_delayed_work(rt2x00dev->workqueue, &rt2x00dev->autowakeup_work, autowake_timeout - 15); } if (conf->flags & IEEE80211_CONF_PS) set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); else clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); rt2x00dev->curr_band = conf->channel->band; rt2x00dev->curr_freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; rt2x00dev->short_retry = conf->short_frame_max_tx_count; rt2x00dev->long_retry = conf->long_frame_max_tx_count; }
int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx; struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); mutex_lock(&priv->mutex); if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); goto out; } if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; } if (changed & (IEEE80211_CONF_CHANGE_SMPS | IEEE80211_CONF_CHANGE_CHANNEL)) { /* mac80211 uses static for non-HT which is what we want */ priv->current_ht_config.smps = conf->smps_mode; /* * Recalculate chain counts. * * If monitor mode is enabled then mac80211 will * set up the SM PS mode to OFF if an HT channel is * configured. */ if (priv->cfg->ops->hcmd->set_rxon_chain) for_each_context(priv, ctx) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); } if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { unsigned long flags; ch_info = iwl_get_channel_info(priv, channel->band, channel->hw_value); if (!is_channel_valid(ch_info)) { IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); ret = -EINVAL; goto out; } spin_lock_irqsave(&priv->lock, flags); for_each_context(priv, ctx) { /* Configure HT40 channels */ if (ctx->ht.enabled != conf_is_ht(conf)) ctx->ht.enabled = conf_is_ht(conf); if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; ctx->ht.is_40mhz = true; } else if (conf_is_ht40_plus(conf)) { ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; ctx->ht.is_40mhz = true; } else { ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; ctx->ht.is_40mhz = false; } } else ctx->ht.is_40mhz = false; /* * Default to no protection. Protection mode will * later be set from BSS config in iwl_ht_conf */ ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not * support ht */ if (le16_to_cpu(ctx->staging.channel) != channel->hw_value) ctx->staging.flags = 0; iwl_set_rxon_channel(priv, channel, ctx); iwl_set_rxon_ht(priv, &priv->current_ht_config); iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); } spin_unlock_irqrestore(&priv->lock, flags); iwl_update_bcast_stations(priv); /* * The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists. */ iwl_set_rate(priv); }
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; int ret = 0; int power; enum nl80211_channel_type channel_type; u32 offchannel_flag; might_sleep(); scan_chan = local->scan_channel; /* If this off-channel logic ever changes, ieee80211_on_oper_channel * may need to change as well. */ offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; if (scan_chan) { chan = scan_chan; /* If scanning on oper channel, use whatever channel-type * is currently in use. */ if (chan == local->oper_channel) channel_type = local->_oper_channel_type; else channel_type = NL80211_CHAN_NO_HT; } else if (local->tmp_channel) { chan = scan_chan = local->tmp_channel; channel_type = local->tmp_channel_type; } else { chan = local->oper_channel; channel_type = local->_oper_channel_type; } if (chan != local->oper_channel || channel_type != local->_oper_channel_type) local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; else local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; if (offchannel_flag || chan != local->hw.conf.channel || channel_type != local->hw.conf.channel_type) { local->hw.conf.channel = chan; local->hw.conf.channel_type = channel_type; changed |= IEEE80211_CONF_CHANGE_CHANNEL; } if (!conf_is_ht(&local->hw.conf)) { /* * mac80211.h documents that this is only valid * when the channel is set to an HT type, and * that otherwise STATIC is used. */ local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; } else if (local->hw.conf.smps_mode != local->smps_mode) { local->hw.conf.smps_mode = local->smps_mode; changed |= IEEE80211_CONF_CHANGE_SMPS; } if ((local->scanning & SCAN_SW_SCANNING) || (local->scanning & SCAN_HW_SCANNING)) power = chan->max_power; else power = local->power_constr_level ? (chan->max_power - local->power_constr_level) : chan->max_power; if (local->user_power_level >= 0) power = min(power, local->user_power_level); if (local->hw.conf.power_level != power) { changed |= IEEE80211_CONF_CHANGE_POWER; local->hw.conf.power_level = power; } if (changed && local->open_count) { ret = drv_config(local, changed); /* * Goal: * HW reconfiguration should never fail, the driver has told * us what it can support so it should live up to that promise. * * Current status: * rfkill is not integrated with mac80211 and a * configuration command can thus fail if hardware rfkill * is enabled * * FIXME: integrate rfkill with mac80211 and then add this * WARN_ON() back * */ /* WARN_ON(ret); */ } return ret; }
void ath9k_tx_tasklet(unsigned long data) { struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct ieee80211_tx_info *tx_info; struct sk_buff *skb = NULL; __le16 fc; while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { hdr = (struct ieee80211_hdr *) skb->data; fc = hdr->frame_control; tx_info = IEEE80211_SKB_CB(skb); memset(&tx_info->status, 0, sizeof(tx_info->status)); rcu_read_lock(); sta = ieee80211_find_sta(priv->vif, hdr->addr1); if (!sta) { rcu_read_unlock(); ieee80211_tx_status(priv->hw, skb); continue; } /* Check if we need to start aggregation */ if (sta && conf_is_ht(&priv->hw->conf) && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { if (ieee80211_is_data_qos(fc)) { u8 *qc, tid; struct ath9k_htc_sta *ista; qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; ista = (struct ath9k_htc_sta *)sta->drv_priv; if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { ieee80211_start_tx_ba_session(sta, tid); spin_lock_bh(&priv->tx_lock); ista->tid_state[tid] = AGGR_PROGRESS; spin_unlock_bh(&priv->tx_lock); } } } rcu_read_unlock(); /* Send status to mac80211 */ ieee80211_tx_status(priv->hw, skb); } /* Wake TX queues if needed */ spin_lock_bh(&priv->tx_lock); if (priv->tx_queues_stop) { priv->tx_queues_stop = false; spin_unlock_bh(&priv->tx_lock); ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Waking up TX queues\n"); ieee80211_wake_queues(priv->hw); return; } spin_unlock_bh(&priv->tx_lock); }
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan, *scan_chan; int ret = 0; int power; enum nl80211_channel_type channel_type; might_sleep(); scan_chan = local->scan_channel; if (scan_chan) { chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; } else if (local->tmp_channel && local->oper_channel != local->tmp_channel) { chan = scan_chan = local->tmp_channel; channel_type = local->tmp_channel_type; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; } else { chan = local->oper_channel; channel_type = local->_oper_channel_type; local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; } if (chan != local->hw.conf.channel || channel_type != local->hw.conf.channel_type) { local->hw.conf.channel = chan; local->hw.conf.channel_type = channel_type; changed |= IEEE80211_CONF_CHANGE_CHANNEL; } if (!conf_is_ht(&local->hw.conf)) { /* * mac80211.h documents that this is only valid * when the channel is set to an HT type, and * that otherwise STATIC is used. */ local->hw.conf.smps_mode = IEEE80211_SMPS_STATIC; } else if (local->hw.conf.smps_mode != local->smps_mode) { local->hw.conf.smps_mode = local->smps_mode; changed |= IEEE80211_CONF_CHANGE_SMPS; } if (scan_chan) power = chan->max_power; else power = local->power_constr_level ? (chan->max_power - local->power_constr_level) : chan->max_power; if (local->user_power_level >= 0) power = min(power, local->user_power_level); if (local->hw.conf.power_level != power) { changed |= IEEE80211_CONF_CHANGE_POWER; local->hw.conf.power_level = power; } if (changed && local->open_count) { ret = drv_config(local, changed); /* WARN_ON(ret); */ } return ret; }
static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, struct ieee80211_hw *hw, struct ath9k_channel *hchan) { struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_conf *conf = &common->hw->conf; bool fastcc; struct ieee80211_channel *channel = hw->conf.channel; struct ath9k_hw_cal_data *caldata; enum htc_phymode mode; __be16 htc_mode; u8 cmd_rsp; int ret; if (priv->op_flags & OP_INVALID) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); ath9k_htc_ps_wakeup(priv); htc_stop(priv->htc); WMI_CMD(WMI_DISABLE_INTR_CMDID); WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); WMI_CMD(WMI_STOP_RECV_CMDID); ath_dbg(common, ATH_DBG_CONFIG, "(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n", priv->ah->curchan->channel, channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf), fastcc); caldata = &priv->caldata[channel->hw_value]; ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (ret) { ath_err(common, "Unable to reset channel (%u Mhz) reset status %d\n", channel->center_freq, ret); goto err; } ath_update_txpow(priv); WMI_CMD(WMI_START_RECV_CMDID); if (ret) goto err; ath9k_host_rx_init(priv); mode = ath9k_htc_get_curmode(priv, hchan); htc_mode = cpu_to_be16(mode); WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); if (ret) goto err; WMI_CMD(WMI_ENABLE_INTR_CMDID); if (ret) goto err; htc_start(priv->htc); err: ath9k_htc_ps_restore(priv); return ret; }
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) { struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; struct ar5416AniState *aniState; int32_t rssi; if (!DO_ANI(ah)) return; aniState = ah->curani; if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, aniState->noiseImmunityLevel + 1)) { return; } } if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, aniState->spurImmunityLevel + 1)) { return; } } if (ah->opmode == NL80211_IFTYPE_AP) { if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); } return; } rssi = BEACON_RSSI(ah); if (rssi > aniState->rssiThrHigh) { if (!aniState->ofdmWeakSigDetectOff) { if (ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, false)) { ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); return; } } if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); return; } } else if (rssi > aniState->rssiThrLow) { if (aniState->ofdmWeakSigDetectOff) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, true); if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel + 1); return; } else { if ((conf->channel->band == IEEE80211_BAND_2GHZ) && !conf_is_ht(conf)) { if (!aniState->ofdmWeakSigDetectOff) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, false); if (aniState->firstepLevel > 0) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); return; } } }
/** * iwl_legacy_mac_config - mac80211 config callback */ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; struct ieee80211_conf *conf = &hw->conf; struct ieee80211_channel *channel = conf->channel; struct iwl_ht_config *ht_conf = &priv->current_ht_config; struct iwl_rxon_context *ctx; unsigned long flags = 0; int ret = 0; u16 ch; int scan_active = 0; bool ht_changed[NUM_IWL_RXON_CTX] = {}; if (WARN_ON(!priv->cfg->ops->legacy)) return -EOPNOTSUPP; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", channel->hw_value, changed); if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { scan_active = 1; IWL_DEBUG_MAC80211(priv, "scan active\n"); } if (changed & (IEEE80211_CONF_CHANGE_SMPS | IEEE80211_CONF_CHANGE_CHANNEL)) { /* mac80211 uses static for non-HT which is what we want */ priv->current_ht_config.smps = conf->smps_mode; /* * Recalculate chain counts. * * If monitor mode is enabled then mac80211 will * set up the SM PS mode to OFF if an HT channel is * configured. */ if (priv->cfg->ops->hcmd->set_rxon_chain) for_each_context(priv, ctx) priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); } /* during scanning mac80211 will delay channel setting until * scan finish with changed = 0 */ if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { if (scan_active) goto set_ch_out; ch = channel->hw_value; ch_info = iwl_get_channel_info(priv, channel->band, ch); if (!is_channel_valid(ch_info)) { IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); ret = -EINVAL; goto set_ch_out; } spin_lock_irqsave(&priv->lock, flags); for_each_context(priv, ctx) { /* Configure HT40 channels */ if (ctx->ht.enabled != conf_is_ht(conf)) { ctx->ht.enabled = conf_is_ht(conf); ht_changed[ctx->ctxid] = true; } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; ctx->ht.is_40mhz = true; } else if (conf_is_ht40_plus(conf)) { ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; ctx->ht.is_40mhz = true; } else { ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; ctx->ht.is_40mhz = false; } } else ctx->ht.is_40mhz = false; /* * Default to no protection. Protection mode will * later be set from BSS config in iwl_ht_conf */ ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; /* if we are switching from ht to 2.4 clear flags * from any ht related info since 2.4 does not * support ht */ if ((le16_to_cpu(ctx->staging.channel) != ch)) ctx->staging.flags = 0; iwl_set_rxon_channel(priv, channel, ctx); iwl_set_rxon_ht(priv, ht_conf); iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); } spin_unlock_irqrestore(&priv->lock, flags); if (priv->cfg->ops->legacy->update_bcast_stations) ret = priv->cfg->ops->legacy->update_bcast_stations(priv); set_ch_out: /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists */ iwl_set_rate(priv); } if (changed & (IEEE80211_CONF_CHANGE_PS | IEEE80211_CONF_CHANGE_IDLE)) { ret = iwl_power_update_mode(priv, false); if (ret) IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); } if (changed & IEEE80211_CONF_CHANGE_POWER) { IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", priv->tx_power_user_lmt, conf->power_level); iwl_set_tx_power(priv, conf->power_level, false); } if (!iwl_is_ready(priv)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; } if (scan_active) goto out; for_each_context(priv, ctx) { if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging))) iwlcore_commit_rxon(priv, ctx); else IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n"); if (ht_changed[ctx->ctxid]) iwl_update_qos(priv, ctx); } out: IWL_DEBUG_MAC80211(priv, "leave\n"); mutex_unlock(&priv->mutex); return ret; }