mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
add support for queueing frames spanning multiple descriptors
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
@@ -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,27 +50,45 @@ 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;
|
||||
|
||||
idx = q->head;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
for (i = 0; i < nbufs; i += 2, buf += 2) {
|
||||
u32 buf0 = buf[0].addr, buf1 = 0;
|
||||
|
||||
desc = &q->desc[idx];
|
||||
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);
|
||||
}
|
||||
|
||||
ACCESS_ONCE(desc->buf0) = cpu_to_le32(buf0);
|
||||
ACCESS_ONCE(desc->buf1) = cpu_to_le32(buf1);
|
||||
ACCESS_ONCE(desc->info) = cpu_to_le32(info);
|
||||
ACCESS_ONCE(desc->ctrl) = cpu_to_le32(ctrl);
|
||||
if (i == nbufs - 1)
|
||||
ctrl |= MT_DMA_CTL_LAST_SEC0;
|
||||
else if (i == nbufs - 2)
|
||||
ctrl |= MT_DMA_CTL_LAST_SEC1;
|
||||
|
||||
q->queued++;
|
||||
idx = q->head;
|
||||
q->head = (q->head + 1) % q->ndesc;
|
||||
|
||||
desc = &q->desc[idx];
|
||||
|
||||
ACCESS_ONCE(desc->buf0) = cpu_to_le32(buf0);
|
||||
ACCESS_ONCE(desc->buf1) = cpu_to_le32(buf1);
|
||||
ACCESS_ONCE(desc->info) = cpu_to_le32(info);
|
||||
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--;
|
||||
|
||||
done(dev, q, &entry);
|
||||
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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
+4
-7
@@ -64,23 +64,20 @@ 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) |
|
||||
MT_TXD_INFO_80211;
|
||||
*tx_info = MT76_SET(MT_TXD_INFO_QSEL, qsel) |
|
||||
MT_TXD_INFO_80211;
|
||||
|
||||
if (!wcid || wcid->hw_key_idx == 0xff)
|
||||
*tx_info |= MT_TXD_INFO_WIV;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user