2023-01-13 11:13:54

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH wireless 1/3] wifi: mt76: dma: do not increment queue head if mt76_dma_add_buf fails

From: Lorenzo Bianconi <[email protected]>

Do not increment queue head if mt76_dma_add_buf fails for Wireless
Ethernet Dispatcher rx queues.

Fixes: cd372b8c99c5 ("wifi: mt76: add WED RX support to mt76_dma_{add,get}_buf")
Signed-off-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
(cherry picked from commit fe13dad8992be0b26c1be390bcd111acf9892c17)
---
drivers/net/wireless/mediatek/mt76/dma.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index f795548562f5..c058a02e9ba5 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -212,14 +212,14 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
{
struct mt76_queue_entry *entry;
struct mt76_desc *desc;
- u32 ctrl;
int i, idx = -1;
+ u32 ctrl, next;

for (i = 0; i < nbufs; i += 2, buf += 2) {
u32 buf0 = buf[0].addr, buf1 = 0;

idx = q->head;
- q->head = (q->head + 1) % q->ndesc;
+ next = (q->head + 1) % q->ndesc;

desc = &q->desc[idx];
entry = &q->entry[idx];
@@ -239,8 +239,8 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
MT_DMA_CTL_TO_HOST;
} else {
if (txwi) {
- q->entry[q->head].txwi = DMA_DUMMY_DATA;
- q->entry[q->head].skip_buf0 = true;
+ q->entry[next].txwi = DMA_DUMMY_DATA;
+ q->entry[next].skip_buf0 = true;
}

if (buf[0].skip_unmap)
@@ -271,6 +271,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
WRITE_ONCE(desc->info, cpu_to_le32(info));
WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));

+ q->head = next;
q->queued++;
}

--
2.39.0


2023-01-13 11:13:55

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH wireless 3/3] wifi: mt76: dma: fix a regression in adding rx buffers

When adding WED support, mt76_dma_add_buf was accidentally changed to set
the skip_buf0 flag for tx buffers on the wrong queue descriptor entry.
Additionally, there is a rxwi leak when rx buffer allocation fails.

Fix this and make the code more readable by adding a separate function for
adding rx buffers.

Reported-by: Mikhail Gavrilov <[email protected]>
Tested-by: Mikhail Gavrilov <[email protected]>
Fixes: cd372b8c99c5 ("wifi: mt76: add WED RX support to mt76_dma_{add,get}_buf")
Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/mediatek/mt76/dma.c | 124 +++++++++++++----------
1 file changed, 72 insertions(+), 52 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 61a8ab9e1db5..06161815c180 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -205,6 +205,52 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
mt76_dma_sync_idx(dev, 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_desc *desc = &q->desc[q->head];
+ struct mt76_queue_entry *entry = &q->entry[q->head];
+ struct mt76_txwi_cache *txwi = NULL;
+ u32 buf1 = 0, ctrl;
+ int idx = q->head;
+ int rx_token;
+
+ ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+
+ if ((q->flags & MT_QFLAG_WED) &&
+ FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
+ txwi = mt76_get_rxwi(dev);
+ if (!txwi)
+ return -ENOMEM;
+
+ rx_token = mt76_rx_token_consume(dev, data, txwi, buf->addr);
+ if (rx_token < 0) {
+ mt76_put_rxwi(dev, txwi);
+ return -ENOMEM;
+ }
+
+ buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);
+ ctrl |= MT_DMA_CTL_TO_HOST;
+ }
+
+ WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr));
+ WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
+ WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
+ WRITE_ONCE(desc->info, 0);
+
+ entry->dma_addr[0] = buf->addr;
+ entry->dma_len[0] = buf->len;
+ entry->txwi = txwi;
+ entry->buf = data;
+ entry->wcid = 0xffff;
+ entry->skip_buf1 = true;
+ q->head = (q->head + 1) % q->ndesc;
+ q->queued++;
+
+ return idx;
+}
+
static int
mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_buf *buf, int nbufs, u32 info,
@@ -215,6 +261,11 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
int i, idx = -1;
u32 ctrl, next;

+ if (txwi) {
+ q->entry[q->head].txwi = DMA_DUMMY_DATA;
+ q->entry[q->head].skip_buf0 = true;
+ }
+
for (i = 0; i < nbufs; i += 2, buf += 2) {
u32 buf0 = buf[0].addr, buf1 = 0;

@@ -224,51 +275,28 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
desc = &q->desc[idx];
entry = &q->entry[idx];

- if ((q->flags & MT_QFLAG_WED) &&
- FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
- struct mt76_txwi_cache *t = txwi;
- int rx_token;
-
- if (!t)
- return -ENOMEM;
-
- rx_token = mt76_rx_token_consume(dev, (void *)skb, t,
- buf[0].addr);
- if (rx_token < 0)
- return -ENOMEM;
-
- buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);
- ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len) |
- MT_DMA_CTL_TO_HOST;
- } else {
- if (txwi) {
- q->entry[next].txwi = DMA_DUMMY_DATA;
- q->entry[next].skip_buf0 = true;
- }
-
- if (buf[0].skip_unmap)
- entry->skip_buf0 = true;
- entry->skip_buf1 = i == nbufs - 1;
-
- entry->dma_addr[0] = buf[0].addr;
- entry->dma_len[0] = buf[0].len;
-
- ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
- if (i < nbufs - 1) {
- entry->dma_addr[1] = buf[1].addr;
- entry->dma_len[1] = buf[1].len;
- buf1 = buf[1].addr;
- ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
- if (buf[1].skip_unmap)
- entry->skip_buf1 = true;
- }
-
- if (i == nbufs - 1)
- ctrl |= MT_DMA_CTL_LAST_SEC0;
- else if (i == nbufs - 2)
- ctrl |= MT_DMA_CTL_LAST_SEC1;
+ if (buf[0].skip_unmap)
+ entry->skip_buf0 = true;
+ entry->skip_buf1 = i == nbufs - 1;
+
+ entry->dma_addr[0] = buf[0].addr;
+ entry->dma_len[0] = buf[0].len;
+
+ ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+ if (i < nbufs - 1) {
+ entry->dma_addr[1] = buf[1].addr;
+ entry->dma_len[1] = buf[1].len;
+ buf1 = buf[1].addr;
+ ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
+ if (buf[1].skip_unmap)
+ entry->skip_buf1 = true;
}

+ if (i == nbufs - 1)
+ ctrl |= MT_DMA_CTL_LAST_SEC0;
+ else if (i == nbufs - 2)
+ ctrl |= MT_DMA_CTL_LAST_SEC1;
+
WRITE_ONCE(desc->buf0, cpu_to_le32(buf0));
WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
WRITE_ONCE(desc->info, cpu_to_le32(info));
@@ -581,17 +609,9 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
spin_lock_bh(&q->lock);

while (q->queued < q->ndesc - 1) {
- struct mt76_txwi_cache *t = NULL;
struct mt76_queue_buf qbuf;
void *buf = NULL;

- if ((q->flags & MT_QFLAG_WED) &&
- FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
- t = mt76_get_rxwi(dev);
- if (!t)
- break;
- }
-
buf = page_frag_alloc(rx_page, q->buf_size, GFP_ATOMIC);
if (!buf)
break;
@@ -605,7 +625,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_buf(dev, q, &qbuf, 1, 0, buf, t) < 0) {
+ if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {
dma_unmap_single(dev->dma_dev, addr, len,
DMA_FROM_DEVICE);
skb_free_frag(buf);
--
2.39.0

2023-01-13 11:15:28

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH wireless 2/3] wifi: mt76: handle possible mt76_rx_token_consume failures

From: Lorenzo Bianconi <[email protected]>

Take into account possible error conditions of mt76_rx_token_consume
routine in mt7915_mmio_wed_init_rx_buf() and mt76_dma_add_buf()

Fixes: cd372b8c99c5 ("wifi: mt76: add WED RX support to mt76_dma_{add,get}_buf")
Fixes: 4f831d18d12d ("wifi: mt76: mt7915: enable WED RX support")
Signed-off-by: Lorenzo Bianconi <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
(cherry picked from commit 96f134dc19645be4994e89a2f68fa89309becbee)
---
drivers/net/wireless/mediatek/mt76/dma.c | 10 +++++++++-
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 7 +++++++
drivers/net/wireless/mediatek/mt76/tx.c | 7 ++++---
3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index c058a02e9ba5..61a8ab9e1db5 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -234,6 +234,9 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,

rx_token = mt76_rx_token_consume(dev, (void *)skb, t,
buf[0].addr);
+ if (rx_token < 0)
+ return -ENOMEM;
+
buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token);
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len) |
MT_DMA_CTL_TO_HOST;
@@ -602,7 +605,12 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
qbuf.addr = addr + offset;
qbuf.len = len - offset;
qbuf.skip_unmap = false;
- mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t);
+ if (mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, t) < 0) {
+ dma_unmap_single(dev->dma_dev, addr, len,
+ DMA_FROM_DEVICE);
+ skb_free_frag(buf);
+ break;
+ }
frames++;
}

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index 0a95c3da241b..8388e2a65853 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -653,6 +653,13 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)

desc->buf0 = cpu_to_le32(phy_addr);
token = mt76_rx_token_consume(&dev->mt76, ptr, t, phy_addr);
+ if (token < 0) {
+ dma_unmap_single(dev->mt76.dma_dev, phy_addr,
+ wed->wlan.rx_size, DMA_TO_DEVICE);
+ skb_free_frag(ptr);
+ goto unmap;
+ }
+
desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN,
token));
desc++;
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 24568b98ed9d..1f309d05380a 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -764,11 +764,12 @@ int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
spin_lock_bh(&dev->rx_token_lock);
token = idr_alloc(&dev->rx_token, t, 0, dev->rx_token_size,
GFP_ATOMIC);
+ if (token >= 0) {
+ t->ptr = ptr;
+ t->dma_addr = phys;
+ }
spin_unlock_bh(&dev->rx_token_lock);

- t->ptr = ptr;
- t->dma_addr = phys;
-
return token;
}
EXPORT_SYMBOL_GPL(mt76_rx_token_consume);
--
2.39.0

Subject: Re: [PATCH wireless 3/3] wifi: mt76: dma: fix a regression in adding rx buffers

On 13.01.23 11:58, Felix Fietkau wrote:
> When adding WED support, mt76_dma_add_buf was accidentally changed to set
> the skip_buf0 flag for tx buffers on the wrong queue descriptor entry.
> Additionally, there is a rxwi leak when rx buffer allocation fails.

thx for working on this

> Fix this and make the code more readable by adding a separate function for
> adding rx buffers.
>
> Reported-by: Mikhail Gavrilov <[email protected]>
> Tested-by: Mikhail Gavrilov <[email protected]>

Many thx for taking care of this. There is one small thing to improve,
please add the following tags here to make things easier for future code
archaeologists and give proper credit:

Link:
https://lore.kernel.org/r/CABXGCsMEnQd=gYKTd1knRsWuxCb=Etv5nAre%[email protected]/
Reported-by: Mike Lothian <[email protected]>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216829
Reported-by: AngeloGioacchino Del Regno
Link:
https://lore.kernel.org/lkml/[email protected]/

To explain: Linus[1] and others considered proper link tags important in
cases like this, as they allow anyone to look into the backstory of a
fix weeks or years later. That's nothing new, the documentation[2] for
some time says to place such tags in cases like this. I care personally
(and made it a bit more explicit in the docs a while ago), because these
tags make my regression tracking efforts a whole lot easier, as they
allow my tracking bot 'regzbot' to automatically connect reports with
patches posted or committed to fix tracked regressions.

Apropos regzbot, let me tell regzbot to monitor this thread:

#regzbot ^backmonitor:
https://lore.kernel.org/r/CABXGCsMEnQd=gYKTd1knRsWuxCb=Etv5nAre%[email protected]/

> [...]

Ciao, Thorsten (wearing his 'the Linux kernel's regression tracker' hat)

[1] for details, see:
https://lore.kernel.org/all/CAHk-=wjMmSZzMJ3Xnskdg4+GGz=5p5p+GSYyFBTh0f-DgvdBWg@mail.gmail.com/
https://lore.kernel.org/all/CAHk-=wgs38ZrfPvy=nOwVkVzjpM3VFU1zobP37Fwd_h9iAD5JQ@mail.gmail.com/
https://lore.kernel.org/all/CAHk-=wjxzafG-=J8oT30s7upn4RhBs6TX-uVFZ5rME+L5_DoJA@mail.gmail.com/

[2] see Documentation/process/submitting-patches.rst
(http://docs.kernel.org/process/submitting-patches.html) and
Documentation/process/5.Posting.rst
(https://docs.kernel.org/process/5.Posting.html)

--
Everything you wanna know about Linux kernel regression tracking:
https://linux-regtracking.leemhuis.info/about/#tldr
If I did something stupid, please tell me, as explained on that page.

2023-01-13 16:21:41

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH wireless 3/3] wifi: mt76: dma: fix a regression in adding rx buffers

"Linux kernel regression tracking (Thorsten Leemhuis)"
<[email protected]> writes:

> On 13.01.23 11:58, Felix Fietkau wrote:
>> When adding WED support, mt76_dma_add_buf was accidentally changed to set
>> the skip_buf0 flag for tx buffers on the wrong queue descriptor entry.
>> Additionally, there is a rxwi leak when rx buffer allocation fails.
>
> thx for working on this
>
>> Fix this and make the code more readable by adding a separate function for
>> adding rx buffers.
>>
>> Reported-by: Mikhail Gavrilov <[email protected]>
>> Tested-by: Mikhail Gavrilov <[email protected]>
>
> Many thx for taking care of this. There is one small thing to improve,
> please add the following tags here to make things easier for future code
> archaeologists and give proper credit:

I can add those.

> Link:
> https://lore.kernel.org/r/CABXGCsMEnQd=gYKTd1knRsWuxCb=Etv5nAre%[email protected]/
> Reported-by: Mike Lothian <[email protected]>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=216829
> Reported-by: AngeloGioacchino Del Regno

But the email is missing for AngeloGioacchino.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

Subject: Re: [PATCH wireless 3/3] wifi: mt76: dma: fix a regression in adding rx buffers

On 13.01.23 16:57, Kalle Valo wrote:
> "Linux kernel regression tracking (Thorsten Leemhuis)"
> <[email protected]> writes:
>
>> On 13.01.23 11:58, Felix Fietkau wrote:
>>> When adding WED support, mt76_dma_add_buf was accidentally changed to set
>>> the skip_buf0 flag for tx buffers on the wrong queue descriptor entry.
>>> Additionally, there is a rxwi leak when rx buffer allocation fails.
>>
>> thx for working on this
>>
>>> Fix this and make the code more readable by adding a separate function for
>>> adding rx buffers.
>>>
>>> Reported-by: Mikhail Gavrilov <[email protected]>
>>> Tested-by: Mikhail Gavrilov <[email protected]>
>>
>> Many thx for taking care of this. There is one small thing to improve,
>> please add the following tags here to make things easier for future code
>> archaeologists and give proper credit:
>
> I can add those.

Great, many thx!

>> Link:
>> https://lore.kernel.org/r/CABXGCsMEnQd=gYKTd1knRsWuxCb=Etv5nAre%[email protected]/
>> Reported-by: Mike Lothian <[email protected]>
>> Link: https://bugzilla.kernel.org/show_bug.cgi?id=216829
>> Reported-by: AngeloGioacchino Del Regno
>
> But the email is missing for AngeloGioacchino.

/me wonders how that happened

Sorry for that. Here it is again:

Reported-by: AngeloGioacchino Del Regno
<[email protected]>
Ciao, Thorsten

2023-01-16 15:36:29

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH wireless 1/3] wifi: mt76: dma: do not increment queue head if mt76_dma_add_buf fails

Felix Fietkau <[email protected]> wrote:

> From: Lorenzo Bianconi <[email protected]>
>
> Do not increment queue head if mt76_dma_add_buf fails for Wireless
> Ethernet Dispatcher rx queues.
>
> Fixes: cd372b8c99c5 ("wifi: mt76: add WED RX support to mt76_dma_{add,get}_buf")
> Signed-off-by: Lorenzo Bianconi <[email protected]>
> Signed-off-by: Felix Fietkau <[email protected]>
> (cherry picked from commit fe13dad8992be0b26c1be390bcd111acf9892c17)

3 patches applied to wireless.git, thanks.

1132d1c834d6 wifi: mt76: dma: do not increment queue head if mt76_dma_add_buf fails
e5c3ac895750 wifi: mt76: handle possible mt76_rx_token_consume failures
953519b35227 wifi: mt76: dma: fix a regression in adding rx buffers

--
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches