From: "Tomas Winkler" <tomasw@gmail.com>
To: "Michael Buesch" <mb@bu3sch.de>
Cc: bcm43xx-dev@lists.berlios.de, "Jiri Benc" <jbenc@suse.cz>,
linux-wireless@vger.kernel.org,
"Johannes Berg" <johannes@sipsolutions.net>,
"Joseph Jezak" <josejx@gentoo.org>
Subject: Re: [RFC PATCH] bcm43xx QoS support
Date: Sun, 17 Jun 2007 00:38:07 +0300 [thread overview]
Message-ID: <1ba2fa240706161438lfd629e4j7317bb62340c82a3@mail.gmail.com> (raw)
In-Reply-To: <200706161328.53726.mb@bu3sch.de>
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.
On 6/16/07, Michael Buesch <mb@bu3sch.de> wrote:
> 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@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
next prev parent reply other threads:[~2007-06-16 21:38 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-06-16 11:28 [RFC PATCH] bcm43xx QoS support Michael Buesch
2007-06-16 21:38 ` Tomas Winkler [this message]
2007-06-16 22:17 ` Johannes Berg
2007-06-16 23:30 ` Tomas Winkler
2007-06-17 9:10 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1ba2fa240706161438lfd629e4j7317bb62340c82a3@mail.gmail.com \
--to=tomasw@gmail.com \
--cc=bcm43xx-dev@lists.berlios.de \
--cc=jbenc@suse.cz \
--cc=johannes@sipsolutions.net \
--cc=josejx@gentoo.org \
--cc=linux-wireless@vger.kernel.org \
--cc=mb@bu3sch.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).