* [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout
@ 2012-02-27 22:41 Arik Nemtsov
2012-02-27 22:41 ` [PATCH 2/7] wl12xx: change bits in the link_map under spin lock Arik Nemtsov
` (6 more replies)
0 siblings, 7 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
With PSM handled in FW, the checks in wl1271_elp_work() are always true.
Thus during active traffic we constantly enter and exit ELP (many times
per second). As each ELP exit takes ~10ms, this can have an adverse
effect on throughput and interactivity.
Set the ELP timeout to the dyn-ps timeout. This period is longer and
avoids the above problem. It also makes sense to stay out of ELP while
we are awake on the network, to minimize delays in Tx/Rx. The same thing
was done by the mac80211 dynamic-ps mechanism before the FW DPS changes.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/ps.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 23d6750..78f598b 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -69,8 +69,6 @@ out:
mutex_unlock(&wl->mutex);
}
-#define ELP_ENTRY_DELAY 5
-
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
@@ -90,7 +88,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
}
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
- msecs_to_jiffies(ELP_ENTRY_DELAY));
+ msecs_to_jiffies(wl->conf.conn.dynamic_ps_timeout));
}
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/7] wl12xx: change bits in the link_map under spin lock
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
@ 2012-02-27 22:41 ` Arik Nemtsov
2012-02-27 22:41 ` [PATCH 3/7] wl12xx: reset link Tx queues when freeing it Arik Nemtsov
` (5 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
These bits are used in op_tx to determine if a packet should be dropped.
As such we should use the spin lock to sync the state.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/cmd.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index b776d9d..ef994da 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -459,23 +459,32 @@ out:
int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
{
+ unsigned long flags;
u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS);
if (link >= WL12XX_MAX_LINKS)
return -EBUSY;
+ /* these bits are used by op_tx */
+ spin_lock_irqsave(&wl->wl_lock, flags);
__set_bit(link, wl->links_map);
__set_bit(link, wlvif->links_map);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
*hlid = link;
return 0;
}
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
{
+ unsigned long flags;
+
if (*hlid == WL12XX_INVALID_LINK_ID)
return;
+ /* these bits are used by op_tx */
+ spin_lock_irqsave(&wl->wl_lock, flags);
__clear_bit(*hlid, wl->links_map);
__clear_bit(*hlid, wlvif->links_map);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
*hlid = WL12XX_INVALID_LINK_ID;
}
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/7] wl12xx: reset link Tx queues when freeing it
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
2012-02-27 22:41 ` [PATCH 2/7] wl12xx: change bits in the link_map under spin lock Arik Nemtsov
@ 2012-02-27 22:41 ` Arik Nemtsov
2012-02-28 9:51 ` Luciano Coelho
2012-02-27 22:41 ` [PATCH 4/7] wl12xx: avoid starving the system hlid Arik Nemtsov
` (4 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
Before, the link was first freed (invalidating it in the map), and later
on vif removal, all valid wlvif-related links were reset. Since these
links were already invalid, we failed to reset them.
The bug was made worse by op_stop, which set the tx_queue_count to 0
arbitrarily. This resulted in a negative tx_queue_count in some scenarios.
Fix this by resetting the Tx-queues of a link when freeing it. Add a
WARN_ON and reset all link Tx-queues in op_stop, to avoid a negative
tx_queue_count.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/cmd.c | 7 +++++++
drivers/net/wireless/wl12xx/main.c | 1 -
drivers/net/wireless/wl12xx/tx.c | 13 ++++++++++---
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index ef994da..ae1f3d7 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -485,6 +485,13 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
__clear_bit(*hlid, wl->links_map);
__clear_bit(*hlid, wlvif->links_map);
spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ /*
+ * At this point op_tx() will not add more packets to the queues. We
+ * can purge them.
+ */
+ wl1271_tx_reset_link_queues(wl, *hlid);
+
*hlid = WL12XX_INVALID_LINK_ID;
}
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index adf9bbc..712e385 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -4228,7 +4228,6 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
clear_bit(hlid, wlvif->ap.sta_hlid_map);
memset(wl->links[hlid].addr, 0, ETH_ALEN);
wl->links[hlid].ba_bitmap = 0;
- wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
wl12xx_free_link(wl, wlvif, &hlid);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 6446e4d..311b5a2 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -527,6 +527,7 @@ static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
+ WARN_ON(wl->tx_queue_count[q] <= 0);
wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
@@ -602,6 +603,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
skb = wl->dummy_packet;
q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
+ WARN_ON(wl->tx_queue_count[q] <= 0);
wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
@@ -959,7 +961,6 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
else
wlvif->sta.ba_rx_bitmap = 0;
- wl1271_tx_reset_link_queues(wl, i);
wl->links[i].allocated_pkts = 0;
wl->links[i].prev_freed_pkts = 0;
}
@@ -973,8 +974,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
struct sk_buff *skb;
struct ieee80211_tx_info *info;
- for (i = 0; i < NUM_TX_QUEUES; i++)
- wl->tx_queue_count[i] = 0;
+ /* only reset the queues if something bad happened */
+ if (WARN_ON(wl1271_tx_total_queue_count(wl) != 0)) {
+ for (i = 0; i < WL12XX_MAX_LINKS; i++)
+ wl1271_tx_reset_link_queues(wl, i);
+
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_queue_count[i] = 0;
+ }
wl->stopped_queues_map = 0;
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/7] wl12xx: avoid starving the system hlid
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
2012-02-27 22:41 ` [PATCH 2/7] wl12xx: change bits in the link_map under spin lock Arik Nemtsov
2012-02-27 22:41 ` [PATCH 3/7] wl12xx: reset link Tx queues when freeing it Arik Nemtsov
@ 2012-02-27 22:41 ` Arik Nemtsov
2012-02-27 22:41 ` [PATCH 5/7] wl12xx: flush all Tx queues on tx_flush timeout Arik Nemtsov
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
Re-factor the Tx scheduler so that the system_hlid is taken into account
before restarting an iteration over the wlvifs. Previously this
hlid had a lower priority and would starve if some wlvif had many
packets.
In addition avoid iterating over wlvifs past last_wlvif when performing
the a second pass. If we had packets in those wlvifs they would have
been found earlier.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/tx.c | 17 +++++++++++++----
1 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 311b5a2..76480a0 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -572,6 +572,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
struct wl12xx_vif *wlvif = wl->last_wlvif;
struct sk_buff *skb = NULL;
+ /* continue from last wlvif (round robin) */
if (wlvif) {
wl12xx_for_each_wlvif_continue(wl, wlvif) {
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
@@ -582,7 +583,11 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
}
}
- /* do another pass */
+ /* dequeue from the system HLID before the restarting wlvif list */
+ if (!skb)
+ skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
+
+ /* do a new pass over the wlvif list */
if (!skb) {
wl12xx_for_each_wlvif(wl, wlvif) {
skb = wl12xx_vif_skb_dequeue(wl, wlvif);
@@ -590,12 +595,16 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
wl->last_wlvif = wlvif;
break;
}
+
+ /*
+ * No need to continue after last_wlvif. The previous
+ * pass should have found it.
+ */
+ if (wlvif == wl->last_wlvif)
+ break;
}
}
- if (!skb)
- skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]);
-
if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
int q;
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5/7] wl12xx: flush all Tx queues on tx_flush timeout
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
` (2 preceding siblings ...)
2012-02-27 22:41 ` [PATCH 4/7] wl12xx: avoid starving the system hlid Arik Nemtsov
@ 2012-02-27 22:41 ` Arik Nemtsov
2012-02-27 22:41 ` [PATCH 6/7] wl12xx: flush Tx during suspend and 802.11h chan switch Arik Nemtsov
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
Ensure our queues are empty at the end of a tx_flush(), in case we
timeout on passively waiting for them. This makes sure no left-overs are
transmitted when we are on the wrong channel.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/tx.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 76480a0..3540d4a 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -1040,6 +1040,7 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
void wl1271_tx_flush(struct wl1271 *wl)
{
unsigned long timeout;
+ int i;
timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
while (!time_after(jiffies, timeout)) {
@@ -1057,6 +1058,12 @@ void wl1271_tx_flush(struct wl1271 *wl)
}
wl1271_warning("Unable to flush all TX buffers, timed out.");
+
+ /* forcibly flush all Tx buffers on our queues */
+ mutex_lock(&wl->mutex);
+ for (i = 0; i < WL12XX_MAX_LINKS; i++)
+ wl1271_tx_reset_link_queues(wl, i);
+ mutex_unlock(&wl->mutex);
}
u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 6/7] wl12xx: flush Tx during suspend and 802.11h chan switch
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
` (3 preceding siblings ...)
2012-02-27 22:41 ` [PATCH 5/7] wl12xx: flush all Tx queues on tx_flush timeout Arik Nemtsov
@ 2012-02-27 22:41 ` Arik Nemtsov
2012-02-27 22:41 ` [PATCH 7/7] wl12xx: increase dynamic PS timeout to 200ms Arik Nemtsov
2012-02-28 12:05 ` [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Luciano Coelho
6 siblings, 0 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
Flush our Tx queues before suspending or changing the channel due to a
channel_switch element in the AP beacon.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/main.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 712e385..ad1a4ad 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1737,6 +1737,8 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
WARN_ON(!wow || !wow->any);
+ wl1271_tx_flush(wl);
+
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
ret = wl1271_configure_suspend(wl, wlvif);
@@ -4496,6 +4498,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
+ wl1271_tx_flush(wl);
+
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF)) {
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 7/7] wl12xx: increase dynamic PS timeout to 200ms
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
` (4 preceding siblings ...)
2012-02-27 22:41 ` [PATCH 6/7] wl12xx: flush Tx during suspend and 802.11h chan switch Arik Nemtsov
@ 2012-02-27 22:41 ` Arik Nemtsov
2012-02-28 12:05 ` [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Luciano Coelho
6 siblings, 0 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-27 22:41 UTC (permalink / raw)
To: linux-wireless; +Cc: Luciano Coelho, Arik Nemtsov
This ensures the user won't encounter lag associated with getting in and
out of PSM when the card is in use.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
---
drivers/net/wireless/wl12xx/main.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index ad1a4ad..418b2b8 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -246,7 +246,7 @@ static struct conf_drv_settings default_conf = {
.psm_entry_retries = 8,
.psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
- .dynamic_ps_timeout = 100,
+ .dynamic_ps_timeout = 200,
.forced_ps = false,
.keep_alive_interval = 55000,
.max_listen_interval = 20,
--
1.7.5.4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 3/7] wl12xx: reset link Tx queues when freeing it
2012-02-27 22:41 ` [PATCH 3/7] wl12xx: reset link Tx queues when freeing it Arik Nemtsov
@ 2012-02-28 9:51 ` Luciano Coelho
2012-02-28 10:09 ` Arik Nemtsov
2012-02-29 8:31 ` Kalle Valo
0 siblings, 2 replies; 12+ messages in thread
From: Luciano Coelho @ 2012-02-28 9:51 UTC (permalink / raw)
To: Arik Nemtsov; +Cc: linux-wireless
On Tue, 2012-02-28 at 00:41 +0200, Arik Nemtsov wrote:
> Before, the link was first freed (invalidating it in the map), and later
> on vif removal, all valid wlvif-related links were reset. Since these
> links were already invalid, we failed to reset them.
> The bug was made worse by op_stop, which set the tx_queue_count to 0
> arbitrarily. This resulted in a negative tx_queue_count in some scenarios.
>
> Fix this by resetting the Tx-queues of a link when freeing it. Add a
> WARN_ON and reset all link Tx-queues in op_stop, to avoid a negative
> tx_queue_count.
>
> Signed-off-by: Arik Nemtsov <arik@wizery.com>
> ---
[...]
> diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
> index 6446e4d..311b5a2 100644
> --- a/drivers/net/wireless/wl12xx/tx.c
> +++ b/drivers/net/wireless/wl12xx/tx.c
> @@ -527,6 +527,7 @@ static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
> if (skb) {
> int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
> spin_lock_irqsave(&wl->wl_lock, flags);
> + WARN_ON(wl->tx_queue_count[q] <= 0);
> wl->tx_queue_count[q]--;
> spin_unlock_irqrestore(&wl->wl_lock, flags);
> }
> @@ -602,6 +603,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
> skb = wl->dummy_packet;
> q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
> spin_lock_irqsave(&wl->wl_lock, flags);
> + WARN_ON(wl->tx_queue_count[q] <= 0);
> wl->tx_queue_count[q]--;
> spin_unlock_irqrestore(&wl->wl_lock, flags);
> }
[...]
> @@ -973,8 +974,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
> struct sk_buff *skb;
> struct ieee80211_tx_info *info;
>
> - for (i = 0; i < NUM_TX_QUEUES; i++)
> - wl->tx_queue_count[i] = 0;
> + /* only reset the queues if something bad happened */
> + if (WARN_ON(wl1271_tx_total_queue_count(wl) != 0)) {
Let's make all these WARN_ONs as WARN_ON_ONCE as it is recommended
nowadays. This will make Kalle Valo happier. :)
I can do a quick sed before I apply this, if you agree.
--
Cheers,
Luca.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/7] wl12xx: reset link Tx queues when freeing it
2012-02-28 9:51 ` Luciano Coelho
@ 2012-02-28 10:09 ` Arik Nemtsov
2012-02-29 8:31 ` Kalle Valo
1 sibling, 0 replies; 12+ messages in thread
From: Arik Nemtsov @ 2012-02-28 10:09 UTC (permalink / raw)
To: Luciano Coelho; +Cc: linux-wireless
On Tue, Feb 28, 2012 at 11:51, Luciano Coelho <coelho@ti.com> wrote:
> On Tue, 2012-02-28 at 00:41 +0200, Arik Nemtsov wrote:
>> Before, the link was first freed (invalidating it in the map), and later
>> on vif removal, all valid wlvif-related links were reset. Since these
>> links were already invalid, we failed to reset them.
>> The bug was made worse by op_stop, which set the tx_queue_count to 0
>> arbitrarily. This resulted in a negative tx_queue_count in some scenarios.
>>
>> Fix this by resetting the Tx-queues of a link when freeing it. Add a
>> WARN_ON and reset all link Tx-queues in op_stop, to avoid a negative
>> tx_queue_count.
>>
>> Signed-off-by: Arik Nemtsov <arik@wizery.com>
>> ---
>
> [...]
>
>> diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
>> index 6446e4d..311b5a2 100644
>> --- a/drivers/net/wireless/wl12xx/tx.c
>> +++ b/drivers/net/wireless/wl12xx/tx.c
>> @@ -527,6 +527,7 @@ static struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl,
>> if (skb) {
>> int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
>> spin_lock_irqsave(&wl->wl_lock, flags);
>> + WARN_ON(wl->tx_queue_count[q] <= 0);
>> wl->tx_queue_count[q]--;
>> spin_unlock_irqrestore(&wl->wl_lock, flags);
>> }
>> @@ -602,6 +603,7 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
>> skb = wl->dummy_packet;
>> q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
>> spin_lock_irqsave(&wl->wl_lock, flags);
>> + WARN_ON(wl->tx_queue_count[q] <= 0);
>> wl->tx_queue_count[q]--;
>> spin_unlock_irqrestore(&wl->wl_lock, flags);
>> }
>
> [...]
>
>> @@ -973,8 +974,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
>> struct sk_buff *skb;
>> struct ieee80211_tx_info *info;
>>
>> - for (i = 0; i < NUM_TX_QUEUES; i++)
>> - wl->tx_queue_count[i] = 0;
>> + /* only reset the queues if something bad happened */
>> + if (WARN_ON(wl1271_tx_total_queue_count(wl) != 0)) {
>
> Let's make all these WARN_ONs as WARN_ON_ONCE as it is recommended
> nowadays. This will make Kalle Valo happier. :)
>
> I can do a quick sed before I apply this, if you agree.
Sure thing.
Arik
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
` (5 preceding siblings ...)
2012-02-27 22:41 ` [PATCH 7/7] wl12xx: increase dynamic PS timeout to 200ms Arik Nemtsov
@ 2012-02-28 12:05 ` Luciano Coelho
6 siblings, 0 replies; 12+ messages in thread
From: Luciano Coelho @ 2012-02-28 12:05 UTC (permalink / raw)
To: Arik Nemtsov; +Cc: linux-wireless
On Tue, 2012-02-28 at 00:41 +0200, Arik Nemtsov wrote:
> With PSM handled in FW, the checks in wl1271_elp_work() are always true.
> Thus during active traffic we constantly enter and exit ELP (many times
> per second). As each ELP exit takes ~10ms, this can have an adverse
> effect on throughput and interactivity.
> Set the ELP timeout to the dyn-ps timeout. This period is longer and
> avoids the above problem. It also makes sense to stay out of ELP while
> we are awake on the network, to minimize delays in Tx/Rx. The same thing
> was done by the mac80211 dynamic-ps mechanism before the FW DPS changes.
>
> Signed-off-by: Arik Nemtsov <arik@wizery.com>
> ---
Applied this whole series with the change from WARN_ON to WARN_ON_ONCE
on patch 3/7 and pushed.
Thanks, Arik!
--
Cheers,
Luca.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/7] wl12xx: reset link Tx queues when freeing it
2012-02-28 9:51 ` Luciano Coelho
2012-02-28 10:09 ` Arik Nemtsov
@ 2012-02-29 8:31 ` Kalle Valo
2012-02-29 8:39 ` Luciano Coelho
1 sibling, 1 reply; 12+ messages in thread
From: Kalle Valo @ 2012-02-29 8:31 UTC (permalink / raw)
To: Luciano Coelho; +Cc: Arik Nemtsov, linux-wireless
Luciano Coelho <coelho@ti.com> writes:
>> @@ -973,8 +974,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
>> struct sk_buff *skb;
>> struct ieee80211_tx_info *info;
>>
>> - for (i = 0; i < NUM_TX_QUEUES; i++)
>> - wl->tx_queue_count[i] = 0;
>> + /* only reset the queues if something bad happened */
>> + if (WARN_ON(wl1271_tx_total_queue_count(wl) != 0)) {
>
> Let's make all these WARN_ONs as WARN_ON_ONCE as it is recommended
> nowadays. This will make Kalle Valo happier. :)
Hehe. Actually the dislike against WARN_ON() was started by John, I
again started the war to killing BUG_ON() :)
But nevertheless, this changes makes also me happy. I have seen cases
where the whole system reboots because of WARN_ON() spam, so
WARN_ON_ONCE() is much better in in cases where's a possibility that it
will get printed a lot. Of course printk_ratelimit() is another option,
but for some reason it isn't that popular.
--
Kalle Valo
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 3/7] wl12xx: reset link Tx queues when freeing it
2012-02-29 8:31 ` Kalle Valo
@ 2012-02-29 8:39 ` Luciano Coelho
0 siblings, 0 replies; 12+ messages in thread
From: Luciano Coelho @ 2012-02-29 8:39 UTC (permalink / raw)
To: Kalle Valo; +Cc: Arik Nemtsov, linux-wireless
On Wed, 2012-02-29 at 10:31 +0200, Kalle Valo wrote:
> Luciano Coelho <coelho@ti.com> writes:
>
> >> @@ -973,8 +974,14 @@ void wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
> >> struct sk_buff *skb;
> >> struct ieee80211_tx_info *info;
> >>
> >> - for (i = 0; i < NUM_TX_QUEUES; i++)
> >> - wl->tx_queue_count[i] = 0;
> >> + /* only reset the queues if something bad happened */
> >> + if (WARN_ON(wl1271_tx_total_queue_count(wl) != 0)) {
> >
> > Let's make all these WARN_ONs as WARN_ON_ONCE as it is recommended
> > nowadays. This will make Kalle Valo happier. :)
>
> Hehe. Actually the dislike against WARN_ON() was started by John, I
> again started the war to killing BUG_ON() :)
Right, John's email was where I got the "recommended" from. ;)
> But nevertheless, this changes makes also me happy. I have seen cases
> where the whole system reboots because of WARN_ON() spam, so
> WARN_ON_ONCE() is much better in in cases where's a possibility that it
> will get printed a lot. Of course printk_ratelimit() is another option,
> but for some reason it isn't that popular.
Yeah, I totally agree. Especially when we have a loop, WARN_ON_ONCE
should be sufficient, in my opinion.
--
Cheers,
Luca.
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2012-02-29 8:39 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-27 22:41 [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Arik Nemtsov
2012-02-27 22:41 ` [PATCH 2/7] wl12xx: change bits in the link_map under spin lock Arik Nemtsov
2012-02-27 22:41 ` [PATCH 3/7] wl12xx: reset link Tx queues when freeing it Arik Nemtsov
2012-02-28 9:51 ` Luciano Coelho
2012-02-28 10:09 ` Arik Nemtsov
2012-02-29 8:31 ` Kalle Valo
2012-02-29 8:39 ` Luciano Coelho
2012-02-27 22:41 ` [PATCH 4/7] wl12xx: avoid starving the system hlid Arik Nemtsov
2012-02-27 22:41 ` [PATCH 5/7] wl12xx: flush all Tx queues on tx_flush timeout Arik Nemtsov
2012-02-27 22:41 ` [PATCH 6/7] wl12xx: flush Tx during suspend and 802.11h chan switch Arik Nemtsov
2012-02-27 22:41 ` [PATCH 7/7] wl12xx: increase dynamic PS timeout to 200ms Arik Nemtsov
2012-02-28 12:05 ` [PATCH 1/7] wl12xx: set the ELP entry delay to the FW dyn-ps timeout Luciano Coelho
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.