From: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
To: Grygorii Strashko <grygorii.strashko@ti.com>
Cc: "David S. Miller" <davem@davemloft.net>,
netdev@vger.kernel.org, Sekhar Nori <nsekhar@ti.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] net: ethernet: ti: davinci_cpdma: fix warning "device driver frees DMA memory with different size"
Date: Wed, 4 Dec 2019 16:22:03 +0200 [thread overview]
Message-ID: <20191204142202.GG2680@khorivan> (raw)
In-Reply-To: <20191204124618.18774-1-grygorii.strashko@ti.com>
Hi Grygorii,
On Wed, Dec 04, 2019 at 02:46:18PM +0200, Grygorii Strashko wrote:
>The TI CPSW(s) driver produces warning with DMA API debug options enabled:
>
>WARNING: CPU: 0 PID: 1033 at kernel/dma/debug.c:1025 check_unmap+0x4a8/0x968
>DMA-API: cpsw 48484000.ethernet: device driver frees DMA memory with different size
> [device address=0x00000000abc6aa02] [map size=64 bytes] [unmap size=42 bytes]
>CPU: 0 PID: 1033 Comm: ping Not tainted 5.3.0-dirty #41
>Hardware name: Generic DRA72X (Flattened Device Tree)
>[<c0112c60>] (unwind_backtrace) from [<c010d270>] (show_stack+0x10/0x14)
>[<c010d270>] (show_stack) from [<c09bc564>] (dump_stack+0xd8/0x110)
>[<c09bc564>] (dump_stack) from [<c013b93c>] (__warn+0xe0/0x10c)
>[<c013b93c>] (__warn) from [<c013b9ac>] (warn_slowpath_fmt+0x44/0x6c)
>[<c013b9ac>] (warn_slowpath_fmt) from [<c01e0368>] (check_unmap+0x4a8/0x968)
>[<c01e0368>] (check_unmap) from [<c01e08a8>] (debug_dma_unmap_page+0x80/0x90)
>[<c01e08a8>] (debug_dma_unmap_page) from [<c0752414>] (__cpdma_chan_free+0x114/0x16c)
>[<c0752414>] (__cpdma_chan_free) from [<c07525c4>] (__cpdma_chan_process+0x158/0x17c)
>[<c07525c4>] (__cpdma_chan_process) from [<c0753690>] (cpdma_chan_process+0x3c/0x5c)
>[<c0753690>] (cpdma_chan_process) from [<c0758660>] (cpsw_tx_mq_poll+0x48/0x94)
>[<c0758660>] (cpsw_tx_mq_poll) from [<c0803018>] (net_rx_action+0x108/0x4e4)
>[<c0803018>] (net_rx_action) from [<c010230c>] (__do_softirq+0xec/0x598)
>[<c010230c>] (__do_softirq) from [<c0143914>] (do_softirq.part.4+0x68/0x74)
>[<c0143914>] (do_softirq.part.4) from [<c0143a44>] (__local_bh_enable_ip+0x124/0x17c)
>[<c0143a44>] (__local_bh_enable_ip) from [<c0871590>] (ip_finish_output2+0x294/0xb7c)
>[<c0871590>] (ip_finish_output2) from [<c0875440>] (ip_output+0x210/0x364)
>[<c0875440>] (ip_output) from [<c0875e2c>] (ip_send_skb+0x1c/0xf8)
>[<c0875e2c>] (ip_send_skb) from [<c08a7fd4>] (raw_sendmsg+0x9a8/0xc74)
>[<c08a7fd4>] (raw_sendmsg) from [<c07d6b90>] (sock_sendmsg+0x14/0x24)
>[<c07d6b90>] (sock_sendmsg) from [<c07d8260>] (__sys_sendto+0xbc/0x100)
>[<c07d8260>] (__sys_sendto) from [<c01011ac>] (__sys_trace_return+0x0/0x14)
>Exception stack(0xea9a7fa8 to 0xea9a7ff0)
>...
>
>The reason is that cpdma_chan_submit_si() now stores original buffer length
>(sw_len) in CPDMA descriptor instead of adjusted buffer length (hw_len)
>used to map the buffer.
It's kind not complete fix.
Seems like debug just shows it only fo dma_map, but for sync it doesn't.
The issue is not in swlen, it contains smilar size and inited to len equally as
hw_len. Problem that hw_len is inited later then swlen after below:
if (len < ctlr->params.min_packet_size) {
len = ctlr->params.min_packet_size;
chan->stats.runt_transmit_buff++;
}
Thus it potentially can have different size for lens less min_pakcet_size, that
could never happen but tracked with dma debug.
mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
cpdma_desc_to_port(chan, mode, si->directed);
if (si->data_dma) {
buffer = si->data_dma;
dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir);
swlen |= CPDMA_DMA_EXT_MAP;
} else {
buffer = dma_map_single(ctlr->dev, si->data_virt, len, chan->dir);
ret = dma_mapping_error(ctlr->dev, buffer);
if (ret) {
cpdma_desc_free(ctlr->pool, desc, 1);
return -EINVAL;
}
}
So, the fix you propose do it only for dma_map_single. But, even it should never
happen, it should be fixed for dma_sync() also for consistency.
Proposition is to move the following initialization:
int swlen = len;
after
if (len < ctlr->params.min_packet_size) {
len = ctlr->params.min_packet_size;
chan->stats.runt_transmit_buff++;
}
-> swlen = len;
And that should work for both cases, even if dma_sync uses len:
dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir);
....
>
>Hence, fix an issue by using adjusted buffer length (hw_len) to unmap
>packet buffer.
>
>Cc: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
>Fixes: 6670acacd59e ("net: ethernet: ti: davinci_cpdma: add dma mapped submit")
>Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>---
> drivers/net/ethernet/ti/davinci_cpdma.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
>index 37ba708ac781..6be5a514d5b1 100644
>--- a/drivers/net/ethernet/ti/davinci_cpdma.c
>+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
>@@ -1197,12 +1197,13 @@ static void __cpdma_chan_free(struct cpdma_chan *chan,
> {
> struct cpdma_ctlr *ctlr = chan->ctlr;
> struct cpdma_desc_pool *pool = ctlr->pool;
>+ int origlen, hw_len;
> dma_addr_t buff_dma;
>- int origlen;
> uintptr_t token;
>
> token = desc_read(desc, sw_token);
> origlen = desc_read(desc, sw_len);
>+ hw_len = desc_read(desc, hw_len);
>
> buff_dma = desc_read(desc, sw_buffer);
> if (origlen & CPDMA_DMA_EXT_MAP) {
>@@ -1210,7 +1211,7 @@ static void __cpdma_chan_free(struct cpdma_chan *chan,
> dma_sync_single_for_cpu(ctlr->dev, buff_dma, origlen,
> chan->dir);
> } else {
>- dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
>+ dma_unmap_single(ctlr->dev, buff_dma, hw_len, chan->dir);
> }
I've tried to avod two register reads on data path. So read only one sw_len
that actually supposed to contain same size. So proposition is to fix it like
in above comment would be more correct, and leave this func unchanged I mean in:
static int cpdma_chan_submit_si(struct submit_info *si) {}
>
> cpdma_desc_free(pool, desc, 1);
>--
>2.17.1
>
--
Regards,
Ivan Khoronzhuk
next prev parent reply other threads:[~2019-12-04 14:22 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-04 12:46 [PATCH] net: ethernet: ti: davinci_cpdma: fix warning "device driver frees DMA memory with different size" Grygorii Strashko
2019-12-04 14:22 ` Ivan Khoronzhuk [this message]
-- strict thread matches above, loose matches on Subject: below --
2019-12-09 11:19 Grygorii Strashko
2019-12-09 20:39 ` Ivan Khoronzhuk
2019-12-09 22:26 ` David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191204142202.GG2680@khorivan \
--to=ivan.khoronzhuk@linaro.org \
--cc=davem@davemloft.net \
--cc=grygorii.strashko@ti.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=nsekhar@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.