From: Arik Nemtsov <arik@wizery.com>
To: <linux-wireless@vger.kernel.org>
Cc: Luciano Coelho <coelho@ti.com>, Arik Nemtsov <arik@wizery.com>
Subject: [PATCH 3/3] wl12xx: implement Tx watermarks per AC
Date: Fri, 24 Jun 2011 13:03:37 +0300 [thread overview]
Message-ID: <1308909817-25689-3-git-send-email-arik@wizery.com> (raw)
In-Reply-To: <1308909817-25689-1-git-send-email-arik@wizery.com>
Each AC is stopped when its queue is filled up to the high watermark,
and restarted when its queue it lower than the low watermark. This
ensures congested ACs are not able to starve other ACs.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/main.c | 13 +++++++------
drivers/net/wireless/wl12xx/tx.c | 20 +++++++++++++-------
drivers/net/wireless/wl12xx/tx.h | 16 ++++++++++++++++
drivers/net/wireless/wl12xx/wl12xx.h | 1 +
4 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index d3e1eb6..166287f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1371,10 +1371,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1271 *wl = hw->priv;
unsigned long flags;
- int q;
+ int q, mapping;
u8 hlid = 0;
- q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+ mapping = skb_get_queue_mapping(skb);
+ q = wl1271_tx_get_queue(mapping);
if (wl->bss_type == BSS_TYPE_AP_BSS)
hlid = wl1271_tx_get_hlid(skb);
@@ -1387,10 +1388,10 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
- wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
- ieee80211_stop_queues(wl->hw);
- set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+ if (skb_queue_len(&wl->tx_queue[q]) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+ wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
+ ieee80211_stop_queue(wl->hw, mapping);
+ set_bit(q, &wl->stopped_queues_map);
}
/* queue the packet */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index ce33590..ef54cee 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -444,14 +444,19 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
{
unsigned long flags;
+ int i;
- if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
- wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) {
- /* firmware buffer has space, restart queues */
- spin_lock_irqsave(&wl->wl_lock, flags);
- ieee80211_wake_queues(wl->hw);
- clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
- spin_unlock_irqrestore(&wl->wl_lock, flags);
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ if (test_bit(i, &wl->stopped_queues_map) &&
+ skb_queue_len(&wl->tx_queue[i]) <=
+ WL1271_TX_QUEUE_LOW_WATERMARK) {
+ /* firmware buffer has space, restart queues */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ ieee80211_wake_queue(wl->hw,
+ wl1271_tx_get_mac80211_queue(i));
+ clear_bit(i, &wl->stopped_queues_map);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ }
}
}
@@ -849,6 +854,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
}
wl->tx_queue_count = 0;
+ wl->stopped_queues_map = 0;
/*
* Make sure the driver is at a consistent state, in case this
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 832f925..f79d3c0 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -182,6 +182,22 @@ static inline int wl1271_tx_get_queue(int queue)
}
}
+static inline int wl1271_tx_get_mac80211_queue(int queue)
+{
+ switch (queue) {
+ case CONF_TX_AC_VO:
+ return 0;
+ case CONF_TX_AC_VI:
+ return 1;
+ case CONF_TX_AC_BE:
+ return 2;
+ case CONF_TX_AC_BK:
+ return 3;
+ default:
+ return 2;
+ }
+}
+
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 89ba1fc..49aee9f 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -437,6 +437,7 @@ struct wl1271 {
/* Frames scheduled for transmission, not handled yet */
struct sk_buff_head tx_queue[NUM_TX_QUEUES];
int tx_queue_count;
+ long stopped_queues_map;
/* Frames received, not handled yet by mac80211 */
struct sk_buff_head deferred_rx_queue;
--
1.7.4.1
next prev parent reply other threads:[~2011-06-24 10:03 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-24 10:03 [PATCH 1/3] wl12xx: schedule TX packets according to FW occupancy Arik Nemtsov
2011-06-24 10:03 ` [PATCH 2/3] wl12xx: Increase low & high TX watermarks Arik Nemtsov
2011-06-24 10:03 ` Arik Nemtsov [this message]
2011-07-05 17:49 ` [PATCH 1/3] wl12xx: schedule TX packets according to FW occupancy Luciano Coelho
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1308909817-25689-3-git-send-email-arik@wizery.com \
--to=arik@wizery.com \
--cc=coelho@ti.com \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox