blob: 47564fc94a5d79cc1767fa13936a1946ebe186e4 [file] [log] [blame]
From 7873df2f26b6b5b22f8f6f696f4830a5282f6621 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Sun, 4 Feb 2024 17:52:44 +0800
Subject: [PATCH 2008/2012] wifi: mt76: connac: wed: add wed rx copy skb
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
dma.c | 71 +++++++++++++++++++++++++++++++++++++++++++++--------------
wed.c | 37 ++++++++++++++++++++++---------
2 files changed, 80 insertions(+), 28 deletions(-)
diff --git a/dma.c b/dma.c
index 53597b5..2f108de 100644
--- a/dma.c
+++ b/dma.c
@@ -225,10 +225,10 @@ void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
static int
mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
- struct mt76_queue_buf *buf, void *data)
+ struct mt76_queue_buf *buf, void *data,
+ struct mt76_rxwi_cache *rxwi)
{
struct mt76_queue_entry *entry = &q->entry[q->head];
- struct mt76_rxwi_cache *rxwi = NULL;
struct mt76_desc *desc;
int idx = q->head;
u32 buf1 = 0, ctrl;
@@ -249,9 +249,11 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
#endif
if (mt76_queue_is_wed_rx(q)) {
- rxwi = mt76_get_rxwi(dev);
- if (!rxwi)
- return -ENOMEM;
+ if (!rxwi) {
+ rxwi = mt76_get_rxwi(dev);
+ if (!rxwi)
+ return -ENOMEM;
+ }
rx_token = mt76_rx_token_consume(dev, data, rxwi, buf->addr);
if (rx_token < 0) {
@@ -421,7 +423,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
static void *
mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
- int *len, u32 *info, bool *more, bool *drop)
+ int *len, u32 *info, bool *more, bool *drop, bool flush)
{
struct mt76_queue_entry *e = &q->entry[idx];
struct mt76_desc *desc = &q->desc[idx];
@@ -478,11 +480,44 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
SKB_WITH_OVERHEAD(q->buf_size),
DMA_FROM_DEVICE);
- buf = r->ptr;
- r->dma_addr = 0;
- r->ptr = NULL;
+ if (flush) {
+ buf = r->ptr;
+ r->dma_addr = 0;
+ r->ptr = NULL;
+
+ mt76_put_rxwi(dev, r);
+ } else {
+ struct mt76_queue_buf qbuf;
+
+ buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC | GFP_DMA32);
+ if (!buf)
+ return NULL;
+
+ memcpy(buf, r->ptr, SKB_WITH_OVERHEAD(q->buf_size));
+
+ r->dma_addr = dma_map_single(dev->dma_dev, r->ptr,
+ SKB_WITH_OVERHEAD(q->buf_size),
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(dev->dma_dev, r->dma_addr))) {
+ skb_free_frag(r->ptr);
+ mt76_put_rxwi(dev, r);
+ return NULL;
+ }
+
+ qbuf.addr = r->dma_addr;
+ qbuf.len = SKB_WITH_OVERHEAD(q->buf_size);
+ qbuf.skip_unmap = false;
+
+ if (mt76_dma_add_rx_buf(dev, q, &qbuf, r->ptr, r) < 0) {
+ dma_unmap_single(dev->dma_dev, r->dma_addr,
+ SKB_WITH_OVERHEAD(q->buf_size),
+ DMA_FROM_DEVICE);
+ skb_free_frag(r->ptr);
+ mt76_put_rxwi(dev, r);
+ return NULL;
+ }
+ }
- mt76_put_rxwi(dev, r);
if (drop)
*drop |= !!(buf1 & MT_DMA_CTL_WO_DROP);
} else {
@@ -519,7 +554,7 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
- return mt76_dma_get_buf(dev, q, idx, len, info, more, drop);
+ return mt76_dma_get_buf(dev, q, idx, len, info, more, drop, flush);
}
static int
@@ -685,7 +720,7 @@ int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
done:
qbuf.len = len - offset;
qbuf.skip_unmap = false;
- if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {
+ if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf, NULL) < 0) {
dma_unmap_single(dev->dma_dev, addr, len,
DMA_FROM_DEVICE);
skb_free_frag(buf);
@@ -786,12 +821,14 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
spin_unlock_bh(&q->lock);
- if (!q->rx_page.va)
- return;
+ if (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) != MT76_WED_Q_RX) {
+ if (!q->rx_page.va)
+ return;
- page = virt_to_page(q->rx_page.va);
- __page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
- memset(&q->rx_page, 0, sizeof(q->rx_page));
+ page = virt_to_page(q->rx_page.va);
+ __page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
+ memset(&q->rx_page, 0, sizeof(q->rx_page));
+ }
}
static void
diff --git a/wed.c b/wed.c
index c03b52f..70e4057 100644
--- a/wed.c
+++ b/wed.c
@@ -9,12 +9,9 @@
void mt76_wed_release_rx_buf(struct mtk_wed_device *wed)
{
struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
- u32 length;
+ struct page *page;
int i;
- length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size +
- sizeof(struct skb_shared_info));
-
for (i = 0; i < dev->rx_token_size; i++) {
struct mt76_rxwi_cache *r;
@@ -24,13 +21,33 @@ void mt76_wed_release_rx_buf(struct mtk_wed_device *wed)
dma_unmap_single(dev->dma_dev, r->dma_addr,
wed->wlan.rx_size, DMA_FROM_DEVICE);
- __free_pages(virt_to_page(r->ptr), get_order(length));
+ skb_free_frag(r->ptr);
r->ptr = NULL;
mt76_put_rxwi(dev, r);
}
mt76_free_pending_rxwi(dev);
+
+ mt76_for_each_q_rx(dev, i) {
+ struct mt76_queue *q = &dev->q_rx[i];
+
+ if (mt76_queue_is_wed_rx(q)) {
+ if (!q->rx_page.va)
+ continue;
+
+ page = virt_to_page(q->rx_page.va);
+ __page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
+ memset(&q->rx_page, 0, sizeof(q->rx_page));
+ }
+ }
+
+ if (!wed->rx_buf_ring.rx_page.va)
+ return;
+
+ page = virt_to_page(wed->rx_buf_ring.rx_page.va);
+ __page_frag_cache_drain(page, wed->rx_buf_ring.rx_page.pagecnt_bias);
+ memset(&wed->rx_buf_ring.rx_page, 0, sizeof(wed->rx_buf_ring.rx_page));
}
EXPORT_SYMBOL_GPL(mt76_wed_release_rx_buf);
@@ -48,25 +65,23 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
for (i = 0; i < size; i++) {
struct mt76_rxwi_cache *r = mt76_get_rxwi(dev);
dma_addr_t phy_addr;
- struct page *page;
int token;
void *ptr;
if (!r)
goto unmap;
- page = __dev_alloc_pages(GFP_KERNEL, get_order(length));
- if (!page) {
+ ptr = page_frag_alloc(&wed->rx_buf_ring.rx_page, length, GFP_ATOMIC);
+ if (!ptr) {
mt76_put_rxwi(dev, r);
goto unmap;
}
- ptr = page_address(page);
phy_addr = dma_map_single(dev->dma_dev, ptr,
wed->wlan.rx_size,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev->dev, phy_addr))) {
- __free_pages(page, get_order(length));
+ skb_free_frag(ptr);
mt76_put_rxwi(dev, r);
goto unmap;
}
@@ -76,7 +91,7 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
if (token < 0) {
dma_unmap_single(dev->dma_dev, phy_addr,
wed->wlan.rx_size, DMA_TO_DEVICE);
- __free_pages(page, get_order(length));
+ skb_free_frag(ptr);
mt76_put_rxwi(dev, r);
goto unmap;
}
--
2.18.0