diff options
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 55 |
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 | ||
1595 | static void dma_rx(struct b43_dmaring *ring, int *slot) | 1606 | static 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 | ||
3423 | static void b43_qos_params_upload(struct b43_wldev *dev, | 3439 | static 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); |