From: Andrew Lewis <andrew-lewis@netspace.net.au>
To: linuxppc-dev@ozlabs.org
Cc: 'Andrew Lewis' <andrew-lewis@netspace.net.au>, paulus@samba.org
Subject: [PATCH/RFC] powerpc: prevent memory corruption due to cache invalidation of unaligned DMA buffer
Date: Thu, 26 Jun 2008 17:29:05 +0800 [thread overview]
Message-ID: <48636161.6080603@netspace.net.au> (raw)
On PowerPC processors with non-coherent cache architectures the DMA
subsystem calls invalidate_dcache_range() before performing a DMA read
operation. If the address and length of the DMA buffer are not aligned
to a cache-line boundary this can result in memory outside of the DMA
buffer being invalidated in the cache. If this memory has an
uncommitted store then the data will be lost and a subsequent read of
that address will result in an old value being returned from main memory.
Only when the DMA buffer starts on a cache-line boundary and is an exact
mutiple of the cache-line size can invalidate_dcache_range() be called,
otherwise flush_dcache_range() must be called. flush_dcache_range()
will first flush uncommitted writes, and then invalidate the cache.
Signed-off-by: Andrew Lewis <andrew-lewis at netspace.net.au>
---
This problem was originally observed using SLUB on the ADS5121
development kit for the Freescale MPC5121e SoC. When booting with a USB
flash disk connected there was a highly intermittent kernel panic where
an attempt was made to dereference an address containing 0x6b6b6b6b, the
SLUB poison marker.
Tracing the origin of the corruption was difficult as modifying the
kernel would often result in the corruption vanishing. Eventually it
was determined that the SCSI request pointer us->srb->request was being
corrupted from a valid value to 0x6b6b6b6b somewhere in the call to
us->proto_handler(us->srb, us) in usb_stor_control_thread()
(drivers/usb/storage/usb.c).
Further tracing revealed the corruption to be occuring when
invalidate_dcache_range() was called.
The address of us->srb->request was 0xCFAC81EC, while the parameters
passed to invalidate_dcache_range() were start=0xCFAC81F0 and
end=0xCFAC8202.
As these addresses are not on a cache-line boundary,
invalidate_dcache_range() actually invalidates from 0xCFAC81E0 to
0xCFAC82E0. This results in an uncommitted store at address 0xCFAC81EC
being discarded to be replaced with 0x6b6b6b6b from the SLUB poisoning
which had been committed to main memory.
Applying this patch also corrected random crashes observed when
connecting and disconnecting a ZD1121 Wireless LAN USB adapter.
dma-noncoherent.c | 11 +++++++++--
1 files changed, 9 insertions(+), 2 deletions(-)
diff -upNr linux-2.6.24.6/arch/powerpc/lib/dma-noncoherent.c wk-linux-2.6.24.6/arch/powerpc/lib/dma-noncoherent.c
--- linux-2.6.24.6/arch/powerpc/lib/dma-noncoherent.c 2008-05-02 05:50:00.000000000 +0800
+++ wk-linux-2.6.24.6/arch/powerpc/lib/dma-noncoherent.c 2008-06-25 15:11:25.000000000 +0800
@@ -348,8 +348,15 @@ void __dma_sync(void *vaddr, size_t size
switch (direction) {
case DMA_NONE:
BUG();
- case DMA_FROM_DEVICE: /* invalidate only */
- invalidate_dcache_range(start, end);
+ case DMA_FROM_DEVICE:
+ /*
+ * invalidate only when cache-line aligned otherwise there is
+ * the potential for discarding uncommitted data from the cache
+ */
+ if ((start & (L1_CACHE_BYTES - 1)) || (size & (L1_CACHE_BYTES - 1)))
+ flush_dcache_range(start, end);
+ else
+ invalidate_dcache_range(start, end);
break;
case DMA_TO_DEVICE: /* writeback only */
clean_dcache_range(start, end);
next reply other threads:[~2008-06-26 9:50 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-26 9:29 Andrew Lewis [this message]
2008-06-26 10:32 ` [PATCH/RFC] powerpc: prevent memory corruption due to cache invalidation of unaligned DMA buffer Gerhard Pircher
2008-06-26 10:55 ` Benjamin Herrenschmidt
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=48636161.6080603@netspace.net.au \
--to=andrew-lewis@netspace.net.au \
--cc=linuxppc-dev@ozlabs.org \
--cc=paulus@samba.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).