diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-04-13 01:53:17 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-13 15:22:18 -0400 |
commit | 9b674a0207c9b75ddcdcdb07e46843fac8267507 (patch) | |
tree | 3a52d2c77ce5af8159dc165d7f0a8b99ed499f11 | |
parent | 832f6a18fc2aead14954c081ece03b7a5b425f81 (diff) |
ath9k_htc: Add TSF adjust capability
In multi-interface mode, beacons/probe responses that are
sent out must have their timestamp field updated. Calculate
the TSF adjustment value for each beaconing interface and set it
in the frame properly.
Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 12 |
4 files changed, 54 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 31c649605d79..87e4ca911a58 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -245,6 +245,7 @@ struct ath9k_htc_vif { | |||
245 | u16 seq_no; | 245 | u16 seq_no; |
246 | bool beacon_configured; | 246 | bool beacon_configured; |
247 | int bslot; | 247 | int bslot; |
248 | __le64 tsfadjust; | ||
248 | }; | 249 | }; |
249 | 250 | ||
250 | struct ath9k_vif_iter_data { | 251 | struct ath9k_vif_iter_data { |
@@ -480,6 +481,8 @@ void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv, | |||
480 | struct ieee80211_vif *vif); | 481 | struct ieee80211_vif *vif); |
481 | void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, | 482 | void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, |
482 | struct ieee80211_vif *vif); | 483 | struct ieee80211_vif *vif); |
484 | void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, | ||
485 | struct ieee80211_vif *vif); | ||
483 | void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); | 486 | void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); |
484 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | 487 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, |
485 | struct ieee80211_vif *vif); | 488 | struct ieee80211_vif *vif); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index b561f703e467..2fad613add51 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | |||
@@ -234,6 +234,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, | |||
234 | struct tx_beacon_header beacon_hdr; | 234 | struct tx_beacon_header beacon_hdr; |
235 | struct ath9k_htc_tx_ctl tx_ctl; | 235 | struct ath9k_htc_tx_ctl tx_ctl; |
236 | struct ieee80211_tx_info *info; | 236 | struct ieee80211_tx_info *info; |
237 | struct ieee80211_mgmt *mgmt; | ||
237 | struct sk_buff *beacon; | 238 | struct sk_buff *beacon; |
238 | u8 *tx_fhdr; | 239 | u8 *tx_fhdr; |
239 | 240 | ||
@@ -257,6 +258,13 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, | |||
257 | return; | 258 | return; |
258 | } | 259 | } |
259 | 260 | ||
261 | /* | ||
262 | * Update the TSF adjust value here, the HW will | ||
263 | * add this value for every beacon. | ||
264 | */ | ||
265 | mgmt = (struct ieee80211_mgmt *)beacon->data; | ||
266 | mgmt->u.beacon.timestamp = avp->tsfadjust; | ||
267 | |||
260 | info = IEEE80211_SKB_CB(beacon); | 268 | info = IEEE80211_SKB_CB(beacon); |
261 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 269 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
262 | struct ieee80211_hdr *hdr = | 270 | struct ieee80211_hdr *hdr = |
@@ -406,6 +414,34 @@ void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv, | |||
406 | "Removed interface at beacon slot: %d\n", avp->bslot); | 414 | "Removed interface at beacon slot: %d\n", avp->bslot); |
407 | } | 415 | } |
408 | 416 | ||
417 | /* | ||
418 | * Calculate the TSF adjustment value for all slots | ||
419 | * other than zero. | ||
420 | */ | ||
421 | void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv, | ||
422 | struct ieee80211_vif *vif) | ||
423 | { | ||
424 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
425 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv; | ||
426 | struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf; | ||
427 | u64 tsfadjust; | ||
428 | |||
429 | if (avp->bslot == 0) | ||
430 | return; | ||
431 | |||
432 | /* | ||
433 | * The beacon interval cannot be different for multi-AP mode, | ||
434 | * and we reach here only for VIF slots greater than zero, | ||
435 | * so beacon_interval is guaranteed to be set in cur_conf. | ||
436 | */ | ||
437 | tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF; | ||
438 | avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); | ||
439 | |||
440 | ath_dbg(common, ATH_DBG_CONFIG, | ||
441 | "tsfadjust is: %llu for bslot: %d\n", | ||
442 | (unsigned long long)tsfadjust, avp->bslot); | ||
443 | } | ||
444 | |||
409 | static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 445 | static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
410 | { | 446 | { |
411 | bool *beacon_configured = (bool *)data; | 447 | bool *beacon_configured = (bool *)data; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 293a9b38e22e..6926ac0d5e5c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -1291,8 +1291,10 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1291 | ath9k_htc_set_opmode(priv); | 1291 | ath9k_htc_set_opmode(priv); |
1292 | 1292 | ||
1293 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && | 1293 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && |
1294 | !(priv->op_flags & OP_ANI_RUNNING)) | 1294 | !(priv->op_flags & OP_ANI_RUNNING)) { |
1295 | ath9k_hw_set_tsfadjust(priv->ah, 1); | ||
1295 | ath9k_htc_start_ani(priv); | 1296 | ath9k_htc_start_ani(priv); |
1297 | } | ||
1296 | 1298 | ||
1297 | ath_dbg(common, ATH_DBG_CONFIG, | 1299 | ath_dbg(common, ATH_DBG_CONFIG, |
1298 | "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); | 1300 | "Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index); |
@@ -1652,6 +1654,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | |||
1652 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { | 1654 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) { |
1653 | ath_dbg(common, ATH_DBG_CONFIG, | 1655 | ath_dbg(common, ATH_DBG_CONFIG, |
1654 | "Beacon enabled for BSS: %pM\n", bss_conf->bssid); | 1656 | "Beacon enabled for BSS: %pM\n", bss_conf->bssid); |
1657 | ath9k_htc_set_tsfadjust(priv, vif); | ||
1655 | priv->op_flags |= OP_ENABLE_BEACON; | 1658 | priv->op_flags |= OP_ENABLE_BEACON; |
1656 | ath9k_htc_beacon_config(priv, vif); | 1659 | ath9k_htc_beacon_config(priv, vif); |
1657 | } | 1660 | } |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 4a4f27ba96af..b3f94850821e 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -82,11 +82,12 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, | |||
82 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | 82 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) |
83 | { | 83 | { |
84 | struct ieee80211_hdr *hdr; | 84 | struct ieee80211_hdr *hdr; |
85 | struct ieee80211_mgmt *mgmt; | ||
85 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 86 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
86 | struct ieee80211_sta *sta = tx_info->control.sta; | 87 | struct ieee80211_sta *sta = tx_info->control.sta; |
87 | struct ieee80211_vif *vif = tx_info->control.vif; | 88 | struct ieee80211_vif *vif = tx_info->control.vif; |
88 | struct ath9k_htc_sta *ista; | 89 | struct ath9k_htc_sta *ista; |
89 | struct ath9k_htc_vif *avp; | 90 | struct ath9k_htc_vif *avp = NULL; |
90 | struct ath9k_htc_tx_ctl tx_ctl; | 91 | struct ath9k_htc_tx_ctl tx_ctl; |
91 | enum htc_endpoint_id epid; | 92 | enum htc_endpoint_id epid; |
92 | u16 qnum; | 93 | u16 qnum; |
@@ -195,6 +196,15 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | |||
195 | 196 | ||
196 | memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); | 197 | memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); |
197 | 198 | ||
199 | /* | ||
200 | * Set the TSF adjust value for probe response | ||
201 | * frame also. | ||
202 | */ | ||
203 | if (avp && unlikely(ieee80211_is_probe_resp(fc))) { | ||
204 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
205 | mgmt->u.probe_resp.timestamp = avp->tsfadjust; | ||
206 | } | ||
207 | |||
198 | tx_ctl.type = ATH9K_HTC_NORMAL; | 208 | tx_ctl.type = ATH9K_HTC_NORMAL; |
199 | 209 | ||
200 | mgmt_hdr.node_idx = sta_idx; | 210 | mgmt_hdr.node_idx = sta_idx; |