Skip to contentSkip to conversation

bcm43xx QoS support

RFC PATCH In review Michael Buesch 3 participants 5 messages Jun 16, 2007 – Jun 17, 2007 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 bcm43xx QoS support

This incomplete patch tries to implement QoS support in the bcm43xx driver.
It's incomplete, because we don't upload the QoS parameters to the hardware, yet.
http://bcm-v4.sipsolutions.net/802.11/QoS
We might need some stack support to implement this (I'm not entirely sure, as I didn't read the whole ieee 802.11e, yet). Does some stack support for QoS exist? We need to upload some TX-opportunity, Interframe-space and some other values to the firmware. Not sure where to get them from, yet (didn't completely read 802.11e, yet :) ).

The bcm43xx device has 6 DMA rings, but I think only 4 are usable for 802.11e QoS. The other two seem to be useful for APs, though.

This patch also implements per-DMAring-locking. So this (theoretically) enables the stack to simultaneously transmit on two (or more) rings. Though, I'm not sure the stack exploits this behaviour, yet.

drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c +87 -21
Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c
===================================================================
@@ -290,6 +290,50 @@ void return_slot(struct bcm43xx_dmaring 
 	ring->used_slots--;
 }
 
+/* Mac80211-queue to bcm43xx-ring mapping */
+static struct bcm43xx_dmaring * priority_to_txring(struct bcm43xx_wldev *dev,
+						   int queue_priority)
+{
+	struct bcm43xx_dmaring *ring;
+
+	/* 0 = highest priority */
+	switch (queue_priority) {
+	default:
+		assert(0);
+		/* fallthrough */
+	case 0:
+		ring = dev->dma.tx_ring3;
+		break;
+	case 1:
+		ring = dev->dma.tx_ring2;
+		break;
+	case 2:
+		ring = dev->dma.tx_ring1;
+		break;
+	case 3:
+		ring = dev->dma.tx_ring0;
+		break;
+	case 4:
+		ring = dev->dma.tx_ring4;
+		break;
+	case 5:
+		ring = dev->dma.tx_ring5;
+		break;
+	}
+
+	return ring;
+}
+
+/* Bcm43xx-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct bcm43xx_dmaring *ring)
+{
+	static const u8 idx_to_prio[] =
+		{ 3, 2, 1, 0, 4, 5, };
+
+	return idx_to_prio[ring->index];
+}
+
+
 u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
 {
 	static const u16 map64[] = {
@@ -816,6 +860,7 @@ struct bcm43xx_dmaring * bcm43xx_setup_d
 		} else
 			assert(0);
 	}
+	spin_lock_init(&ring->lock);
 #ifdef CONFIG_BCM43XX_MAC80211_DEBUG
 	ring->last_injected_overflow = jiffies;
 #endif
@@ -1171,37 +1216,39 @@ int bcm43xx_dma_tx(struct bcm43xx_wldev 
 		   struct sk_buff *skb,
 		   struct ieee80211_tx_control *ctl)
 {
-	struct bcm43xx_dmaring *ring = dev->dma.tx_ring1;
+	struct bcm43xx_dmaring *ring;
 	int err = 0;
+	unsigned long flags;
 
+	ring = priority_to_txring(dev, ctl->queue);
+	spin_lock_irqsave(&ring->lock, flags);
 	assert(ring->tx);
 	if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
-		/* This should never trigger, as we call
-		 * ieee80211_stop_queue() when it's full.
-		 */
 		printkl(KERN_ERR PFX "DMA queue overflow\n");
-		return NETDEV_TX_BUSY;
+		err = -ENOSPC;
+		goto out_unlock;
 	}
 	/* Check if the queue was stopped in mac80211,
-	 * but we got called nevertheless. */
+	 * but we got called nevertheless.
+	 * That would be a mac80211 bug. */
 	assert(!ring->stopped);
 
 	err = dma_tx_fragment(ring, skb, ctl);
 	if (unlikely(err)) {
 		printkl(KERN_ERR PFX "DMA tx mapping failure\n");
-		return NETDEV_TX_BUSY;
+		goto out_unlock;
 	}
-
 	ring->nr_tx_packets++;
 	if ((free_slots(ring) < SLOTS_PER_PACKET) ||
 	    should_inject_overflow(ring)) {
 		/* This TX ring is full. */
-		/* FIXME: we currently only have one queue, so hardcode queue 0 here. */
-		ieee80211_stop_queue(dev->wl->hw, 0);
+		ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
 		ring->stopped = 1;
 	}
+out_unlock:
+	spin_unlock_irqrestore(&ring->lock, flags);
 
-	return 0;
+	return err;
 }
 
 void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev,
@@ -1216,6 +1263,9 @@ void bcm43xx_dma_handle_txstatus(struct 
 	ring = parse_cookie(dev, status->cookie, &slot);
 	if (unlikely(!ring))
 		return;
+	assert(irqs_disabled());
+	spin_lock(&ring->lock);
+
 	assert(ring->tx);
 	ops = ring->ops;
 	while (1) {
@@ -1257,24 +1307,32 @@ void bcm43xx_dma_handle_txstatus(struct 
 	dev->stats.last_tx = jiffies;
 	if (ring->stopped) {
 		assert(free_slots(ring) >= SLOTS_PER_PACKET);
-		/* FIXME: we currently only have one queue, co hardcode queue 0 here. */
-		ieee80211_wake_queue(dev->wl->hw, 0);
+		ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
 		ring->stopped = 0;
 	}
+
+	spin_unlock(&ring->lock);
 }
 
 void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
 			      struct ieee80211_tx_queue_stats *stats)
 {
-	struct bcm43xx_dma *dma = &dev->dma;
+	const int nr_queues = dev->wl->hw->queues;
 	struct bcm43xx_dmaring *ring;
 	struct ieee80211_tx_queue_stats_data *data;
+	unsigned long flags;
+	int i;
 
-	ring = dma->tx_ring1;
-	data = &(stats->data[0]);
-	data->len = ring->used_slots / SLOTS_PER_PACKET;
-	data->limit = ring->nr_slots / SLOTS_PER_PACKET;
-	data->count = ring->nr_tx_packets;
+	for (i = 0; i < nr_queues; i++) {
+		data = &(stats->data[i]);
+		ring = priority_to_txring(dev, i);
+
+		spin_lock_irqsave(&ring->lock, flags);
+		data->len = ring->used_slots / SLOTS_PER_PACKET;
+		data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+		data->count = ring->nr_tx_packets;
+		spin_unlock_irqrestore(&ring->lock, flags);
+	}
 }
 
 static void dma_rx(struct bcm43xx_dmaring *ring,
@@ -1397,16 +1455,24 @@ void bcm43xx_dma_rx(struct bcm43xx_dmari
 	ring->current_slot = slot;
 }
 
-static inline void bcm43xx_dma_tx_suspend_ring(struct bcm43xx_dmaring *ring)
+static void bcm43xx_dma_tx_suspend_ring(struct bcm43xx_dmaring *ring)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
 	assert(ring->tx);
 	ring->ops->tx_suspend(ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
 }
 
-static inline void bcm43xx_dma_tx_resume_ring(struct bcm43xx_dmaring *ring)
+static void bcm43xx_dma_tx_resume_ring(struct bcm43xx_dmaring *ring)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
 	assert(ring->tx);
 	ring->ops->tx_resume(ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
 }
 
 void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev)
drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h +2 -0
Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h
===================================================================
@@ -252,6 +252,8 @@ struct bcm43xx_dmaring {
 	u8 dma64;
 	/* Boolean. Is this ring stopped at ieee80211 level? */
 	u8 stopped;
+	/* Lock, only used for TX. */
+	spinlock_t lock;
 	struct bcm43xx_wldev *dev;
 #ifdef CONFIG_BCM43XX_MAC80211_DEBUG
 	/* Maximum number of used slots. */
drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c +15 -11
Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c
===================================================================
@@ -2448,16 +2448,17 @@ static int bcm43xx_tx(struct ieee80211_h
 	int err = -ENODEV;
 	unsigned long flags;
 
+	/* DMA-TX is done without a global lock. */
 	if (unlikely(!dev))
 		goto out;
-	spin_lock_irqsave(&wl->irq_lock, flags);
-	if (likely(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED)) {
-		if (bcm43xx_using_pio(dev))
-			err = bcm43xx_pio_tx(dev, skb, ctl);
-		else
-			err = bcm43xx_dma_tx(dev, skb, ctl);
-	}
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED);
+	assert(dev->started);
+	if (bcm43xx_using_pio(dev)) {
+		spin_lock_irqsave(&wl->irq_lock, flags);
+		err = bcm43xx_pio_tx(dev, skb, ctl);
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
+	} else
+		err = bcm43xx_dma_tx(dev, skb, ctl);
 out:
 	if (unlikely(err))
 		return NETDEV_TX_BUSY;
@@ -3313,10 +3314,13 @@ static int bcm43xx_wireless_core_init(st
 	bcm43xx_write_mac_bssid_templates(dev);
 
 	do {
-		if (bcm43xx_using_pio(dev))
+		if (bcm43xx_using_pio(dev)) {
 			err = bcm43xx_pio_init(dev);
-		else
+		} else {
 			err = bcm43xx_dma_init(dev);
+			if (!err)
+				bcm43xx_qos_init(dev);
+		}
 	} while (err == -EAGAIN);
 	if (err)
 		goto err_chip_exit;
@@ -3798,7 +3802,7 @@ static int bcm43xx_wireless_init(struct 
 	hw->max_signal = 100;
 	hw->max_rssi = -110;
 	hw->max_noise = -110;
-	hw->queues = 1;
+	hw->queues = 4;
 	SET_IEEE80211_DEV(hw, dev->dev);
 	if (is_valid_ether_addr(sprom->r1.et1mac))
 		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c +25 -0
Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c
===================================================================
@@ -619,3 +619,28 @@ void bcm43xx_tx_resume(struct bcm43xx_wl
 	else
 		bcm43xx_dma_tx_resume(dev);
 }
+
+static void upload_qos_parms(struct bcm43xx_wldev *dev,
+			     const u16 *parms,
+			     u16 offset)
+{
+	int i;
+
+	for (i = 0; i < BCM43xx_NR_QOSPARMS; i++) {
+		bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED,
+				    offset + i, parms[i]);
+	}
+}
+
+/* Initialize the QoS parameters */
+void bcm43xx_qos_init(struct bcm43xx_wldev *dev)
+{
+	//TODO
+	bcm43xx_hf_write(dev, bcm43xx_hf_read(dev) | BCM43xx_HF_EDCF);
+	//FIXME kill magic
+	bcm43xx_write16(dev, 0x688,
+			bcm43xx_read16(dev, 0x688) | 0x4);
+
+
+	/*TODO: We might need some stack support here to get the values. */
+}
drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h +15 -0
Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h
===================================================================
@@ -215,6 +215,21 @@ void bcm43xx_handle_hwtxstatus(struct bc
 void bcm43xx_tx_suspend(struct bcm43xx_wldev *dev);
 void bcm43xx_tx_resume(struct bcm43xx_wldev *dev);
 
+
+#define BCM43xx_NR_QOSPARMS		21
+enum {
+	BCM43xx_QOSPARM_TXOP = 0,
+	BCM43xx_QOSPARM_CWMIN,
+	BCM43xx_QOSPARM_CWMAX,
+	BCM43xx_QOSPARM_CWCUR,
+	BCM43xx_QOSPARM_AIFS,
+	BCM43xx_QOSPARM_BSLOTS,
+	BCM43xx_QOSPARM_REGGAP,
+	BCM43xx_QOSPARM_STATUS,
+};
+void bcm43xx_qos_init(struct bcm43xx_wldev *dev);
+
+
 /* Helper functions for converting the key-table index from "firmware-format"
  * to "raw-format" and back. The firmware API changed for this at some revision.
  * We need to account for that here. */
Signature · 1 line
Greetings Michael.
#1 lore raw

iwlwifi supports QoS. It has queues 4 hw for WMM access categories 2 hw queus for HCCA.
There is also a discussion about supporting hardware queues in qdisc in netdev.

Quoted 349 lines · Michael Buesch

This incomplete patch tries to implement QoS support in the bcm43xx driver.
It's incomplete, because we don't upload the QoS parameters to the hardware, yet.
http://bcm-v4.sipsolutions.net/802.11/QoS
We might need some stack support to implement this (I'm not entirely sure, as I didn't read the whole ieee 802.11e, yet). Does some stack support for QoS exist? We need to upload some TX-opportunity, Interframe-space and some other values to the firmware. Not sure where to get them from, yet (didn't completely read 802.11e, yet :) ).

The bcm43xx device has 6 DMA rings, but I think only 4 are usable for 802.11e QoS. The other two seem to be useful for APs, though.

This patch also implements per-DMAring-locking. So this (theoretically) enables the stack to simultaneously transmit on two (or more) rings. Though, I'm not sure the stack exploits this behaviour, yet.

Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c
===================================================================

drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c 2007-06-16 00:38:59.000000000 +0200 renamed from drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c 2007-06-02 23:14:46.000000000 +0200 +87 -21
@@ -290,6 +290,50 @@ void return_slot(struct bcm43xx_dmaring
        ring->used_slots--;
 }
 
+/* Mac80211-queue to bcm43xx-ring mapping */
+static struct bcm43xx_dmaring * priority_to_txring(struct bcm43xx_wldev *dev,
+                                                  int queue_priority)
+{
+       struct bcm43xx_dmaring *ring;
+
+       /* 0 = highest priority */
+       switch (queue_priority) {
+       default:
+               assert(0);
+               /* fallthrough */
+       case 0:
+               ring = dev->dma.tx_ring3;
+               break;
+       case 1:
+               ring = dev->dma.tx_ring2;
+               break;
+       case 2:
+               ring = dev->dma.tx_ring1;
+               break;
+       case 3:
+               ring = dev->dma.tx_ring0;
+               break;
+       case 4:
+               ring = dev->dma.tx_ring4;
+               break;
+       case 5:
+               ring = dev->dma.tx_ring5;
+               break;
+       }
+
+       return ring;
+}
+
+/* Bcm43xx-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct bcm43xx_dmaring *ring)
+{
+       static const u8 idx_to_prio[] =
+               { 3, 2, 1, 0, 4, 5, };
+
+       return idx_to_prio[ring->index];
+}
+
+
 u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
 {
        static const u16 map64[] = {
@@ -816,6 +860,7 @@ struct bcm43xx_dmaring * bcm43xx_setup_d
                } else
                        assert(0);
        }
+       spin_lock_init(&ring->lock);
 #ifdef CONFIG_BCM43XX_MAC80211_DEBUG
        ring->last_injected_overflow = jiffies;
 #endif
@@ -1171,37 +1216,39 @@ int bcm43xx_dma_tx(struct bcm43xx_wldev
                   struct sk_buff *skb,
                   struct ieee80211_tx_control *ctl)
 {
-       struct bcm43xx_dmaring *ring = dev->dma.tx_ring1;
+       struct bcm43xx_dmaring *ring;
        int err = 0;
+       unsigned long flags;
 
+       ring = priority_to_txring(dev, ctl->queue);
+       spin_lock_irqsave(&ring->lock, flags);
        assert(ring->tx);
        if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
-               /* This should never trigger, as we call
-                * ieee80211_stop_queue() when it's full.
-                */
                printkl(KERN_ERR PFX "DMA queue overflow\n");
-               return NETDEV_TX_BUSY;
+               err = -ENOSPC;
+               goto out_unlock;
        }
        /* Check if the queue was stopped in mac80211,
-        * but we got called nevertheless. */
+        * but we got called nevertheless.
+        * That would be a mac80211 bug. */
        assert(!ring->stopped);
 
        err = dma_tx_fragment(ring, skb, ctl);
        if (unlikely(err)) {
                printkl(KERN_ERR PFX "DMA tx mapping failure\n");
-               return NETDEV_TX_BUSY;
+               goto out_unlock;
        }
-
        ring->nr_tx_packets++;
        if ((free_slots(ring) < SLOTS_PER_PACKET) ||
            should_inject_overflow(ring)) {
                /* This TX ring is full. */
-               /* FIXME: we currently only have one queue, so hardcode queue 0 here. */
-               ieee80211_stop_queue(dev->wl->hw, 0);
+               ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
                ring->stopped = 1;
        }
+out_unlock:
+       spin_unlock_irqrestore(&ring->lock, flags);
 
-       return 0;
+       return err;
 }
 
 void bcm43xx_dma_handle_txstatus(struct bcm43xx_wldev *dev,
@@ -1216,6 +1263,9 @@ void bcm43xx_dma_handle_txstatus(struct
        ring = parse_cookie(dev, status->cookie, &slot);
        if (unlikely(!ring))
                return;
+       assert(irqs_disabled());
+       spin_lock(&ring->lock);
+
        assert(ring->tx);
        ops = ring->ops;
        while (1) {
@@ -1257,24 +1307,32 @@ void bcm43xx_dma_handle_txstatus(struct
        dev->stats.last_tx = jiffies;
        if (ring->stopped) {
                assert(free_slots(ring) >= SLOTS_PER_PACKET);
-               /* FIXME: we currently only have one queue, co hardcode queue 0 here. */
-               ieee80211_wake_queue(dev->wl->hw, 0);
+               ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
                ring->stopped = 0;
        }
+
+       spin_unlock(&ring->lock);
 }
 
 void bcm43xx_dma_get_tx_stats(struct bcm43xx_wldev *dev,
                              struct ieee80211_tx_queue_stats *stats)
 {
-       struct bcm43xx_dma *dma = &dev->dma;
+       const int nr_queues = dev->wl->hw->queues;
        struct bcm43xx_dmaring *ring;
        struct ieee80211_tx_queue_stats_data *data;
+       unsigned long flags;
+       int i;
 
-       ring = dma->tx_ring1;
-       data = &(stats->data[0]);
-       data->len = ring->used_slots / SLOTS_PER_PACKET;
-       data->limit = ring->nr_slots / SLOTS_PER_PACKET;
-       data->count = ring->nr_tx_packets;
+       for (i = 0; i < nr_queues; i++) {
+               data = &(stats->data[i]);
+               ring = priority_to_txring(dev, i);
+
+               spin_lock_irqsave(&ring->lock, flags);
+               data->len = ring->used_slots / SLOTS_PER_PACKET;
+               data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+               data->count = ring->nr_tx_packets;
+               spin_unlock_irqrestore(&ring->lock, flags);
+       }
 }
 
 static void dma_rx(struct bcm43xx_dmaring *ring,
@@ -1397,16 +1455,24 @@ void bcm43xx_dma_rx(struct bcm43xx_dmari
        ring->current_slot = slot;
 }
 
-static inline void bcm43xx_dma_tx_suspend_ring(struct bcm43xx_dmaring *ring)
+static void bcm43xx_dma_tx_suspend_ring(struct bcm43xx_dmaring *ring)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&ring->lock, flags);
        assert(ring->tx);
        ring->ops->tx_suspend(ring);
+       spin_unlock_irqrestore(&ring->lock, flags);
 }
 
-static inline void bcm43xx_dma_tx_resume_ring(struct bcm43xx_dmaring *ring)
+static void bcm43xx_dma_tx_resume_ring(struct bcm43xx_dmaring *ring)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&ring->lock, flags);
        assert(ring->tx);
        ring->ops->tx_resume(ring);
+       spin_unlock_irqrestore(&ring->lock, flags);
 }
 
 void bcm43xx_dma_tx_suspend(struct bcm43xx_wldev *dev)

Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h
===================================================================

drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h 2007-06-16 00:43:40.000000000 +0200 renamed from drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h 2007-06-02 22:54:41.000000000 +0200 +2 -0
@@ -252,6 +252,8 @@ struct bcm43xx_dmaring {
        u8 dma64;
        /* Boolean. Is this ring stopped at ieee80211 level? */
        u8 stopped;
+       /* Lock, only used for TX. */
+       spinlock_t lock;
        struct bcm43xx_wldev *dev;
 #ifdef CONFIG_BCM43XX_MAC80211_DEBUG
        /* Maximum number of used slots. */

Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c
===================================================================

drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c 2007-06-16 00:50:26.000000000 +0200 renamed from drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c 2007-06-14 16:05:09.000000000 +0200 +15 -11
@@ -2448,16 +2448,17 @@ static int bcm43xx_tx(struct ieee80211_h
        int err = -ENODEV;
        unsigned long flags;
 
+       /* DMA-TX is done without a global lock. */
        if (unlikely(!dev))
                goto out;
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       if (likely(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED)) {
-               if (bcm43xx_using_pio(dev))
-                       err = bcm43xx_pio_tx(dev, skb, ctl);
-               else
-                       err = bcm43xx_dma_tx(dev, skb, ctl);
-       }
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
+       assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED);
+       assert(dev->started);
+       if (bcm43xx_using_pio(dev)) {
+               spin_lock_irqsave(&wl->irq_lock, flags);
+               err = bcm43xx_pio_tx(dev, skb, ctl);
+               spin_unlock_irqrestore(&wl->irq_lock, flags);
+       } else
+               err = bcm43xx_dma_tx(dev, skb, ctl);
 out:
        if (unlikely(err))
                return NETDEV_TX_BUSY;
@@ -3313,10 +3314,13 @@ static int bcm43xx_wireless_core_init(st
        bcm43xx_write_mac_bssid_templates(dev);
 
        do {
-               if (bcm43xx_using_pio(dev))
+               if (bcm43xx_using_pio(dev)) {
                        err = bcm43xx_pio_init(dev);
-               else
+               } else {
                        err = bcm43xx_dma_init(dev);
+                       if (!err)
+                               bcm43xx_qos_init(dev);
+               }
        } while (err == -EAGAIN);
        if (err)
                goto err_chip_exit;
@@ -3798,7 +3802,7 @@ static int bcm43xx_wireless_init(struct
        hw->max_signal = 100;
        hw->max_rssi = -110;
        hw->max_noise = -110;
-       hw->queues = 1;
+       hw->queues = 4;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->r1.et1mac))
                SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);

Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c
===================================================================

drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c 2007-06-16 13:14:30.000000000 +0200 renamed from drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c 2007-06-10 14:37:06.000000000 +0200 +25 -0
@@ -619,3 +619,28 @@ void bcm43xx_tx_resume(struct bcm43xx_wl
        else
                bcm43xx_dma_tx_resume(dev);
 }
+
+static void upload_qos_parms(struct bcm43xx_wldev *dev,
+                            const u16 *parms,
+                            u16 offset)
+{
+       int i;
+
+       for (i = 0; i < BCM43xx_NR_QOSPARMS; i++) {
+               bcm43xx_shm_write16(dev, BCM43xx_SHM_SHARED,
+                                   offset + i, parms[i]);
+       }
+}
+
+/* Initialize the QoS parameters */
+void bcm43xx_qos_init(struct bcm43xx_wldev *dev)
+{
+       //TODO
+       bcm43xx_hf_write(dev, bcm43xx_hf_read(dev) | BCM43xx_HF_EDCF);
+       //FIXME kill magic
+       bcm43xx_write16(dev, 0x688,
+                       bcm43xx_read16(dev, 0x688) | 0x4);
+
+
+       /*TODO: We might need some stack support here to get the values. */
+}

Index: bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h
===================================================================

drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h 2007-06-16 01:09:03.000000000 +0200 renamed from drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h 2007-06-01 01:14:02.000000000 +0200 +15 -1
@@ -215,6 +215,21 @@ void bcm43xx_handle_hwtxstatus(struct bc
 void bcm43xx_tx_suspend(struct bcm43xx_wldev *dev);
 void bcm43xx_tx_resume(struct bcm43xx_wldev *dev);
 
+
+#define BCM43xx_NR_QOSPARMS            21
+enum {
+       BCM43xx_QOSPARM_TXOP = 0,
+       BCM43xx_QOSPARM_CWMIN,
+       BCM43xx_QOSPARM_CWMAX,
+       BCM43xx_QOSPARM_CWCUR,
+       BCM43xx_QOSPARM_AIFS,
+       BCM43xx_QOSPARM_BSLOTS,
+       BCM43xx_QOSPARM_REGGAP,
+       BCM43xx_QOSPARM_STATUS,
+};
+void bcm43xx_qos_init(struct bcm43xx_wldev *dev);
+
+
 /* Helper functions for converting the key-table index from "firmware-format"
  * to "raw-format" and back. The firmware API changed for this at some revision.
  * We need to account for that here. */
 
--

Greetings Michael.
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#2 lore raw
Quoted 2 lines · Tomas Winkler

iwlwifi supports QoS. It has queues 4 hw for WMM access categories 2 hw queus for HCCA.

But it too can't ever create QoS-data frames or negotiate TXOPs afaict, unless it does more than we want in hardware.

Quoted 2 lines

There is also a discussion about supporting hardware queues in qdisc in netdev.

Which isn't really a concern to the driver since only mac80211 will need to be changed for that.

I suppose the question is: what are we missing in mac80211 now? It seems that we have no way of sending out QoS-data frames and that seems weird. Nor do we parse TXOP information etc. Possibly this is because we support WME and that's based on an early 802.11e draft?

johannes

#3 lore raw
Quoted 6 lines · Johannes Berg
Quoted 2 lines · Tomas Winkler

iwlwifi supports QoS. It has queues 4 hw for WMM access categories 2 hw queus for HCCA.

But it too can't ever create QoS-data frames or negotiate TXOPs afaict, unless it does more than we want in hardware.

True

Quoted 6 lines
Quoted 2 lines

There is also a discussion about supporting hardware queues in qdisc in netdev.

Which isn't really a concern to the driver since only mac80211 will need to be changed for that.

I'm not sure it's only mac80211 problem as driver is responsible for stopping and waking up the queues. Only driver knows whether hw queue is full or not.

Quoted 2 lines

I suppose the question is: what are we missing in mac80211 now? It seems that we have no way of sending out QoS-data frames and that seems weird.

QoS frame are send just fine by mac80211 (at least under iwlwifi), only the sequence numbers has to be overwritten in driver since the current handler doesn't advance them per TID.

Quoted 2 lines

Nor do we parse TXOP information etc. Possibly this is because we support WME and that's based on an early 802.11e draft?

I addition wme.c qdisc scheduler is rather naive one, it only statically assign priorities, it wouldn't pass WMM certification I guess.

Quoted 3 lines

johannes

maintainer
#4 lore raw
Quoted 9 lines · Tomas Winkler
Quoted 6 lines
Quoted 2 lines

There is also a discussion about supporting hardware queues in qdisc in netdev.

Which isn't really a concern to the driver since only mac80211 will need to be changed for that.

I'm not sure it's only mac80211 problem as driver is responsible for stopping and waking up the queues. Only driver knows whether hw queue is full or not.

Of course, but we already have that API in mac80211, hence well-written drivers already tell mac80211 about it so all we'd need to do is change mac80211 to tell the net layer :)

Quoted 6 lines
Quoted 2 lines

I suppose the question is: what are we missing in mac80211 now? It seems that we have no way of sending out QoS-data frames and that seems weird..

QoS frame are send just fine by mac80211 (at least under iwlwifi), only the sequence numbers has to be overwritten in driver since the current handler doesn't advance them per TID.

Oh, you're right, I missed that wme_qdiscop_enqueue does that.

Quoted 6 lines
Quoted 2 lines

Nor do we parse TXOP information etc. Possibly this is because we support WME and that's based on an early 802.11e draft?

I addition wme.c qdisc scheduler is rather naive one, it only statically assign priorities, it wouldn't pass WMM certification I guess.

I have no idea what WMM certification contains. All I've been trying to say is that this area really needs some work to be useful.

For the problem at hand, namely some QoS support in bcm43xx, we'll just have to hardcode some QoS parameters for now, I'd think, but I don't know what those would be.

johannes