diff options
author | Sujith Manoharan <Sujith.Manoharan@atheros.com> | 2011-04-13 01:53:34 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-04-13 15:22:26 -0400 |
commit | 7d547eb4bb664c5a6b7c8790c2ecb0aec5d15385 (patch) | |
tree | 3a4b7627fa9c6e0e98b0948723eb2458c83e2f5f | |
parent | 2493a547ee81e6daca812d5dd7cf9357aebc379b (diff) |
ath9k_htc: Handle buffered frames in AP mode
Use the CAB endpoint to send buffered multicast or
broadcast frames after each SWBA event.
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 | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 43 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_init.c | 3 | ||||
-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 | 14 |
5 files changed, 65 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 87e4ca911a58..a072a9eb3f3e 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -292,6 +292,7 @@ struct ath9k_htc_tx_ctl { | |||
292 | 292 | ||
293 | #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) | 293 | #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) |
294 | #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) | 294 | #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) |
295 | #define CAB_STAT_INC priv->debug.tx_stats.cab_queued++ | ||
295 | 296 | ||
296 | #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) | 297 | #define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++) |
297 | 298 | ||
@@ -301,6 +302,7 @@ struct ath_tx_stats { | |||
301 | u32 skb_queued; | 302 | u32 skb_queued; |
302 | u32 skb_completed; | 303 | u32 skb_completed; |
303 | u32 skb_dropped; | 304 | u32 skb_dropped; |
305 | u32 cab_queued; | ||
304 | u32 queue_stats[WME_NUM_AC]; | 306 | u32 queue_stats[WME_NUM_AC]; |
305 | }; | 307 | }; |
306 | 308 | ||
@@ -324,6 +326,7 @@ struct ath9k_debug { | |||
324 | 326 | ||
325 | #define TX_STAT_INC(c) do { } while (0) | 327 | #define TX_STAT_INC(c) do { } while (0) |
326 | #define RX_STAT_INC(c) do { } while (0) | 328 | #define RX_STAT_INC(c) do { } while (0) |
329 | #define CAB_STAT_INC do { } while (0) | ||
327 | 330 | ||
328 | #define TX_QSTAT_INC(c) do { } while (0) | 331 | #define TX_QSTAT_INC(c) do { } while (0) |
329 | 332 | ||
@@ -505,7 +508,8 @@ void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); | |||
505 | 508 | ||
506 | int ath9k_tx_init(struct ath9k_htc_priv *priv); | 509 | int ath9k_tx_init(struct ath9k_htc_priv *priv); |
507 | void ath9k_tx_tasklet(unsigned long data); | 510 | void ath9k_tx_tasklet(unsigned long data); |
508 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); | 511 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, |
512 | struct sk_buff *skb, bool is_cab); | ||
509 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); | 513 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); |
510 | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); | 514 | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); |
511 | int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); | 515 | int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 7aafd2179398..c96779c24296 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | |||
@@ -272,6 +272,48 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, | |||
272 | dev_kfree_skb_any(skb); | 272 | dev_kfree_skb_any(skb); |
273 | } | 273 | } |
274 | 274 | ||
275 | static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv, | ||
276 | int slot) | ||
277 | { | ||
278 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
279 | struct ieee80211_vif *vif; | ||
280 | struct sk_buff *skb; | ||
281 | struct ieee80211_hdr *hdr; | ||
282 | int padpos, padsize, ret; | ||
283 | |||
284 | spin_lock_bh(&priv->beacon_lock); | ||
285 | |||
286 | vif = priv->cur_beacon_conf.bslot[slot]; | ||
287 | |||
288 | skb = ieee80211_get_buffered_bc(priv->hw, vif); | ||
289 | |||
290 | while(skb) { | ||
291 | hdr = (struct ieee80211_hdr *) skb->data; | ||
292 | |||
293 | padpos = ath9k_cmn_padpos(hdr->frame_control); | ||
294 | padsize = padpos & 3; | ||
295 | if (padsize && skb->len > padpos) { | ||
296 | if (skb_headroom(skb) < padsize) { | ||
297 | dev_kfree_skb_any(skb); | ||
298 | goto next; | ||
299 | } | ||
300 | skb_push(skb, padsize); | ||
301 | memmove(skb->data, skb->data + padsize, padpos); | ||
302 | } | ||
303 | |||
304 | ret = ath9k_htc_tx_start(priv, skb, true); | ||
305 | if (ret != 0) { | ||
306 | ath_dbg(common, ATH_DBG_FATAL, | ||
307 | "Failed to send CAB frame\n"); | ||
308 | dev_kfree_skb_any(skb); | ||
309 | } | ||
310 | next: | ||
311 | skb = ieee80211_get_buffered_bc(priv->hw, vif); | ||
312 | } | ||
313 | |||
314 | spin_unlock_bh(&priv->beacon_lock); | ||
315 | } | ||
316 | |||
275 | static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, | 317 | static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, |
276 | int slot) | 318 | int slot) |
277 | { | 319 | { |
@@ -390,6 +432,7 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv) | |||
390 | } | 432 | } |
391 | spin_unlock_bh(&priv->beacon_lock); | 433 | spin_unlock_bh(&priv->beacon_lock); |
392 | 434 | ||
435 | ath9k_htc_send_buffered(priv, slot); | ||
393 | ath9k_htc_send_beacon(priv, slot); | 436 | ath9k_htc_send_beacon(priv, slot); |
394 | } | 437 | } |
395 | 438 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 9405e0ad7032..b1c68bff72a6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -748,7 +748,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, | |||
748 | IEEE80211_HW_HAS_RATE_CONTROL | | 748 | IEEE80211_HW_HAS_RATE_CONTROL | |
749 | IEEE80211_HW_RX_INCLUDES_FCS | | 749 | IEEE80211_HW_RX_INCLUDES_FCS | |
750 | IEEE80211_HW_SUPPORTS_PS | | 750 | IEEE80211_HW_SUPPORTS_PS | |
751 | IEEE80211_HW_PS_NULLFUNC_STACK; | 751 | IEEE80211_HW_PS_NULLFUNC_STACK | |
752 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; | ||
752 | 753 | ||
753 | hw->wiphy->interface_modes = | 754 | hw->wiphy->interface_modes = |
754 | BIT(NL80211_IFTYPE_STATION) | | 755 | BIT(NL80211_IFTYPE_STATION) | |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 6926ac0d5e5c..8f38075d1240 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -797,6 +797,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
797 | len += snprintf(buf + len, sizeof(buf) - len, | 797 | len += snprintf(buf + len, sizeof(buf) - len, |
798 | "%20s : %10u\n", "SKBs dropped", | 798 | "%20s : %10u\n", "SKBs dropped", |
799 | priv->debug.tx_stats.skb_dropped); | 799 | priv->debug.tx_stats.skb_dropped); |
800 | len += snprintf(buf + len, sizeof(buf) - len, | ||
801 | "%20s : %10u\n", "CAB queued", | ||
802 | priv->debug.tx_stats.cab_queued); | ||
800 | 803 | ||
801 | len += snprintf(buf + len, sizeof(buf) - len, | 804 | len += snprintf(buf + len, sizeof(buf) - len, |
802 | "%20s : %10u\n", "BE queued", | 805 | "%20s : %10u\n", "BE queued", |
@@ -1054,7 +1057,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1054 | memmove(skb->data, skb->data + padsize, padpos); | 1057 | memmove(skb->data, skb->data + padsize, padpos); |
1055 | } | 1058 | } |
1056 | 1059 | ||
1057 | ret = ath9k_htc_tx_start(priv, skb); | 1060 | ret = ath9k_htc_tx_start(priv, skb, false); |
1058 | if (ret != 0) { | 1061 | if (ret != 0) { |
1059 | if (ret == -ENOMEM) { | 1062 | if (ret == -ENOMEM) { |
1060 | ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, | 1063 | ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index b3f94850821e..0e2855893669 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -79,7 +79,8 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, | |||
79 | return error; | 79 | return error; |
80 | } | 80 | } |
81 | 81 | ||
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, |
83 | struct sk_buff *skb, bool is_cab) | ||
83 | { | 84 | { |
84 | struct ieee80211_hdr *hdr; | 85 | struct ieee80211_hdr *hdr; |
85 | struct ieee80211_mgmt *mgmt; | 86 | struct ieee80211_mgmt *mgmt; |
@@ -170,6 +171,12 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | |||
170 | tx_fhdr = skb_push(skb, sizeof(tx_hdr)); | 171 | tx_fhdr = skb_push(skb, sizeof(tx_hdr)); |
171 | memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); | 172 | memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); |
172 | 173 | ||
174 | if (is_cab) { | ||
175 | CAB_STAT_INC; | ||
176 | epid = priv->cab_ep; | ||
177 | goto send; | ||
178 | } | ||
179 | |||
173 | qnum = skb_get_queue_mapping(skb); | 180 | qnum = skb_get_queue_mapping(skb); |
174 | 181 | ||
175 | switch (qnum) { | 182 | switch (qnum) { |
@@ -222,7 +229,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | |||
222 | memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); | 229 | memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); |
223 | epid = priv->mgmt_ep; | 230 | epid = priv->mgmt_ep; |
224 | } | 231 | } |
225 | 232 | send: | |
226 | return htc_send(priv->htc, skb, epid, &tx_ctl); | 233 | return htc_send(priv->htc, skb, epid, &tx_ctl); |
227 | } | 234 | } |
228 | 235 | ||
@@ -326,7 +333,8 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | |||
326 | } else if ((ep_id == priv->data_bk_ep) || | 333 | } else if ((ep_id == priv->data_bk_ep) || |
327 | (ep_id == priv->data_be_ep) || | 334 | (ep_id == priv->data_be_ep) || |
328 | (ep_id == priv->data_vi_ep) || | 335 | (ep_id == priv->data_vi_ep) || |
329 | (ep_id == priv->data_vo_ep)) { | 336 | (ep_id == priv->data_vo_ep) || |
337 | (ep_id == priv->cab_ep)) { | ||
330 | skb_pull(skb, sizeof(struct tx_frame_hdr)); | 338 | skb_pull(skb, sizeof(struct tx_frame_hdr)); |
331 | } else { | 339 | } else { |
332 | ath_err(common, "Unsupported TX EPID: %d\n", ep_id); | 340 | ath_err(common, "Unsupported TX EPID: %d\n", ep_id); |