aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-07-06 09:18:13 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:02:30 -0400
commit2ffa5fede379091bf62a732462b829e4b51af054 (patch)
tree4d1811c57b70c557d2edf077a6ff0a3f5b2548fc /drivers/net/wireless/p54
parent6d541a684d7eb72c71eaba82b09a360c96609134 (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.c7
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