add support for queueing frames spanning multiple descriptors

Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Felix Fietkau
2016-02-05 01:15:35 +01:00
parent a6c48ae56e
commit 2dfb9faa78
7 changed files with 111 additions and 47 deletions
+49 -14
View File
@@ -15,6 +15,8 @@
#include "mt76.h"
#include "dma.h"
#define DMA_DUMMY_TXWI ((void *) ~0)
static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
@@ -48,15 +50,29 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q)
static int
mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
u32 buf0, int len0, u32 buf1, int len1, u32 info)
struct mt76_queue_buf *buf, int nbufs, u32 info,
struct sk_buff *skb, void *txwi)
{
struct mt76_desc *desc;
u32 ctrl;
int idx;
int i, idx = -1;
ctrl = MT76_SET(MT_DMA_CTL_SD_LEN0, len0) |
MT76_SET(MT_DMA_CTL_SD_LEN1, len1) |
(len1 ? MT_DMA_CTL_LAST_SEC1 : MT_DMA_CTL_LAST_SEC0);
if (txwi)
q->entry[q->head].txwi = DMA_DUMMY_TXWI;
for (i = 0; i < nbufs; i += 2, buf += 2) {
u32 buf0 = buf[0].addr, buf1 = 0;
ctrl = MT76_SET(MT_DMA_CTL_SD_LEN0, buf[0].len);
if (i < nbufs - 1) {
buf1 = buf[1].addr;
ctrl |= MT76_SET(MT_DMA_CTL_SD_LEN1, buf[1].len);
}
if (i == nbufs - 1)
ctrl |= MT_DMA_CTL_LAST_SEC0;
else if (i == nbufs - 2)
ctrl |= MT_DMA_CTL_LAST_SEC1;
idx = q->head;
q->head = (q->head + 1) % q->ndesc;
@@ -69,6 +85,10 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
ACCESS_ONCE(desc->ctrl) = cpu_to_le32(ctrl);
q->queued++;
}
q->entry[idx].txwi = txwi;
q->entry[idx].skb = skb;
return idx;
}
@@ -78,15 +98,25 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
struct mt76_queue_entry *prev_e)
{
struct mt76_queue_entry *e = &q->entry[idx];
struct sk_buff *skb = e->skb;
dma_addr_t skb_addr;
__le32 __ctrl = ACCESS_ONCE(q->desc[idx].ctrl);
u32 ctrl = le32_to_cpu(__ctrl);
if (e->txwi)
skb_addr = ACCESS_ONCE(q->desc[idx].buf1);
else
skb_addr = ACCESS_ONCE(q->desc[idx].buf0);
if (!e->txwi || !e->skb) {
__le32 addr = ACCESS_ONCE(q->desc[idx].buf0);
u32 len = MT76_GET(MT_DMA_CTL_SD_LEN0, ctrl);
dma_unmap_single(dev->dev, le32_to_cpu(addr), len,
DMA_TO_DEVICE);
}
dma_unmap_single(dev->dev, skb_addr, skb->len, DMA_TO_DEVICE);
if (!(ctrl & MT_DMA_CTL_LAST_SEC0)) {
__le32 addr = ACCESS_ONCE(q->desc[idx].buf1);
u32 len = MT76_GET(MT_DMA_CTL_SD_LEN1, ctrl);
dma_unmap_single(dev->dev, le32_to_cpu(addr), len,
DMA_TO_DEVICE);
}
if (e->txwi == DMA_DUMMY_TXWI)
e->txwi = NULL;
*prev_e = *e;
memset(e, 0, sizeof(*e));
@@ -111,7 +141,9 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
if (entry.schedule)
q->swq_queued--;
if (entry.skb)
done(dev, q, &entry);
if (entry.txwi)
mt76_put_txwi(dev, entry.txwi);
@@ -196,6 +228,8 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi)
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
struct mt76_queue_buf qbuf;
buf = alloc(q->buf_size);
if (!buf)
break;
@@ -206,8 +240,9 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool napi)
break;
}
idx = mt76_dma_add_buf(dev, q, addr + offset, len - offset, 0, 0, 0);
q->entry[idx].buf = buf;
qbuf.addr = addr + offset;
qbuf.len = len - offset;
idx = mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL);
frames++;
}
+9 -3
View File
@@ -53,12 +53,17 @@ enum mt76_rxq_id {
__MT_RXQ_MAX
};
struct mt76_queue_buf {
dma_addr_t addr;
int len;
};
struct mt76_queue_entry {
struct sk_buff *skb;
union {
void *buf;
struct mt76_txwi_cache *txwi;
struct sk_buff *skb;
};
struct mt76_txwi_cache *txwi;
bool schedule;
};
@@ -96,7 +101,8 @@ struct mt76_queue_ops {
int (*alloc)(struct mt76_dev *dev, struct mt76_queue *q);
int (*add_buf)(struct mt76_dev *dev, struct mt76_queue *q,
u32 buf0, int len0, u32 buf1, int len1, u32 info);
struct mt76_queue_buf *buf, int nbufs, u32 info,
struct sk_buff *skb, void *txwi);
void *(*dequeue)(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
int *len, u32 *info, bool *more);
+4 -2
View File
@@ -20,6 +20,7 @@ mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb)
{
struct mt76_queue *q = &dev->mt76.q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
int idx;
@@ -27,9 +28,10 @@ mt7603_tx_queue_mcu(struct mt7603_dev *dev, enum mt76_txq_id qid,
if (dma_mapping_error(dev->mt76.dev, addr))
return -ENOMEM;
buf.addr = addr;
buf.len = skb->len;
spin_lock_bh(&q->lock);
idx = mt76_queue_add_buf(dev, q, addr, skb->len, 0, 0, 0);
q->entry[idx].skb = skb;
idx = mt76_queue_add_buf(dev, q, &buf, 1, 0, skb, NULL);
mt76_queue_kick(dev, q);
spin_unlock_bh(&q->lock);
+4 -2
View File
@@ -19,6 +19,7 @@ mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, int cmd, int seq)
{
struct mt76_queue *q = &dev->mt76.q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
u32 tx_info;
int idx;
@@ -33,9 +34,10 @@ mt76x2_tx_queue_mcu(struct mt76x2_dev *dev, enum mt76_txq_id qid,
if (dma_mapping_error(dev->mt76.dev, addr))
return -ENOMEM;
buf.addr = addr;
buf.len = skb->len;
spin_lock_bh(&q->lock);
idx = mt76_queue_add_buf(dev, q, addr, skb->len, 0, 0, tx_info);
q->entry[idx].skb = skb;
idx = mt76_queue_add_buf(dev, q, &buf, 1, tx_info, skb, NULL);
mt76_queue_kick(dev, q);
spin_unlock_bh(&q->lock);
+3 -6
View File
@@ -64,22 +64,19 @@ int mt76x2_tx_prepare_skb(struct mt76_dev *mdev, void *txwi,
{
struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int len, qsel = MT_QSEL_EDCA;
int qsel = MT_QSEL_EDCA;
int ret;
mt76x2_mac_write_txwi(dev, txwi, skb, wcid, sta);
ret = mt76_insert_hdr_pad(skb);
if (ret)
if (ret < 0)
return ret;
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
qsel = 0;
len = skb->len + sizeof(struct mt76x2_txwi);
len += mt76x2_mac_skb_tx_overhead(dev, skb);
*tx_info = MT76_SET(MT_TXD_INFO_LEN, len) |
MT76_SET(MT_TXD_INFO_QSEL, qsel) |
*tx_info = MT76_SET(MT_TXD_INFO_QSEL, qsel) |
MT_TXD_INFO_80211;
if (!wcid || wcid->hw_key_idx == 0xff)
+31 -9
View File
@@ -92,9 +92,12 @@ int mt76_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct ieee80211_sta *sta)
{
struct mt76_txwi_cache *t;
struct mt76_queue_buf buf[32];
struct sk_buff *iter;
dma_addr_t addr;
int len;
u32 tx_info = 0;
int ret;
int n, ret;
t = mt76_get_txwi(dev);
if (!t) {
@@ -110,21 +113,40 @@ int mt76_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
if (ret < 0)
goto free_txwi;
addr = dma_map_single(dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
len = skb->len - skb->data_len;
addr = dma_map_single(dev->dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(dev->dev, addr)) {
ret = -ENOMEM;
goto free_txwi;
}
ret = dev->queue_ops->add_buf(dev, q, t->dma_addr, dev->drv->txwi_size,
addr, skb->len, tx_info);
if (ret < 0)
return ret;
n = 0;
buf[n].addr = t->dma_addr;
buf[n++].len = dev->drv->txwi_size;
buf[n].addr = addr;
buf[n++].len = len;
q->entry[ret].skb = skb;
q->entry[ret].txwi = t;
skb_walk_frags(skb, iter) {
if (n == ARRAY_SIZE(buf))
goto unmap;
return ret;
addr = dma_map_single(dev->dev, iter->data, iter->len, DMA_TO_DEVICE);
if (dma_mapping_error(dev->dev, addr))
goto unmap;
buf[n].addr = addr;
buf[n++].len = iter->len;
}
if (q->queued + (n + 1) / 2 >= q->ndesc)
goto unmap;
return dev->queue_ops->add_buf(dev, q, buf, n, tx_info, skb, t);
unmap:
ret = -ENOMEM;
for (n--; n > 0; n--)
dma_unmap_single(dev->dev, buf[n].addr, buf[n].len, DMA_TO_DEVICE);
free_txwi:
mt76_put_txwi(dev, t);
+1 -1
View File
@@ -39,7 +39,7 @@ int mt76_insert_hdr_pad(struct sk_buff *skb)
skb->data[len] = 0;
skb->data[len + 1] = 0;
return 0;
return 2;
}
EXPORT_SYMBOL_GPL(mt76_insert_hdr_pad);