is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
if (is_ht40 &&
- (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ (priv->staging_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
ctrl_chan_high = 1;
cmd.band = band;
cmd.expect_beacon = 0;
cmd.channel = cpu_to_le16(channel);
- cmd.rxon_flags = priv->active_rxon.flags;
- cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.rxon_flags = priv->staging_rxon.flags;
+ cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
return rc;
}
- rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
- return rc;
+ priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.switch_in_progress = true;
+
+ return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
}
/**
priv->active_rxon.channel, channel);
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
cmd.channel = cpu_to_le16(channel);
- cmd.rxon_flags = priv->active_rxon.flags;
- cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.rxon_flags = priv->staging_rxon.flags;
+ cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
if (ch_info)
priv->active_rxon.channel, channel);
return -EFAULT;
}
+ priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
}
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
cmd.channel = cpu_to_le16(channel);
- cmd.rxon_flags = priv->active_rxon.flags;
- cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.rxon_flags = priv->staging_rxon.flags;
+ cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
ch_info = iwl_get_channel_info(priv, priv->band, channel);
if (ch_info)
priv->active_rxon.channel, channel);
return -EFAULT;
}
+ priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
}
return -EINVAL;
}
+ /*
+ * receive commit_rxon request
+ * abort any previous channel switch if still in process
+ */
+ if (priv->switch_rxon.switch_in_progress &&
+ (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;
+ }
+
/* If we don't need to send a full RXON, we can use
* iwl_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
- if (!le32_to_cpu(csa->status)) {
- rxon->channel = csa->channel;
- priv->staging_rxon.channel = csa->channel;
- IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
- le16_to_cpu(csa->channel));
- } else
- IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
- le16_to_cpu(csa->channel));
+ if (priv->switch_rxon.switch_in_progress) {
+ if (!le32_to_cpu(csa->status) &&
+ (csa->channel == priv->switch_rxon.channel)) {
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+ IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
+ le16_to_cpu(csa->channel));
+ } else
+ IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+ le16_to_cpu(csa->channel));
+
+ priv->switch_rxon.switch_in_progress = false;
+ }
}
EXPORT_SYMBOL(iwl_rx_csa);
goto set_ch_out;
}
- if (iwl_is_associated(priv) &&
- (le16_to_cpu(priv->active_rxon.channel) != ch) &&
- priv->cfg->ops->lib->set_channel_switch) {
- ret = priv->cfg->ops->lib->set_channel_switch(priv,
- ch);
- goto out;
- }
-
spin_lock_irqsave(&priv->lock, flags);
/* Configure HT40 channels */
iwl_set_flags_for_band(priv, conf->channel->band);
spin_unlock_irqrestore(&priv->lock, flags);
+ if (iwl_is_associated(priv) &&
+ (le16_to_cpu(priv->active_rxon.channel) != ch) &&
+ priv->cfg->ops->lib->set_channel_switch) {
+ iwl_set_rate(priv);
+ /*
+ * at this point, staging_rxon has the
+ * configuration for channel switch
+ */
+ ret = priv->cfg->ops->lib->set_channel_switch(priv,
+ ch);
+ if (!ret) {
+ iwl_print_rx_config_cmd(priv);
+ goto out;
+ }
+ priv->switch_rxon.switch_in_progress = false;
+ }
set_ch_out:
/* The list of supported rates and rate mask can be different
* for each band; since the band may have changed, reset
};
#endif
+/*
+ * iwl_switch_rxon: "channel switch" structure
+ *
+ * @ switch_in_progress: channel switch in progress
+ * @ channel: new channel
+ */
+struct iwl_switch_rxon {
+ bool switch_in_progress;
+ __le16 channel;
+};
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
const struct iwl_rxon_cmd active_rxon;
struct iwl_rxon_cmd staging_rxon;
+ struct iwl_switch_rxon switch_rxon;
+
/* 1st responses from initialize and runtime uCode images.
* 4965's initialize alive response contains some calibration data. */
struct iwl_init_alive_resp card_alive_init;