aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-6000.c
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2010-05-06 11:54:11 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-06-06 02:16:09 -0400
commit79d07325502e73508f917475bc1617b60979dd94 (patch)
tree7493c7db482c41b4535690c3a19fb81f3a7b2580 /drivers/net/wireless/iwlwifi/iwl-6000.c
parenta0ee74cf080389aee4fbf198ffa7e85b3480b661 (diff)
iwlwifi: support channel switch offload in driver
Support channel switch in driver as a separated mac80211 callback function instead of part of mac_config callback; by moving to this approach, uCode can have more control of channel switch timing. Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-6000.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 5f6dbd9561d7..077514546d02 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -239,10 +239,17 @@ static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
239 return 0; 239 return 0;
240} 240}
241 241
242static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) 242static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
243 struct ieee80211_channel_switch *ch_switch)
243{ 244{
244 struct iwl6000_channel_switch_cmd cmd; 245 struct iwl6000_channel_switch_cmd cmd;
245 const struct iwl_channel_info *ch_info; 246 const struct iwl_channel_info *ch_info;
247 u32 switch_time_in_usec, ucode_switch_time;
248 u16 ch;
249 u32 tsf_low;
250 u8 switch_count;
251 u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
252 struct ieee80211_vif *vif = priv->vif;
246 struct iwl_host_cmd hcmd = { 253 struct iwl_host_cmd hcmd = {
247 .id = REPLY_CHANNEL_SWITCH, 254 .id = REPLY_CHANNEL_SWITCH,
248 .len = sizeof(cmd), 255 .len = sizeof(cmd),
@@ -250,23 +257,51 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
250 .data = &cmd, 257 .data = &cmd,
251 }; 258 };
252 259
253 IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
254 priv->active_rxon.channel, channel);
255
256 cmd.band = priv->band == IEEE80211_BAND_2GHZ; 260 cmd.band = priv->band == IEEE80211_BAND_2GHZ;
257 cmd.channel = cpu_to_le16(channel); 261 ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
262 IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
263 priv->active_rxon.channel, ch);
264 cmd.channel = cpu_to_le16(ch);
258 cmd.rxon_flags = priv->staging_rxon.flags; 265 cmd.rxon_flags = priv->staging_rxon.flags;
259 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; 266 cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
260 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); 267 switch_count = ch_switch->count;
261 ch_info = iwl_get_channel_info(priv, priv->band, channel); 268 tsf_low = ch_switch->timestamp & 0x0ffffffff;
269 /*
270 * calculate the ucode channel switch time
271 * adding TSF as one of the factor for when to switch
272 */
273 if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
274 if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
275 beacon_interval)) {
276 switch_count -= (priv->ucode_beacon_time -
277 tsf_low) / beacon_interval;
278 } else
279 switch_count = 0;
280 }
281 if (switch_count <= 1)
282 cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
283 else {
284 switch_time_in_usec =
285 vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
286 ucode_switch_time = iwl_usecs_to_beacons(priv,
287 switch_time_in_usec,
288 beacon_interval);
289 cmd.switch_time = iwl_add_beacon_time(priv,
290 priv->ucode_beacon_time,
291 ucode_switch_time,
292 beacon_interval);
293 }
294 IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
295 cmd.switch_time);
296 ch_info = iwl_get_channel_info(priv, priv->band, ch);
262 if (ch_info) 297 if (ch_info)
263 cmd.expect_beacon = is_channel_radar(ch_info); 298 cmd.expect_beacon = is_channel_radar(ch_info);
264 else { 299 else {
265 IWL_ERR(priv, "invalid channel switch from %u to %u\n", 300 IWL_ERR(priv, "invalid channel switch from %u to %u\n",
266 priv->active_rxon.channel, channel); 301 priv->active_rxon.channel, ch);
267 return -EFAULT; 302 return -EFAULT;
268 } 303 }
269 priv->switch_rxon.channel = cpu_to_le16(channel); 304 priv->switch_rxon.channel = cmd.channel;
270 priv->switch_rxon.switch_in_progress = true; 305 priv->switch_rxon.switch_in_progress = true;
271 306
272 return iwl_send_cmd_sync(priv, &hcmd); 307 return iwl_send_cmd_sync(priv, &hcmd);