aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-5000.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-5000.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c58
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
270static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel) 274static 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);