blob: a50ea6c34a4d8e852b97f4f1f71ce3359338b366 [file] [log] [blame]
From 7a963d92dd37bb16d00cc9ba7684f131d3331a78 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Thu, 5 Jan 2023 16:43:57 +0800
Subject: [PATCH 2008/2011] wifi: mt76: connac: wed: add wed rx copy skb
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
---
dma.c | 76 +++++++++++++++++++++++++++++++++++++++------------
mt7915/mmio.c | 35 ++++++++++++++++++------
2 files changed, 85 insertions(+), 26 deletions(-)
diff --git a/dma.c b/dma.c
index e3e2f38..7c5e623 100644
--- a/dma.c
+++ b/dma.c
@@ -213,11 +213,11 @@ 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_desc *desc = &q->desc[q->head];
struct mt76_queue_entry *entry = &q->entry[q->head];
- struct mt76_rxwi_cache *rxwi = NULL;
u32 buf1 = 0, ctrl;
int idx = q->head;
int rx_token;
@@ -225,9 +225,11 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
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) {
@@ -389,7 +391,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];
@@ -439,11 +441,43 @@ 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);
+ mt76_put_rxwi(dev, r);
+ } else {
+ struct mt76_queue_buf qbuf;
+
+ buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
+ 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;
+ }
+ }
if (drop) {
u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
@@ -482,7 +516,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
@@ -622,6 +656,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
int len = SKB_WITH_OVERHEAD(q->buf_size);
int frames = 0, offset = q->buf_offset;
dma_addr_t addr;
+ bool flags = false;
if (!q->ndesc)
return 0;
@@ -645,7 +680,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
qbuf.addr = addr + offset;
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);
@@ -654,7 +689,10 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
frames++;
}
- if (frames)
+ flags = (q->flags & MT_QFLAG_WED) &&
+ FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX;
+
+ if (frames || flags)
mt76_dma_kick_queue(dev, q);
spin_unlock_bh(&q->lock);
@@ -777,12 +815,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/mt7915/mmio.c b/mt7915/mmio.c
index d739390..aa5c5dd 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -614,6 +614,7 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
{
struct mt7915_dev *dev;
+ struct page *page;
u32 length;
int i;
@@ -630,13 +631,33 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
dma_unmap_single(dev->mt76.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->mt76, r);
}
mt76_free_pending_rxwi(&dev->mt76);
+
+ mt76_for_each_q_rx(&dev->mt76, i) {
+ struct mt76_queue *q = &dev->mt76.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));
}
static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
@@ -653,35 +674,33 @@ static u32 mt7915_mmio_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->mt76);
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->mt76, r);
goto unmap;
}
- ptr = page_address(page);
phy_addr = dma_map_single(dev->mt76.dma_dev, ptr,
wed->wlan.rx_size,
DMA_TO_DEVICE);
+
if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) {
- __free_pages(page, get_order(length));
+ skb_free_frag(ptr);
mt76_put_rxwi(&dev->mt76, r);
goto unmap;
}
-
desc->buf0 = cpu_to_le32(phy_addr);
token = mt76_rx_token_consume(&dev->mt76, ptr, r, phy_addr);
if (token < 0) {
dma_unmap_single(dev->mt76.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->mt76, r);
goto unmap;
}
--
2.18.0