Skip to content

Commit

Permalink
b43: Add QOS support
Browse files Browse the repository at this point in the history
This adds QOS support to the b43 driver.
QOS can be disabled on driver level with a module parameter for debugging purposes.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Michael Buesch authored and linvjw committed Mar 7, 2008
1 parent e5f98f2 commit e6f5b93
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 91 deletions.
37 changes: 37 additions & 0 deletions drivers/net/wireless/b43/b43.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define B43_MMIO_RNG 0x65A
#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
#define B43_MMIO_POWERUP_DELAY 0x6A8

/* SPROM boardflags_lo values */
Expand Down Expand Up @@ -621,6 +623,35 @@ struct b43_key {
u8 algorithm;
};

/* SHM offsets to the QOS data structures for the 4 different queues. */
#define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \
(B43_NR_QOSPARAMS * sizeof(u16) * (queue)))
#define B43_QOS_BACKGROUND B43_QOS_PARAMS(0)
#define B43_QOS_BESTEFFORT B43_QOS_PARAMS(1)
#define B43_QOS_VIDEO B43_QOS_PARAMS(2)
#define B43_QOS_VOICE B43_QOS_PARAMS(3)

/* QOS parameter hardware data structure offsets. */
#define B43_NR_QOSPARAMS 22
enum {
B43_QOSPARAM_TXOP = 0,
B43_QOSPARAM_CWMIN,
B43_QOSPARAM_CWMAX,
B43_QOSPARAM_CWCUR,
B43_QOSPARAM_AIFS,
B43_QOSPARAM_BSLOTS,
B43_QOSPARAM_REGGAP,
B43_QOSPARAM_STATUS,
};

/* QOS parameters for a queue. */
struct b43_qos_params {
/* The QOS parameters */
struct ieee80211_tx_queue_params p;
/* Does this need to get uploaded to hardware? */
bool need_hw_update;
};

struct b43_wldev;

/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
Expand Down Expand Up @@ -673,6 +704,12 @@ struct b43_wl {
struct sk_buff *current_beacon;
bool beacon0_uploaded;
bool beacon1_uploaded;

/* The current QOS parameters for the 4 queues.
* This is protected by the irq_lock. */
struct b43_qos_params qos_params[4];
/* Workqueue for updating QOS parameters in hardware. */
struct work_struct qos_update_work;
};

/* In-memory representation of a cached microcode file. */
Expand Down
90 changes: 40 additions & 50 deletions drivers/net/wireless/b43/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,52 +291,6 @@ static inline int request_slot(struct b43_dmaring *ring)
return slot;
}

/* Mac80211-queue to b43-ring mapping */
static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
int queue_priority)
{
struct b43_dmaring *ring;

/*FIXME: For now we always run on TX-ring-1 */
return dev->dma.tx_ring1;

/* 0 = highest priority */
switch (queue_priority) {
default:
B43_WARN_ON(1);
/* 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;
}

return ring;
}

/* b43-ring to mac80211-queue mapping */
static inline int txring_to_priority(struct b43_dmaring *ring)
{
static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
unsigned int index;

/*FIXME: have only one queue, for now */
return 0;

index = ring->index;
if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
index = 0;
return idx_to_prio[index];
}

static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx)
{
static const u16 map64[] = {
Expand Down Expand Up @@ -1272,6 +1226,37 @@ static inline int should_inject_overflow(struct b43_dmaring *ring)
return 0;
}

/* 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)
{
struct b43_dmaring *ring;

if (b43_modparam_qos) {
/* 0 = highest priority */
switch (queue_prio) {
default:
B43_WARN_ON(1);
/* fallthrough */
case 0:
ring = dev->dma.tx_ring3; /* AC_VO */
break;
case 1:
ring = dev->dma.tx_ring2; /* AC_VI */
break;
case 2:
ring = dev->dma.tx_ring1; /* AC_BE */
break;
case 3:
ring = dev->dma.tx_ring0; /* AC_BK */
break;
}
} else
ring = dev->dma.tx_ring1;

return ring;
}

int b43_dma_tx(struct b43_wldev *dev,
struct sk_buff *skb, struct ieee80211_tx_control *ctl)
{
Expand All @@ -1294,7 +1279,7 @@ int b43_dma_tx(struct b43_wldev *dev,
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else {
/* Decide by priority where to put this frame. */
ring = priority_to_txring(dev, ctl->queue);
ring = select_ring_by_priority(dev, ctl->queue);
}

spin_lock_irqsave(&ring->lock, flags);
Expand All @@ -1309,6 +1294,11 @@ int b43_dma_tx(struct b43_wldev *dev,
* That would be a mac80211 bug. */
B43_WARN_ON(ring->stopped);

/* 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 = ctl->queue;

err = dma_tx_fragment(ring, skb, ctl);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
Expand All @@ -1325,7 +1315,7 @@ int b43_dma_tx(struct b43_wldev *dev,
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) {
/* This TX ring is full. */
ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
ieee80211_stop_queue(dev->wl->hw, ctl->queue);
ring->stopped = 1;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
Expand Down Expand Up @@ -1404,7 +1394,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
dev->stats.last_tx = jiffies;
if (ring->stopped) {
B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
ring->stopped = 0;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
Expand All @@ -1425,7 +1415,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,

for (i = 0; i < nr_queues; i++) {
data = &(stats->data[i]);
ring = priority_to_txring(dev, i);
ring = select_ring_by_priority(dev, i);

spin_lock_irqsave(&ring->lock, flags);
data->len = ring->used_slots / SLOTS_PER_PACKET;
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/b43/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ 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;
/* Lock, only used for TX. */
spinlock_t lock;
struct b43_wldev *dev;
Expand Down
Loading

0 comments on commit e6f5b93

Please sign in to comment.