b43: fix queue warning From: Johannes Berg Due to my mac80211 HW queue mapping changes, the way b43 played with the # of queues broke. By using the new HW queue mapping abilities of mac80211, b43 can stop playing with the # of queues and even map them in the order it needs: 0,1,2,3 -> 3,2,1,0 if QoS is enabled or 0,1,2,3 -> 1 if QoS is disabled. Signed-off-by: Johannes Berg --- drivers/net/wireless/b43/b43.h | 13 ++----- drivers/net/wireless/b43/dma.c | 67 +++++++++++++--------------------------- drivers/net/wireless/b43/dma.h | 3 - drivers/net/wireless/b43/main.c | 51 +++++++++++++++++------------- drivers/net/wireless/b43/pio.c | 62 +++++++++++++------------------------ drivers/net/wireless/b43/pio.h | 2 - 6 files changed, 78 insertions(+), 120 deletions(-) --- a/drivers/net/wireless/b43/b43.h 2012-06-08 20:03:44.000000000 +0200 +++ b/drivers/net/wireless/b43/b43.h 2012-06-08 20:06:47.000000000 +0200 @@ -686,6 +686,8 @@ struct b43_key { #define B43_QOS_VIDEO B43_QOS_PARAMS(2) #define B43_QOS_VOICE B43_QOS_PARAMS(3) +#define B43_HW_QUEUE_NUM 5 + /* QOS parameter hardware data structure offsets. */ #define B43_NR_QOSPARAMS 16 enum { @@ -870,13 +872,6 @@ struct b43_wl { * handler, only. This basically is just the IRQ mask register. */ spinlock_t hardirq_lock; - /* The number of queues that were registered with the mac80211 subsystem - * initially. This is a backup copy of hw->queues in case hw->queues has - * to be dynamically lowered at runtime (Firmware does not support QoS). - * hw->queues has to be restored to the original value before unregistering - * from the mac80211 subsystem. */ - u16 mac80211_initially_registered_queues; - /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. */ @@ -927,10 +922,10 @@ struct b43_wl { struct work_struct tx_work; /* Queue of packets to be transmitted. */ - struct sk_buff_head tx_queue[B43_QOS_QUEUE_NUM]; + struct sk_buff_head tx_queue[B43_HW_QUEUE_NUM]; /* Flag that implement the queues stopping. */ - bool tx_queue_stopped[B43_QOS_QUEUE_NUM]; + bool tx_queue_stopped[B43_HW_QUEUE_NUM]; /* firmware loading work */ struct work_struct firmware_load; --- a/drivers/net/wireless/b43/dma.c 2012-06-08 20:03:44.000000000 +0200 +++ b/drivers/net/wireless/b43/dma.c 2012-06-08 20:06:47.000000000 +0200 @@ -1374,34 +1374,23 @@ static inline int should_inject_overflow } /* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ -static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev, - u8 queue_prio) +static struct b43_dmaring *select_ring_by_number(struct b43_wldev *dev, u8 q) { - struct b43_dmaring *ring; - - if (dev->qos_enabled) { - /* 0 = highest priority */ - switch (queue_prio) { - default: - B43_WARN_ON(1); - /* fallthrough */ - case 0: - ring = dev->dma.tx_ring_AC_VO; - break; - case 1: - ring = dev->dma.tx_ring_AC_VI; - break; - case 2: - ring = dev->dma.tx_ring_AC_BE; - break; - case 3: - ring = dev->dma.tx_ring_AC_BK; - break; - } - } else - ring = dev->dma.tx_ring_AC_BE; - - return ring; + switch (q) { + case 0: + return dev->dma.tx_ring_AC_BK; + default: + WARN_ON_ONCE(1); + /* fall through */ + case 1: + return dev->dma.tx_ring_AC_BE; + case 2: + return dev->dma.tx_ring_AC_VI; + case 3: + return dev->dma.tx_ring_AC_VO; + case 4: + return dev->dma.tx_ring_mcast; + } } int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) @@ -1413,16 +1402,12 @@ int b43_dma_tx(struct b43_wldev *dev, st hdr = (struct ieee80211_hdr *)skb->data; if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - /* The multicast ring will be sent after the DTIM */ - ring = dev->dma.tx_ring_mcast; /* Set the more-data bit. Ucode will clear it on * the last frame for us. */ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } else { - /* Decide by priority where to put this frame. */ - ring = select_ring_by_priority( - dev, skb_get_queue_mapping(skb)); } + ring = select_ring_by_number(dev, info->hw_queue); + WARN_ON_ONCE(ring->index != info->hw_queue); B43_WARN_ON(!ring->tx); @@ -1445,11 +1430,6 @@ int b43_dma_tx(struct b43_wldev *dev, st goto out; } - /* Assign the queue number to the ring (if not already done before) - * so TX status handling can use it. The queue to ring mapping is - * static, so we don't need to store it per frame. */ - ring->queue_prio = skb_get_queue_mapping(skb); - err = dma_tx_fragment(ring, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key @@ -1465,9 +1445,8 @@ int b43_dma_tx(struct b43_wldev *dev, st if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || should_inject_overflow(ring)) { /* This TX ring is full. */ - unsigned int skb_mapping = skb_get_queue_mapping(skb); - ieee80211_stop_queue(dev->wl->hw, skb_mapping); - dev->wl->tx_queue_stopped[skb_mapping] = 1; + ieee80211_stop_queue(dev->wl->hw, ring->index); + dev->wl->tx_queue_stopped[ring->index] = 1; ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1589,12 +1568,12 @@ void b43_dma_handle_txstatus(struct b43_ ring->stopped = false; } - if (dev->wl->tx_queue_stopped[ring->queue_prio]) { - dev->wl->tx_queue_stopped[ring->queue_prio] = 0; + if (dev->wl->tx_queue_stopped[ring->index]) { + dev->wl->tx_queue_stopped[ring->index] = 0; } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ - ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); + ieee80211_wake_queue(dev->wl->hw, ring->index); if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } --- a/drivers/net/wireless/b43/dma.h 2012-06-08 20:03:44.000000000 +0200 +++ b/drivers/net/wireless/b43/dma.h 2012-06-08 20:06:47.000000000 +0200 @@ -256,9 +256,6 @@ struct b43_dmaring { enum b43_dmatype type; /* Boolean. Is this ring stopped at ieee80211 level? */ bool stopped; - /* The QOS priority assigned to this ring. Only used for TX rings. - * This is the mac80211 "queue" value. */ - u8 queue_prio; struct b43_wldev *dev; #ifdef CONFIG_B43_DEBUG /* Maximum number of used slots. */ --- a/drivers/net/wireless/b43/main.c 2012-06-08 20:03:44.000000000 +0200 +++ b/drivers/net/wireless/b43/main.c 2012-06-08 20:10:07.000000000 +0200 @@ -2538,8 +2538,6 @@ static int b43_upload_microcode(struct b dev->fw.hdr_format = B43_FW_HDR_351; dev->fw.opensource = (fwdate == 0xFFFF); - /* Default to use-all-queues. */ - dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; dev->qos_enabled = !!modparam_qos; /* Default to firmware/hardware crypto acceleration. */ dev->hwcrypto_enabled = true; @@ -2560,10 +2558,8 @@ static int b43_upload_microcode(struct b } if (!(fwcapa & B43_FWCAPA_QOS)) { b43info(dev->wl, "QoS not supported by firmware\n"); - /* Disable QoS. Tweak hw->queues to 1. It will be restored before - * ieee80211_unregister to make sure the networking core can - * properly free possible resources. */ - dev->wl->hw->queues = 1; + /* This is still a hack */ + dev->wl->hw->flags &= ~IEEE80211_HW_SUPPORTS_QOS; dev->qos_enabled = false; } } else { @@ -3379,7 +3375,7 @@ static void b43_tx_work(struct work_stru return; } - for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) { + for (queue_num = B43_HW_QUEUE_NUM - 1; queue_num >= 0; queue_num--) { while (skb_queue_len(&wl->tx_queue[queue_num])) { skb = skb_dequeue(&wl->tx_queue[queue_num]); if (b43_using_pio_transfers(dev)) @@ -3411,6 +3407,7 @@ static void b43_op_tx(struct ieee80211_h struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (unlikely(skb->len < 2 + 2 + 6)) { /* Too short, this can't be a valid frame. */ @@ -3419,11 +3416,11 @@ static void b43_op_tx(struct ieee80211_h } B43_WARN_ON(skb_shinfo(skb)->nr_frags); - skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); - if (!wl->tx_queue_stopped[skb->queue_mapping]) { + skb_queue_tail(&wl->tx_queue[info->hw_queue], skb); + if (!wl->tx_queue_stopped[info->hw_queue]) { ieee80211_queue_work(wl->hw, &wl->tx_work); } else { - ieee80211_stop_queue(wl->hw, skb->queue_mapping); + ieee80211_stop_queue(wl->hw, info->hw_queue); } } @@ -4223,7 +4220,7 @@ redo: B43_WARN_ON(mask != 0xFFFFFFFF && mask); /* Drain all TX queues. */ - for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) { + for (queue_num = 0; queue_num < B43_HW_QUEUE_NUM; queue_num++) { while (skb_queue_len(&wl->tx_queue[queue_num])) dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num])); } @@ -4737,6 +4734,7 @@ static int b43_op_add_interface(struct i struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; int err = -EOPNOTSUPP; + int i; /* TODO: allow WDS/AP devices to coexist */ @@ -4764,6 +4762,16 @@ static int b43_op_add_interface(struct i b43_set_synth_pu_delay(dev, 0); b43_upload_card_macaddress(dev); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (dev->qos_enabled) + vif->hw_queue[i] = 3 - i; + else /* use BE queue for all */ + vif->hw_queue[i] = 1; + } + + /* 0-3 for ACs, 4 for CAB */ + vif->cab_queue = 4; + err = 0; out_mutex_unlock: mutex_unlock(&wl->mutex); @@ -5286,6 +5294,7 @@ static struct b43_wl *b43_wireless_init( /* fill hw info */ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_QUEUE_CONTROL | IEEE80211_HW_SIGNAL_DBM; hw->wiphy->interface_modes = @@ -5297,8 +5306,14 @@ static struct b43_wl *b43_wireless_init( hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1; - wl->mac80211_initially_registered_queues = hw->queues; + /* + * Register 4 AC queues & the mcast queue, + * we may not use them later if QoS isn't + * supported by the firmware. + */ + hw->queues = 5; + /* Use queue 1 (BE) since if QoS is disabled that's the only one */ + hw->offchannel_tx_hw_queue = 1; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) @@ -5316,7 +5331,7 @@ static struct b43_wl *b43_wireless_init( INIT_WORK(&wl->tx_work, b43_tx_work); /* Initialize queues and flags. */ - for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) { + for (queue_num = 0; queue_num < B43_HW_QUEUE_NUM; queue_num++) { skb_queue_head_init(&wl->tx_queue[queue_num]); wl->tx_queue_stopped[queue_num] = 0; } @@ -5370,10 +5385,6 @@ static void b43_bcma_remove(struct bcma_ * as the ieee80211 unreg will destroy the workqueue. */ cancel_work_sync(&wldev->restart_work); - /* Restore the queues count before unregistering, because firmware detect - * might have modified it. Restoring is important, so the networking - * stack can properly free resources. */ - wl->hw->queues = wl->mac80211_initially_registered_queues; b43_leds_stop(wldev); ieee80211_unregister_hw(wl->hw); @@ -5447,10 +5458,6 @@ static void b43_ssb_remove(struct ssb_de B43_WARN_ON(!wl); if (wl->current_dev == wldev) { - /* Restore the queues count before unregistering, because firmware detect - * might have modified it. Restoring is important, so the networking - * stack can properly free resources. */ - wl->hw->queues = wl->mac80211_initially_registered_queues; b43_leds_stop(wldev); ieee80211_unregister_hw(wl->hw); } --- a/drivers/net/wireless/b43/pio.c 2012-06-08 20:03:44.000000000 +0200 +++ b/drivers/net/wireless/b43/pio.c 2012-06-08 20:06:47.000000000 +0200 @@ -297,34 +297,24 @@ err_destroy_bk: } /* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */ -static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev, - u8 queue_prio) +static struct b43_pio_txqueue * +select_queue_by_number(struct b43_wldev *dev, u8 q) { - struct b43_pio_txqueue *q; - - if (dev->qos_enabled) { - /* 0 = highest priority */ - switch (queue_prio) { - default: - B43_WARN_ON(1); - /* fallthrough */ - case 0: - q = dev->pio.tx_queue_AC_VO; - break; - case 1: - q = dev->pio.tx_queue_AC_VI; - break; - case 2: - q = dev->pio.tx_queue_AC_BE; - break; - case 3: - q = dev->pio.tx_queue_AC_BK; - break; - } - } else - q = dev->pio.tx_queue_AC_BE; - - return q; + switch (q) { + case 0: + return dev->pio.tx_queue_AC_BK; + default: + WARN_ON_ONCE(1); + /* fall through */ + case 1: + return dev->pio.tx_queue_AC_BE; + case 2: + return dev->pio.tx_queue_AC_VI; + case 3: + return dev->pio.tx_queue_AC_VO; + case 4: + return dev->pio.tx_queue_mcast; + } } static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q, @@ -510,15 +500,12 @@ int b43_pio_tx(struct b43_wldev *dev, st hdr = (struct ieee80211_hdr *)skb->data; if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - /* The multicast queue will be sent after the DTIM. */ - q = dev->pio.tx_queue_mcast; /* Set the frame More-Data bit. Ucode will clear it * for us on the last frame. */ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } else { - /* Decide by priority where to put this frame. */ - q = select_queue_by_priority(dev, skb_get_queue_mapping(skb)); } + q = select_queue_by_number(dev, info->hw_queue); + WARN_ON_ONCE(q->index != info->hw_queue); hdrlen = b43_txhdr_size(dev); total_len = roundup(skb->len + hdrlen, 4); @@ -538,16 +525,11 @@ int b43_pio_tx(struct b43_wldev *dev, st if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + ieee80211_stop_queue(dev->wl->hw, q->index); q->stopped = true; goto out; } - /* Assign the queue number to the ring (if not already done before) - * so TX status handling can use it. The mac80211-queue to b43-queue - * mapping is static, so we don't need to store it per frame. */ - q->queue_prio = skb_get_queue_mapping(skb); - err = pio_tx_frame(q, skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key @@ -565,7 +547,7 @@ int b43_pio_tx(struct b43_wldev *dev, st if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + ieee80211_stop_queue(dev->wl->hw, q->index); q->stopped = true; } @@ -600,7 +582,7 @@ void b43_pio_handle_txstatus(struct b43_ list_add(&pack->list, &q->packets_list); if (q->stopped) { - ieee80211_wake_queue(dev->wl->hw, q->queue_prio); + ieee80211_wake_queue(dev->wl->hw, q->index); q->stopped = false; } } --- a/drivers/net/wireless/b43/pio.h 2012-06-08 20:03:44.000000000 +0200 +++ b/drivers/net/wireless/b43/pio.h 2012-06-08 20:06:47.000000000 +0200 @@ -83,8 +83,6 @@ struct b43_pio_txqueue { bool stopped; /* Our b43 queue index number */ u8 index; - /* The mac80211 QoS queue priority. */ - u8 queue_prio; /* Buffer for TX packet meta data. */ struct b43_pio_txpacket packets[B43_PIO_MAX_NR_TXPACKETS];