diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-5000.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index a28af7eb67eb..32710a801cb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -208,6 +208,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | |||
208 | BIT(IWL_CALIB_TX_IQ_PERD) | | 208 | BIT(IWL_CALIB_TX_IQ_PERD) | |
209 | BIT(IWL_CALIB_BASE_BAND); | 209 | BIT(IWL_CALIB_BASE_BAND); |
210 | 210 | ||
211 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; | ||
212 | |||
211 | return 0; | 213 | return 0; |
212 | } | 214 | } |
213 | 215 | ||
@@ -252,6 +254,8 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) | |||
252 | BIT(IWL_CALIB_TX_IQ) | | 254 | BIT(IWL_CALIB_TX_IQ) | |
253 | BIT(IWL_CALIB_BASE_BAND); | 255 | BIT(IWL_CALIB_BASE_BAND); |
254 | 256 | ||
257 | priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; | ||
258 | |||
255 | return 0; | 259 | return 0; |
256 | } | 260 | } |
257 | 261 | ||
@@ -267,33 +271,69 @@ static void iwl5150_temperature(struct iwl_priv *priv) | |||
267 | iwl_tt_handler(priv); | 271 | iwl_tt_handler(priv); |
268 | } | 272 | } |
269 | 273 | ||
270 | static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) | 274 | static int iwl5000_hw_channel_switch(struct iwl_priv *priv, |
275 | struct ieee80211_channel_switch *ch_switch) | ||
271 | { | 276 | { |
272 | struct iwl5000_channel_switch_cmd cmd; | 277 | struct iwl5000_channel_switch_cmd cmd; |
273 | const struct iwl_channel_info *ch_info; | 278 | const struct iwl_channel_info *ch_info; |
279 | u32 switch_time_in_usec, ucode_switch_time; | ||
280 | u16 ch; | ||
281 | u32 tsf_low; | ||
282 | u8 switch_count; | ||
283 | u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval); | ||
284 | struct ieee80211_vif *vif = priv->vif; | ||
274 | struct iwl_host_cmd hcmd = { | 285 | struct iwl_host_cmd hcmd = { |
275 | .id = REPLY_CHANNEL_SWITCH, | 286 | .id = REPLY_CHANNEL_SWITCH, |
276 | .len = sizeof(cmd), | 287 | .len = sizeof(cmd), |
277 | .flags = CMD_SIZE_HUGE, | 288 | .flags = CMD_SYNC, |
278 | .data = &cmd, | 289 | .data = &cmd, |
279 | }; | 290 | }; |
280 | 291 | ||
281 | IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", | ||
282 | priv->active_rxon.channel, channel); | ||
283 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; | 292 | cmd.band = priv->band == IEEE80211_BAND_2GHZ; |
284 | cmd.channel = cpu_to_le16(channel); | 293 | ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq); |
294 | IWL_DEBUG_11H(priv, "channel switch from %d to %d\n", | ||
295 | priv->active_rxon.channel, ch); | ||
296 | cmd.channel = cpu_to_le16(ch); | ||
285 | cmd.rxon_flags = priv->staging_rxon.flags; | 297 | cmd.rxon_flags = priv->staging_rxon.flags; |
286 | cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; | 298 | cmd.rxon_filter_flags = priv->staging_rxon.filter_flags; |
287 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | 299 | switch_count = ch_switch->count; |
288 | ch_info = iwl_get_channel_info(priv, priv->band, channel); | 300 | tsf_low = ch_switch->timestamp & 0x0ffffffff; |
301 | /* | ||
302 | * calculate the ucode channel switch time | ||
303 | * adding TSF as one of the factor for when to switch | ||
304 | */ | ||
305 | if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) { | ||
306 | if (switch_count > ((priv->ucode_beacon_time - tsf_low) / | ||
307 | beacon_interval)) { | ||
308 | switch_count -= (priv->ucode_beacon_time - | ||
309 | tsf_low) / beacon_interval; | ||
310 | } else | ||
311 | switch_count = 0; | ||
312 | } | ||
313 | if (switch_count <= 1) | ||
314 | cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time); | ||
315 | else { | ||
316 | switch_time_in_usec = | ||
317 | vif->bss_conf.beacon_int * switch_count * TIME_UNIT; | ||
318 | ucode_switch_time = iwl_usecs_to_beacons(priv, | ||
319 | switch_time_in_usec, | ||
320 | beacon_interval); | ||
321 | cmd.switch_time = iwl_add_beacon_time(priv, | ||
322 | priv->ucode_beacon_time, | ||
323 | ucode_switch_time, | ||
324 | beacon_interval); | ||
325 | } | ||
326 | IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n", | ||
327 | cmd.switch_time); | ||
328 | ch_info = iwl_get_channel_info(priv, priv->band, ch); | ||
289 | if (ch_info) | 329 | if (ch_info) |
290 | cmd.expect_beacon = is_channel_radar(ch_info); | 330 | cmd.expect_beacon = is_channel_radar(ch_info); |
291 | else { | 331 | else { |
292 | IWL_ERR(priv, "invalid channel switch from %u to %u\n", | 332 | IWL_ERR(priv, "invalid channel switch from %u to %u\n", |
293 | priv->active_rxon.channel, channel); | 333 | priv->active_rxon.channel, ch); |
294 | return -EFAULT; | 334 | return -EFAULT; |
295 | } | 335 | } |
296 | priv->switch_rxon.channel = cpu_to_le16(channel); | 336 | priv->switch_rxon.channel = cmd.channel; |
297 | priv->switch_rxon.switch_in_progress = true; | 337 | priv->switch_rxon.switch_in_progress = true; |
298 | 338 | ||
299 | return iwl_send_cmd_sync(priv, &hcmd); | 339 | return iwl_send_cmd_sync(priv, &hcmd); |