From: <miles.chen@mediatek.com>
To: Robin Murphy <robin.murphy@arm.com>,
Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org,
wsd_upstream@mediatek.com, linux-mediatek@lists.infradead.org,
iommu@lists.linux-foundation.org,
Miles Chen <miles.chen@mediatek.com>
Subject: [PATCH] dma-debug: fix incorrect pfn calculation
Date: Tue, 26 Sep 2017 21:24:47 +0800 [thread overview]
Message-ID: <1506432287-7214-1-git-send-email-miles.chen@mediatek.com> (raw)
From: Miles Chen <miles.chen@mediatek.com>
dma-debug report the following warning:
[name:panic&]WARNING: CPU: 3 PID: 298 at kernel-4.4/lib/dma-debug.c:604
debug _dma_assert_idle+0x1a8/0x230()
DMA-API: cpu touching an active dma mapped cacheline [cln=0x00000882300]
CPU: 3 PID: 298 Comm: vold Tainted: G W O 4.4.22+ #1
Hardware name: MT6739 (DT)
Call trace:
[<ffffff800808acd0>] dump_backtrace+0x0/0x1d4
[<ffffff800808affc>] show_stack+0x14/0x1c
[<ffffff800838019c>] dump_stack+0xa8/0xe0
[<ffffff80080a0594>] warn_slowpath_common+0xf4/0x11c
[<ffffff80080a061c>] warn_slowpath_fmt+0x60/0x80
[<ffffff80083afe24>] debug_dma_assert_idle+0x1a8/0x230
[<ffffff80081dca9c>] wp_page_copy.isra.96+0x118/0x520
[<ffffff80081de114>] do_wp_page+0x4fc/0x534
[<ffffff80081e0a14>] handle_mm_fault+0xd4c/0x1310
[<ffffff8008098798>] do_page_fault+0x1c8/0x394
[<ffffff800808231c>] do_mem_abort+0x50/0xec
I found that debug_dma_alloc_coherent() and debug_dma_free_coherent()
always use type "dma_debug_coherent" and assume that dma_alloc_coherent()
always returns a linear address.
However if a device returns false on is_device_dma_coherent(),
dma_alloc_coherent() will create another non-cacheable mapping
(also non linear). In this case, page_to_pfn(virt_to_page(virt)) will
return an incorrect pfn. If the pfn is valid and mapped as a COW page,
we will hit the warning when doing wp_page_copy().
Fix this by calculating correct pfn if is_device_dma_coherent()
returns false.
Signed-off-by: Miles Chen <miles.chen@mediatek.com>
---
lib/dma-debug.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index ea4cc3d..b17e56e 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -47,6 +47,8 @@ enum {
dma_debug_sg,
dma_debug_coherent,
dma_debug_resource,
+ dma_debug_noncoherent,
+ nr_dma_debug_types,
};
enum map_err_types {
@@ -154,9 +156,9 @@ static inline bool dma_debug_disabled(void)
[MAP_ERR_CHECKED] = "dma map error checked",
};
-static const char *type2name[5] = { "single", "page",
+static const char *type2name[nr_dma_debug_types] = { "single", "page",
"scather-gather", "coherent",
- "resource" };
+ "resource", "noncoherent" };
static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
"DMA_FROM_DEVICE", "DMA_NONE" };
@@ -1484,6 +1486,7 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t dma_addr, void *virt)
{
struct dma_debug_entry *entry;
+ bool coherent = is_device_dma_coherent(dev);
if (unlikely(dma_debug_disabled()))
return;
@@ -1495,9 +1498,11 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
if (!entry)
return;
- entry->type = dma_debug_coherent;
+ entry->type = coherent ? dma_debug_coherent :
+ dma_debug_noncoherent;
entry->dev = dev;
- entry->pfn = page_to_pfn(virt_to_page(virt));
+ entry->pfn = coherent ? page_to_pfn(virt_to_page(virt)) :
+ dma_addr >> PAGE_SHIFT;
entry->offset = offset_in_page(virt);
entry->size = size;
entry->dev_addr = dma_addr;
@@ -1510,10 +1515,13 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
void debug_dma_free_coherent(struct device *dev, size_t size,
void *virt, dma_addr_t addr)
{
+ bool coherent = is_device_dma_coherent(dev);
struct dma_debug_entry ref = {
- .type = dma_debug_coherent,
+ .type = coherent ? dma_debug_coherent :
+ dma_debug_noncoherent,
.dev = dev,
- .pfn = page_to_pfn(virt_to_page(virt)),
+ .pfn = coherent ? page_to_pfn(virt_to_page(virt)) :
+ addr >> PAGE_SHIFT,
.offset = offset_in_page(virt),
.dev_addr = addr,
.size = size,
--
1.9.1
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
WARNING: multiple messages have this Message-ID (diff)
From: <miles.chen@mediatek.com>
To: Robin Murphy <robin.murphy@arm.com>,
Andrew Morton <akpm@linux-foundation.org>
Cc: <linux-kernel@vger.kernel.org>, <linux-mm@kvack.org>,
<wsd_upstream@mediatek.com>, <linux-mediatek@lists.infradead.org>,
<iommu@lists.linux-foundation.org>,
Miles Chen <miles.chen@mediatek.com>
Subject: [PATCH] dma-debug: fix incorrect pfn calculation
Date: Tue, 26 Sep 2017 21:24:47 +0800 [thread overview]
Message-ID: <1506432287-7214-1-git-send-email-miles.chen@mediatek.com> (raw)
From: Miles Chen <miles.chen@mediatek.com>
dma-debug report the following warning:
[name:panic&]WARNING: CPU: 3 PID: 298 at kernel-4.4/lib/dma-debug.c:604
debug _dma_assert_idle+0x1a8/0x230()
DMA-API: cpu touching an active dma mapped cacheline [cln=0x00000882300]
CPU: 3 PID: 298 Comm: vold Tainted: G W O 4.4.22+ #1
Hardware name: MT6739 (DT)
Call trace:
[<ffffff800808acd0>] dump_backtrace+0x0/0x1d4
[<ffffff800808affc>] show_stack+0x14/0x1c
[<ffffff800838019c>] dump_stack+0xa8/0xe0
[<ffffff80080a0594>] warn_slowpath_common+0xf4/0x11c
[<ffffff80080a061c>] warn_slowpath_fmt+0x60/0x80
[<ffffff80083afe24>] debug_dma_assert_idle+0x1a8/0x230
[<ffffff80081dca9c>] wp_page_copy.isra.96+0x118/0x520
[<ffffff80081de114>] do_wp_page+0x4fc/0x534
[<ffffff80081e0a14>] handle_mm_fault+0xd4c/0x1310
[<ffffff8008098798>] do_page_fault+0x1c8/0x394
[<ffffff800808231c>] do_mem_abort+0x50/0xec
I found that debug_dma_alloc_coherent() and debug_dma_free_coherent()
always use type "dma_debug_coherent" and assume that dma_alloc_coherent()
always returns a linear address.
However if a device returns false on is_device_dma_coherent(),
dma_alloc_coherent() will create another non-cacheable mapping
(also non linear). In this case, page_to_pfn(virt_to_page(virt)) will
return an incorrect pfn. If the pfn is valid and mapped as a COW page,
we will hit the warning when doing wp_page_copy().
Fix this by calculating correct pfn if is_device_dma_coherent()
returns false.
Signed-off-by: Miles Chen <miles.chen@mediatek.com>
---
lib/dma-debug.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index ea4cc3d..b17e56e 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -47,6 +47,8 @@ enum {
dma_debug_sg,
dma_debug_coherent,
dma_debug_resource,
+ dma_debug_noncoherent,
+ nr_dma_debug_types,
};
enum map_err_types {
@@ -154,9 +156,9 @@ static inline bool dma_debug_disabled(void)
[MAP_ERR_CHECKED] = "dma map error checked",
};
-static const char *type2name[5] = { "single", "page",
+static const char *type2name[nr_dma_debug_types] = { "single", "page",
"scather-gather", "coherent",
- "resource" };
+ "resource", "noncoherent" };
static const char *dir2name[4] = { "DMA_BIDIRECTIONAL", "DMA_TO_DEVICE",
"DMA_FROM_DEVICE", "DMA_NONE" };
@@ -1484,6 +1486,7 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t dma_addr, void *virt)
{
struct dma_debug_entry *entry;
+ bool coherent = is_device_dma_coherent(dev);
if (unlikely(dma_debug_disabled()))
return;
@@ -1495,9 +1498,11 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
if (!entry)
return;
- entry->type = dma_debug_coherent;
+ entry->type = coherent ? dma_debug_coherent :
+ dma_debug_noncoherent;
entry->dev = dev;
- entry->pfn = page_to_pfn(virt_to_page(virt));
+ entry->pfn = coherent ? page_to_pfn(virt_to_page(virt)) :
+ dma_addr >> PAGE_SHIFT;
entry->offset = offset_in_page(virt);
entry->size = size;
entry->dev_addr = dma_addr;
@@ -1510,10 +1515,13 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
void debug_dma_free_coherent(struct device *dev, size_t size,
void *virt, dma_addr_t addr)
{
+ bool coherent = is_device_dma_coherent(dev);
struct dma_debug_entry ref = {
- .type = dma_debug_coherent,
+ .type = coherent ? dma_debug_coherent :
+ dma_debug_noncoherent,
.dev = dev,
- .pfn = page_to_pfn(virt_to_page(virt)),
+ .pfn = coherent ? page_to_pfn(virt_to_page(virt)) :
+ addr >> PAGE_SHIFT,
.offset = offset_in_page(virt),
.dev_addr = addr,
.size = size,
--
1.9.1
next reply other threads:[~2017-09-26 13:24 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-09-26 13:24 miles.chen [this message]
2017-09-26 13:24 ` [PATCH] dma-debug: fix incorrect pfn calculation miles.chen
[not found] ` <1506432287-7214-1-git-send-email-miles.chen-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
2017-09-26 14:53 ` Robin Murphy
2017-09-26 14:53 ` Robin Murphy
2017-09-26 14:53 ` Robin Murphy
2017-09-27 1:07 ` Miles Chen
2017-09-27 1:07 ` Miles Chen
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=1506432287-7214-1-git-send-email-miles.chen@mediatek.com \
--to=miles.chen@mediatek.com \
--cc=akpm@linux-foundation.org \
--cc=iommu@lists.linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-mm@kvack.org \
--cc=robin.murphy@arm.com \
--cc=wsd_upstream@mediatek.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.