summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorIdo Yariv <ido@wizery.com>2011-03-01 15:14:43 +0200
committerLuciano Coelho <coelho@ti.com>2011-03-03 16:12:57 +0200
commitb07d4037051318d47c055384ef887535a0ed2d1e (patch)
tree87be47dfa0c80bdf6570e613269421b937a27d87 /drivers/net/wireless/wl12xx
parent2da69b890f47852dc368136375f49a5d24e2d9a1 (diff)
downloadlwn-b07d4037051318d47c055384ef887535a0ed2d1e.tar.gz
lwn-b07d4037051318d47c055384ef887535a0ed2d1e.zip
wl12xx: Avoid redundant TX work
TX might be handled in the threaded IRQ handler, in which case, TX work might be scheduled just to discover it has nothing to do. Save a few context switches by cancelling redundant TX work in case TX is about to be handled in the threaded IRQ handler. Also, avoid scheduling TX work from wl1271_op_tx if not needed. Signed-off-by: Ido Yariv <ido@wizery.com> Reviewed-by: Luciano Coelho <coelho@ti.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/main.c32
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h1
2 files changed, 28 insertions, 5 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index f408c5a84cc9..2679abcf5a05 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -668,6 +668,11 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
struct wl1271 *wl = (struct wl1271 *)cookie;
bool done = false;
unsigned int defer_count;
+ unsigned long flags;
+
+ /* TX might be handled here, avoid redundant work */
+ set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
+ cancel_work_sync(&wl->tx_work);
mutex_lock(&wl->mutex);
@@ -712,13 +717,17 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_rx(wl, &wl->fw_status->common);
/* Check if any tx blocks were freed */
+ spin_lock_irqsave(&wl->wl_lock, flags);
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
wl->tx_queue_count) {
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
/*
* In order to avoid starvation of the TX path,
* call the work function directly.
*/
wl1271_tx_work_locked(wl);
+ } else {
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}
/* check for tx results */
@@ -754,6 +763,14 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_ps_elp_sleep(wl);
out:
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ /* In case TX was not handled here, queue TX work */
+ clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
+ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
+ wl->tx_queue_count)
+ ieee80211_queue_work(wl->hw, &wl->tx_work);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
mutex_unlock(&wl->mutex);
return IRQ_HANDLED;
@@ -1068,7 +1085,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
int q;
u8 hlid = 0;
+ q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ hlid = wl1271_tx_get_hlid(skb);
+
spin_lock_irqsave(&wl->wl_lock, flags);
+
wl->tx_queue_count++;
/*
@@ -1081,12 +1104,8 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
}
- spin_unlock_irqrestore(&wl->wl_lock, flags);
-
/* queue the packet */
- q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
if (wl->bss_type == BSS_TYPE_AP_BSS) {
- hlid = wl1271_tx_get_hlid(skb);
wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
} else {
@@ -1098,8 +1117,11 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* before that, the tx_work will not be initialized!
*/
- if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
+ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
+ !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->tx_work);
+
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
}
static struct notifier_block wl1271_dev_notifier = {
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index e395c0c4ebbd..86be83e25ec5 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -317,6 +317,7 @@ enum wl12xx_flags {
WL1271_FLAG_JOINED,
WL1271_FLAG_GPIO_POWER,
WL1271_FLAG_TX_QUEUE_STOPPED,
+ WL1271_FLAG_TX_PENDING,
WL1271_FLAG_IN_ELP,
WL1271_FLAG_PSM,
WL1271_FLAG_PSM_REQUESTED,