diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2010-05-06 11:54:11 -0400 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-06-06 02:16:09 -0400 |
commit | 79d07325502e73508f917475bc1617b60979dd94 (patch) | |
tree | 7493c7db482c41b4535690c3a19fb81f3a7b2580 /drivers/net/wireless/iwlwifi/iwl-6000.c | |
parent | a0ee74cf080389aee4fbf198ffa7e85b3480b661 (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.c | 53 |
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 | ||
242 | static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | 242 | static 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); |