Search Linux Wireless

[RFC PATCH] bcm43xx QoS support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c	2007-06-02 23:14:46.000000000 +0200
+++ bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.c	2007-06-16 00:38:59.000000000 +0200
@@ -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
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h	2007-06-02 22:54:41.000000000 +0200
+++ bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_dma.h	2007-06-16 00:43:40.000000000 +0200
@@ -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
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c	2007-06-14 16:05:09.000000000 +0200
+++ bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_main.c	2007-06-16 00:50:26.000000000 +0200
@@ -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
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c	2007-06-10 14:37:06.000000000 +0200
+++ bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.c	2007-06-16 13:14:30.000000000 +0200
@@ -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
===================================================================
--- bu3sch-wireless-dev.orig/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h	2007-06-01 01:14:02.000000000 +0200
+++ bu3sch-wireless-dev/drivers/net/wireless/mac80211/bcm43xx/bcm43xx_xmit.h	2007-06-16 01:09:03.000000000 +0200
@@ -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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux