aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfrancesco.gringoli@ing.unibs.it <francesco.gringoli@ing.unibs.it>2011-12-16 12:34:56 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-19 14:40:22 -0500
commitbad6919469662b7c92bc6353642aaaa777b36bac (patch)
tree35c1429e8216cc5ae4ef2f505a838d523045037f
parent1d8d3dec5fbba15864f25c734a7fda5703234091 (diff)
b43: avoid packet losses in the dma worker code.
Following Rafal request, we verified that on "modern" CPUs using one or more workers is equivalent. Here is patch V3 that addresses the packet loss bug in the dma engine using only one worker. ------- This patch addresses a bug in the dma worker code that keeps draining packets even when the hardware queues are full. In such cases packets can not be passed down to the device and are erroneusly dropped by the code. This problem was already discussed here http://www.mail-archive.com/b43-dev@lists.infradead.org/msg01413.html and acknowledged by Michael. Number of hardware queues is now defined in b43.h (B43_QOS_QUEUE_NUM). Acknowledgements to Riccardo Paolillo <riccardo.paolillo@gmail.com> and Michele Orru <michele.orru@hotmail.it> Signed-off-by: Francesco Gringoli <francesco.gringoli@ing.unibs.it> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/b43/b43.h9
-rw-r--r--drivers/net/wireless/b43/dma.c15
-rw-r--r--drivers/net/wireless/b43/main.c55
3 files changed, 60 insertions, 19 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 37110dfd2c96..f19605e8eb4c 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -667,6 +667,7 @@ struct b43_key {
667}; 667};
668 668
669/* SHM offsets to the QOS data structures for the 4 different queues. */ 669/* SHM offsets to the QOS data structures for the 4 different queues. */
670#define B43_QOS_QUEUE_NUM 4
670#define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \ 671#define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \
671 (B43_NR_QOSPARAMS * sizeof(u16) * (queue))) 672 (B43_NR_QOSPARAMS * sizeof(u16) * (queue)))
672#define B43_QOS_BACKGROUND B43_QOS_PARAMS(0) 673#define B43_QOS_BACKGROUND B43_QOS_PARAMS(0)
@@ -904,7 +905,7 @@ struct b43_wl {
904 struct work_struct beacon_update_trigger; 905 struct work_struct beacon_update_trigger;
905 906
906 /* The current QOS parameters for the 4 queues. */ 907 /* The current QOS parameters for the 4 queues. */
907 struct b43_qos_params qos_params[4]; 908 struct b43_qos_params qos_params[B43_QOS_QUEUE_NUM];
908 909
909 /* Work for adjustment of the transmission power. 910 /* Work for adjustment of the transmission power.
910 * This is scheduled when we determine that the actual TX output 911 * This is scheduled when we determine that the actual TX output
@@ -913,8 +914,12 @@ struct b43_wl {
913 914
914 /* Packet transmit work */ 915 /* Packet transmit work */
915 struct work_struct tx_work; 916 struct work_struct tx_work;
917
916 /* Queue of packets to be transmitted. */ 918 /* Queue of packets to be transmitted. */
917 struct sk_buff_head tx_queue; 919 struct sk_buff_head tx_queue[B43_QOS_QUEUE_NUM];
920
921 /* Flag that implement the queues stopping. */
922 bool tx_queue_stopped[B43_QOS_QUEUE_NUM];
918 923
919 /* The device LEDs. */ 924 /* The device LEDs. */
920 struct b43_leds leds; 925 struct b43_leds leds;
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 5e45604f0f5d..56d37dc967aa 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1465,7 +1465,9 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
1465 if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || 1465 if ((free_slots(ring) < TX_SLOTS_PER_FRAME) ||
1466 should_inject_overflow(ring)) { 1466 should_inject_overflow(ring)) {
1467 /* This TX ring is full. */ 1467 /* This TX ring is full. */
1468 ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); 1468 unsigned int skb_mapping = skb_get_queue_mapping(skb);
1469 ieee80211_stop_queue(dev->wl->hw, skb_mapping);
1470 dev->wl->tx_queue_stopped[skb_mapping] = 1;
1469 ring->stopped = 1; 1471 ring->stopped = 1;
1470 if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { 1472 if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
1471 b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); 1473 b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
@@ -1584,12 +1586,21 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
1584 } 1586 }
1585 if (ring->stopped) { 1587 if (ring->stopped) {
1586 B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); 1588 B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
1587 ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
1588 ring->stopped = 0; 1589 ring->stopped = 0;
1590 }
1591
1592 if (dev->wl->tx_queue_stopped[ring->queue_prio]) {
1593 dev->wl->tx_queue_stopped[ring->queue_prio] = 0;
1594 } else {
1595 /* If the driver queue is running wake the corresponding
1596 * mac80211 queue. */
1597 ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
1589 if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { 1598 if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
1590 b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); 1599 b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
1591 } 1600 }
1592 } 1601 }
1602 /* Add work to the queue. */
1603 ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work);
1593} 1604}
1594 1605
1595static void dma_rx(struct b43_dmaring *ring, int *slot) 1606static void dma_rx(struct b43_dmaring *ring, int *slot)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 5634d9a9965b..989f654de006 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3378,6 +3378,7 @@ static void b43_tx_work(struct work_struct *work)
3378 struct b43_wl *wl = container_of(work, struct b43_wl, tx_work); 3378 struct b43_wl *wl = container_of(work, struct b43_wl, tx_work);
3379 struct b43_wldev *dev; 3379 struct b43_wldev *dev;
3380 struct sk_buff *skb; 3380 struct sk_buff *skb;
3381 int queue_num;
3381 int err = 0; 3382 int err = 0;
3382 3383
3383 mutex_lock(&wl->mutex); 3384 mutex_lock(&wl->mutex);
@@ -3387,15 +3388,26 @@ static void b43_tx_work(struct work_struct *work)
3387 return; 3388 return;
3388 } 3389 }
3389 3390
3390 while (skb_queue_len(&wl->tx_queue)) { 3391 for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
3391 skb = skb_dequeue(&wl->tx_queue); 3392 while (skb_queue_len(&wl->tx_queue[queue_num])) {
3393 skb = skb_dequeue(&wl->tx_queue[queue_num]);
3394 if (b43_using_pio_transfers(dev))
3395 err = b43_pio_tx(dev, skb);
3396 else
3397 err = b43_dma_tx(dev, skb);
3398 if (err == -ENOSPC) {
3399 wl->tx_queue_stopped[queue_num] = 1;
3400 ieee80211_stop_queue(wl->hw, queue_num);
3401 skb_queue_head(&wl->tx_queue[queue_num], skb);
3402 break;
3403 }
3404 if (unlikely(err))
3405 dev_kfree_skb(skb); /* Drop it */
3406 err = 0;
3407 }
3392 3408
3393 if (b43_using_pio_transfers(dev)) 3409 if (!err)
3394 err = b43_pio_tx(dev, skb); 3410 wl->tx_queue_stopped[queue_num] = 0;
3395 else
3396 err = b43_dma_tx(dev, skb);
3397 if (unlikely(err))
3398 dev_kfree_skb(skb); /* Drop it */
3399 } 3411 }
3400 3412
3401#if B43_DEBUG 3413#if B43_DEBUG
@@ -3416,8 +3428,12 @@ static void b43_op_tx(struct ieee80211_hw *hw,
3416 } 3428 }
3417 B43_WARN_ON(skb_shinfo(skb)->nr_frags); 3429 B43_WARN_ON(skb_shinfo(skb)->nr_frags);
3418 3430
3419 skb_queue_tail(&wl->tx_queue, skb); 3431 skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb);
3420 ieee80211_queue_work(wl->hw, &wl->tx_work); 3432 if (!wl->tx_queue_stopped[skb->queue_mapping]) {
3433 ieee80211_queue_work(wl->hw, &wl->tx_work);
3434 } else {
3435 ieee80211_stop_queue(wl->hw, skb->queue_mapping);
3436 }
3421} 3437}
3422 3438
3423static void b43_qos_params_upload(struct b43_wldev *dev, 3439static void b43_qos_params_upload(struct b43_wldev *dev,
@@ -4147,6 +4163,7 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
4147 struct b43_wl *wl; 4163 struct b43_wl *wl;
4148 struct b43_wldev *orig_dev; 4164 struct b43_wldev *orig_dev;
4149 u32 mask; 4165 u32 mask;
4166 int queue_num;
4150 4167
4151 if (!dev) 4168 if (!dev)
4152 return NULL; 4169 return NULL;
@@ -4199,9 +4216,11 @@ redo:
4199 mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); 4216 mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
4200 B43_WARN_ON(mask != 0xFFFFFFFF && mask); 4217 B43_WARN_ON(mask != 0xFFFFFFFF && mask);
4201 4218
4202 /* Drain the TX queue */ 4219 /* Drain all TX queues. */
4203 while (skb_queue_len(&wl->tx_queue)) 4220 for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
4204 dev_kfree_skb(skb_dequeue(&wl->tx_queue)); 4221 while (skb_queue_len(&wl->tx_queue[queue_num]))
4222 dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num]));
4223 }
4205 4224
4206 b43_mac_suspend(dev); 4225 b43_mac_suspend(dev);
4207 b43_leds_exit(dev); 4226 b43_leds_exit(dev);
@@ -5245,6 +5264,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
5245 struct ieee80211_hw *hw; 5264 struct ieee80211_hw *hw;
5246 struct b43_wl *wl; 5265 struct b43_wl *wl;
5247 char chip_name[6]; 5266 char chip_name[6];
5267 int queue_num;
5248 5268
5249 hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops); 5269 hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
5250 if (!hw) { 5270 if (!hw) {
@@ -5264,7 +5284,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
5264 BIT(NL80211_IFTYPE_WDS) | 5284 BIT(NL80211_IFTYPE_WDS) |
5265 BIT(NL80211_IFTYPE_ADHOC); 5285 BIT(NL80211_IFTYPE_ADHOC);
5266 5286
5267 hw->queues = modparam_qos ? 4 : 1; 5287 hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1;
5268 wl->mac80211_initially_registered_queues = hw->queues; 5288 wl->mac80211_initially_registered_queues = hw->queues;
5269 hw->max_rates = 2; 5289 hw->max_rates = 2;
5270 SET_IEEE80211_DEV(hw, dev->dev); 5290 SET_IEEE80211_DEV(hw, dev->dev);
@@ -5281,7 +5301,12 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
5281 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); 5301 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
5282 INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); 5302 INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
5283 INIT_WORK(&wl->tx_work, b43_tx_work); 5303 INIT_WORK(&wl->tx_work, b43_tx_work);
5284 skb_queue_head_init(&wl->tx_queue); 5304
5305 /* Initialize queues and flags. */
5306 for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
5307 skb_queue_head_init(&wl->tx_queue[queue_num]);
5308 wl->tx_queue_stopped[queue_num] = 0;
5309 }
5285 5310
5286 snprintf(chip_name, ARRAY_SIZE(chip_name), 5311 snprintf(chip_name, ARRAY_SIZE(chip_name),
5287 (dev->chip_id > 0x9999) ? "%d" : "%04X", dev->chip_id); 5312 (dev->chip_id > 0x9999) ? "%d" : "%04X", dev->chip_id);