diff options
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 39 |
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 | ||
265 | struct 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 | ||
270 | struct 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 | ||
272 | struct ath9k_htc_tx_ctl { | 277 | struct ath9k_htc_tx_ctl { |
@@ -532,6 +537,8 @@ int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv); | |||
532 | int get_hw_qnum(u16 queue, int *hwq_map); | 537 | int get_hw_qnum(u16 queue, int *hwq_map); |
533 | int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, | 538 | int 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); |
540 | void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); | ||
541 | void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); | ||
535 | 542 | ||
536 | int ath9k_rx_init(struct ath9k_htc_priv *priv); | 543 | int ath9k_rx_init(struct ath9k_htc_priv *priv); |
537 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); | 544 | void 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 | ||
868 | fail_tx: | 863 | fail_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 | ||
56 | void 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 | |||
68 | void 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 | |||
56 | int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, | 79 | int 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 | ||
322 | void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | 341 | void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, |