diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-07-06 09:18:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:02:30 -0400 |
commit | 2ffa5fede379091bf62a732462b829e4b51af054 (patch) | |
tree | 4d1811c57b70c557d2edf077a6ff0a3f5b2548fc /drivers/net/wireless/p54 | |
parent | 6d541a684d7eb72c71eaba82b09a360c96609134 (diff) |
p54: fix queue stall due to underrun
Larry Finger discovered a weird behavior under load.
In essence, the queue's length count under runs,
which in turn renders the associated ac queue unusable.
Reported-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54')
-rw-r--r-- | drivers/net/wireless/p54/txrx.c | 7 |
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 31fda17bec43..6426d2cae6de 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c | |||
@@ -199,7 +199,7 @@ static int p54_tx_qos_accounting_alloc(struct p54_common *priv, | |||
199 | queue = &priv->tx_stats[p54_queue]; | 199 | queue = &priv->tx_stats[p54_queue]; |
200 | 200 | ||
201 | spin_lock_irqsave(&priv->tx_stats_lock, flags); | 201 | spin_lock_irqsave(&priv->tx_stats_lock, flags); |
202 | if (unlikely(queue->len > queue->limit && IS_QOS_QUEUE(p54_queue))) { | 202 | if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) { |
203 | spin_unlock_irqrestore(&priv->tx_stats_lock, flags); | 203 | spin_unlock_irqrestore(&priv->tx_stats_lock, flags); |
204 | return -ENOSPC; | 204 | return -ENOSPC; |
205 | } | 205 | } |
@@ -222,8 +222,11 @@ static void p54_tx_qos_accounting_free(struct p54_common *priv, | |||
222 | if (skb && IS_DATA_FRAME(skb)) { | 222 | if (skb && IS_DATA_FRAME(skb)) { |
223 | struct p54_hdr *hdr = (void *) skb->data; | 223 | struct p54_hdr *hdr = (void *) skb->data; |
224 | struct p54_tx_data *data = (void *) hdr->data; | 224 | struct p54_tx_data *data = (void *) hdr->data; |
225 | unsigned long flags; | ||
225 | 226 | ||
227 | spin_lock_irqsave(&priv->tx_stats_lock, flags); | ||
226 | priv->tx_stats[data->hw_queue].len--; | 228 | priv->tx_stats[data->hw_queue].len--; |
229 | spin_unlock_irqrestore(&priv->tx_stats_lock, flags); | ||
227 | } | 230 | } |
228 | p54_wake_queues(priv); | 231 | p54_wake_queues(priv); |
229 | } | 232 | } |
@@ -462,7 +465,6 @@ static void p54_rx_eeprom_readback(struct p54_common *priv, | |||
462 | 465 | ||
463 | priv->eeprom = NULL; | 466 | priv->eeprom = NULL; |
464 | tmp = p54_find_and_unlink_skb(priv, hdr->req_id); | 467 | tmp = p54_find_and_unlink_skb(priv, hdr->req_id); |
465 | p54_tx_qos_accounting_free(priv, tmp); | ||
466 | dev_kfree_skb_any(tmp); | 468 | dev_kfree_skb_any(tmp); |
467 | complete(&priv->eeprom_comp); | 469 | complete(&priv->eeprom_comp); |
468 | } | 470 | } |
@@ -489,7 +491,6 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) | |||
489 | priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); | 491 | priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); |
490 | 492 | ||
491 | tmp = p54_find_and_unlink_skb(priv, hdr->req_id); | 493 | tmp = p54_find_and_unlink_skb(priv, hdr->req_id); |
492 | p54_tx_qos_accounting_free(priv, tmp); | ||
493 | dev_kfree_skb_any(tmp); | 494 | dev_kfree_skb_any(tmp); |
494 | } | 495 | } |
495 | 496 | ||