aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2011-04-13 01:53:34 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-13 15:22:26 -0400
commit7d547eb4bb664c5a6b7c8790c2ecb0aec5d15385 (patch)
tree3a4b7627fa9c6e0e98b0948723eb2458c83e2f5f /drivers/net
parent2493a547ee81e6daca812d5dd7cf9357aebc379b (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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c43
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c14
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 87e4ca911a5..a072a9eb3f3 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
506int ath9k_tx_init(struct ath9k_htc_priv *priv); 509int ath9k_tx_init(struct ath9k_htc_priv *priv);
507void ath9k_tx_tasklet(unsigned long data); 510void ath9k_tx_tasklet(unsigned long data);
508int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); 511int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
512 struct sk_buff *skb, bool is_cab);
509void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); 513void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
510bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype); 514bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype);
511int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); 515int 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 7aafd217939..c96779c2429 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
275static 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
275static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, 317static 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 9405e0ad703..b1c68bff72a 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 6926ac0d5e5..8f38075d124 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 b3f94850821..0e285589366 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
82int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) 82int 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 232send:
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);