aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2011-04-13 01:55:29 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-13 15:23:42 -0400
commit8e86a54715c4102a8ed697939de9ebd9715dc59c (patch)
tree6ec011dfe718973e3aeba78176a51302744f71d5
parent3deff76095c4ac4252e27c537db3041f619c23a2 (diff)
ath9k_htc: Fix TX queue management
Handle queue start/stop properly by maintaining a counter to check if the pending frame count has exceeded the threshold. Otherwise, packets would be dropped needlessly. While at it, use a simple flag to track queue status and use helper functions too. 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.h13
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c21
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c39
5 files changed, 52 insertions, 27 deletions
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 3185fe7568c..fc4c466e756 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -262,11 +262,16 @@ struct ath9k_htc_rx {
262 spinlock_t rxbuflock; 262 spinlock_t rxbuflock;
263}; 263};
264 264
265struct ath9k_htc_tx { 265#define ATH9K_HTC_TX_RESERVE 10
266 bool tx_queues_stop; 266#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
267 spinlock_t tx_lock; 267
268#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
268 269
270struct ath9k_htc_tx {
271 u8 flags;
272 int queued_cnt;
269 struct sk_buff_head tx_queue; 273 struct sk_buff_head tx_queue;
274 spinlock_t tx_lock;
270}; 275};
271 276
272struct ath9k_htc_tx_ctl { 277struct ath9k_htc_tx_ctl {
@@ -532,6 +537,8 @@ int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
532int get_hw_qnum(u16 queue, int *hwq_map); 537int get_hw_qnum(u16 queue, int *hwq_map);
533int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 538int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
534 struct ath9k_tx_queue_info *qinfo); 539 struct ath9k_tx_queue_info *qinfo);
540void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv);
541void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv);
535 542
536int ath9k_rx_init(struct ath9k_htc_priv *priv); 543int ath9k_rx_init(struct ath9k_htc_priv *priv);
537void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); 544void ath9k_rx_cleanup(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 713def18451..de37d46bb0d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -326,6 +326,10 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
326 ath_dbg(common, ATH_DBG_FATAL, 326 ath_dbg(common, ATH_DBG_FATAL,
327 "Failed to send CAB frame\n"); 327 "Failed to send CAB frame\n");
328 dev_kfree_skb_any(skb); 328 dev_kfree_skb_any(skb);
329 } else {
330 spin_lock_bh(&priv->tx.tx_lock);
331 priv->tx.queued_cnt++;
332 spin_unlock_bh(&priv->tx.tx_lock);
329 } 333 }
330 next: 334 next:
331 skb = ieee80211_get_buffered_bc(priv->hw, vif); 335 skb = ieee80211_get_buffered_bc(priv->hw, vif);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 1f6df4a1d22..92e4b312a98 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -399,7 +399,7 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
399 /* Start TX */ 399 /* Start TX */
400 htc_start(priv->htc); 400 htc_start(priv->htc);
401 spin_lock_bh(&priv->tx.tx_lock); 401 spin_lock_bh(&priv->tx.tx_lock);
402 priv->tx.tx_queues_stop = false; 402 priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
403 spin_unlock_bh(&priv->tx.tx_lock); 403 spin_unlock_bh(&priv->tx.tx_lock);
404 ieee80211_wake_queues(hw); 404 ieee80211_wake_queues(hw);
405 405
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index ff3a49577a0..690113673d2 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -833,6 +833,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
833{ 833{
834 struct ieee80211_hdr *hdr; 834 struct ieee80211_hdr *hdr;
835 struct ath9k_htc_priv *priv = hw->priv; 835 struct ath9k_htc_priv *priv = hw->priv;
836 struct ath_common *common = ath9k_hw_common(priv->ah);
836 int padpos, padsize, ret; 837 int padpos, padsize, ret;
837 838
838 hdr = (struct ieee80211_hdr *) skb->data; 839 hdr = (struct ieee80211_hdr *) skb->data;
@@ -841,28 +842,22 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
841 padpos = ath9k_cmn_padpos(hdr->frame_control); 842 padpos = ath9k_cmn_padpos(hdr->frame_control);
842 padsize = padpos & 3; 843 padsize = padpos & 3;
843 if (padsize && skb->len > padpos) { 844 if (padsize && skb->len > padpos) {
844 if (skb_headroom(skb) < padsize) 845 if (skb_headroom(skb) < padsize) {
846 ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n");
845 goto fail_tx; 847 goto fail_tx;
848 }
846 skb_push(skb, padsize); 849 skb_push(skb, padsize);
847 memmove(skb->data, skb->data + padsize, padpos); 850 memmove(skb->data, skb->data + padsize, padpos);
848 } 851 }
849 852
850 ret = ath9k_htc_tx_start(priv, skb, false); 853 ret = ath9k_htc_tx_start(priv, skb, false);
851 if (ret != 0) { 854 if (ret != 0) {
852 if (ret == -ENOMEM) { 855 ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n");
853 ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
854 "Stopping TX queues\n");
855 ieee80211_stop_queues(hw);
856 spin_lock_bh(&priv->tx.tx_lock);
857 priv->tx.tx_queues_stop = true;
858 spin_unlock_bh(&priv->tx.tx_lock);
859 } else {
860 ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
861 "Tx failed\n");
862 }
863 goto fail_tx; 856 goto fail_tx;
864 } 857 }
865 858
859 ath9k_htc_check_stop_queues(priv);
860
866 return; 861 return;
867 862
868fail_tx: 863fail_tx:
@@ -924,7 +919,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
924 htc_start(priv->htc); 919 htc_start(priv->htc);
925 920
926 spin_lock_bh(&priv->tx.tx_lock); 921 spin_lock_bh(&priv->tx.tx_lock);
927 priv->tx.tx_queues_stop = false; 922 priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
928 spin_unlock_bh(&priv->tx.tx_lock); 923 spin_unlock_bh(&priv->tx.tx_lock);
929 924
930 ieee80211_wake_queues(hw); 925 ieee80211_wake_queues(hw);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 6f7987d7b6b..1cbe194179a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -53,6 +53,29 @@ int get_hw_qnum(u16 queue, int *hwq_map)
53 } 53 }
54} 54}
55 55
56void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv)
57{
58 spin_lock_bh(&priv->tx.tx_lock);
59 priv->tx.queued_cnt++;
60 if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) &&
61 !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
62 priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP;
63 ieee80211_stop_queues(priv->hw);
64 }
65 spin_unlock_bh(&priv->tx.tx_lock);
66}
67
68void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv)
69{
70 spin_lock_bh(&priv->tx.tx_lock);
71 if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) &&
72 (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
73 priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
74 ieee80211_wake_queues(priv->hw);
75 }
76 spin_unlock_bh(&priv->tx.tx_lock);
77}
78
56int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 79int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
57 struct ath9k_tx_queue_info *qinfo) 80 struct ath9k_tx_queue_info *qinfo)
58{ 81{
@@ -302,21 +325,17 @@ void ath9k_tx_tasklet(unsigned long data)
302 rcu_read_unlock(); 325 rcu_read_unlock();
303 326
304 send_mac80211: 327 send_mac80211:
328 spin_lock_bh(&priv->tx.tx_lock);
329 if (WARN_ON(--priv->tx.queued_cnt < 0))
330 priv->tx.queued_cnt = 0;
331 spin_unlock_bh(&priv->tx.tx_lock);
332
305 /* Send status to mac80211 */ 333 /* Send status to mac80211 */
306 ieee80211_tx_status(priv->hw, skb); 334 ieee80211_tx_status(priv->hw, skb);
307 } 335 }
308 336
309 /* Wake TX queues if needed */ 337 /* Wake TX queues if needed */
310 spin_lock_bh(&priv->tx.tx_lock); 338 ath9k_htc_check_wake_queues(priv);
311 if (priv->tx.tx_queues_stop) {
312 priv->tx.tx_queues_stop = false;
313 spin_unlock_bh(&priv->tx.tx_lock);
314 ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
315 "Waking up TX queues\n");
316 ieee80211_wake_queues(priv->hw);
317 return;
318 }
319 spin_unlock_bh(&priv->tx.tx_lock);
320} 339}
321 340
322void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, 341void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,