|
@@ -120,7 +120,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
|
|
|
(priv->switch_rxon.channel != priv->staging_rxon.channel)) {
|
|
|
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
|
|
|
le16_to_cpu(priv->switch_rxon.channel));
|
|
|
- priv->switch_rxon.switch_in_progress = false;
|
|
|
+ iwl_chswitch_done(priv, false);
|
|
|
}
|
|
|
|
|
|
/* If we don't need to send a full RXON, we can use
|
|
@@ -3325,6 +3325,98 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
|
|
|
+ struct ieee80211_channel_switch *ch_switch)
|
|
|
+{
|
|
|
+ struct iwl_priv *priv = hw->priv;
|
|
|
+ const struct iwl_channel_info *ch_info;
|
|
|
+ struct ieee80211_conf *conf = &hw->conf;
|
|
|
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
|
|
|
+ u16 ch;
|
|
|
+ unsigned long flags = 0;
|
|
|
+
|
|
|
+ IWL_DEBUG_MAC80211(priv, "enter\n");
|
|
|
+
|
|
|
+ if (iwl_is_rfkill(priv))
|
|
|
+ goto out_exit;
|
|
|
+
|
|
|
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
|
|
|
+ test_bit(STATUS_SCANNING, &priv->status))
|
|
|
+ goto out_exit;
|
|
|
+
|
|
|
+ if (!iwl_is_associated(priv))
|
|
|
+ goto out_exit;
|
|
|
+
|
|
|
+ /* channel switch in progress */
|
|
|
+ if (priv->switch_rxon.switch_in_progress == true)
|
|
|
+ goto out_exit;
|
|
|
+
|
|
|
+ mutex_lock(&priv->mutex);
|
|
|
+ if (priv->cfg->ops->lib->set_channel_switch) {
|
|
|
+
|
|
|
+ ch = ieee80211_frequency_to_channel(
|
|
|
+ ch_switch->channel->center_freq);
|
|
|
+ if (le16_to_cpu(priv->active_rxon.channel) != ch) {
|
|
|
+ ch_info = iwl_get_channel_info(priv,
|
|
|
+ conf->channel->band,
|
|
|
+ ch);
|
|
|
+ if (!is_channel_valid(ch_info)) {
|
|
|
+ IWL_DEBUG_MAC80211(priv, "invalid channel\n");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
|
+
|
|
|
+ priv->current_ht_config.smps = conf->smps_mode;
|
|
|
+
|
|
|
+ /* Configure HT40 channels */
|
|
|
+ ht_conf->is_ht = conf_is_ht(conf);
|
|
|
+ if (ht_conf->is_ht) {
|
|
|
+ if (conf_is_ht40_minus(conf)) {
|
|
|
+ ht_conf->extension_chan_offset =
|
|
|
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
|
|
|
+ ht_conf->is_40mhz = true;
|
|
|
+ } else if (conf_is_ht40_plus(conf)) {
|
|
|
+ ht_conf->extension_chan_offset =
|
|
|
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
|
|
|
+ ht_conf->is_40mhz = true;
|
|
|
+ } else {
|
|
|
+ ht_conf->extension_chan_offset =
|
|
|
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
|
|
|
+ ht_conf->is_40mhz = false;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ ht_conf->is_40mhz = false;
|
|
|
+
|
|
|
+ /* 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(priv->staging_rxon.channel) != ch))
|
|
|
+ priv->staging_rxon.flags = 0;
|
|
|
+
|
|
|
+ iwl_set_rxon_channel(priv, conf->channel);
|
|
|
+ iwl_set_rxon_ht(priv, ht_conf);
|
|
|
+ iwl_set_flags_for_band(priv, conf->channel->band,
|
|
|
+ priv->vif);
|
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
+
|
|
|
+ iwl_set_rate(priv);
|
|
|
+ /*
|
|
|
+ * at this point, staging_rxon has the
|
|
|
+ * configuration for channel switch
|
|
|
+ */
|
|
|
+ if (priv->cfg->ops->lib->set_channel_switch(priv,
|
|
|
+ ch_switch))
|
|
|
+ priv->switch_rxon.switch_in_progress = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+out:
|
|
|
+ mutex_unlock(&priv->mutex);
|
|
|
+out_exit:
|
|
|
+ if (!priv->switch_rxon.switch_in_progress)
|
|
|
+ ieee80211_chswitch_done(priv->vif, false);
|
|
|
+ IWL_DEBUG_MAC80211(priv, "leave\n");
|
|
|
+}
|
|
|
+
|
|
|
/*****************************************************************************
|
|
|
*
|
|
|
* sysfs attributes
|
|
@@ -3646,6 +3738,7 @@ static struct ieee80211_ops iwl_hw_ops = {
|
|
|
.sta_notify = iwl_mac_sta_notify,
|
|
|
.sta_add = iwlagn_mac_sta_add,
|
|
|
.sta_remove = iwl_mac_sta_remove,
|
|
|
+ .channel_switch = iwl_mac_channel_switch,
|
|
|
};
|
|
|
|
|
|
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|