public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* PCI DMA to small buffers on cache-incoherent arch
@ 2002-06-08 20:38 Roland Dreier
  2002-06-08 13:58 ` Anton Blanchard
  2002-06-08 23:03 ` David S. Miller
  0 siblings, 2 replies; 99+ messages in thread
From: Roland Dreier @ 2002-06-08 20:38 UTC (permalink / raw)
  To: linux-kernel

I recently fixed some problems in the 2.4 USB stack that caused
crashes on the PowerPC 440GP (and probably other cache-incoherent
architectures).  However, some parts of my fix have raised some
questions on the linux-usb-devel and linuxppc-embedded mailing lists
and I would like to raise these issues here so that we can get a
definitive answer.  I would especially appreciate comments from David
Miller and other PCI DMA experts.

The problem that caused crashes on cache-incoherent architectures (my
specific system uses a PPC 440GP but this should apply in general) was
the following.  The USB stack was doing PCI DMA into buffers that were
allocated on the stack, which causes stack corruption: on the PPC
440GP, pci_map_single() with PCI_DMA_FROMDEVICE just invalidates the
cache for the region being mapped.  However, if a buffer is smaller
than a cache line, then two bad things can happen.

First, there may be valid data outside the buffer but in the same
cache line that has not been flushed to main memory yet.  In that case
when the cache is invalidated the new data is lost and any access to
that memory will get the old data from main memory.  Second, access to
the cache line after the cache has been invalidated but before the DMA
has completed will pull the cache line back into processor cache and
the DMA buffer will have invalid data.

The solution to this was simply to use kmalloc() to allocate buffers
instead of using automatic variables.  On the PPC 440GP this is
definitely safe because the 440GP's has 32 byte cache lines and
kmalloc() will never return a buffer that is smaller than 32 bytes or
not 32-byte aligned.  However, this leads to my first question: is
this safe on all architectures?  Could there be a cache-incoherent
architecture where kmalloc() returned a buffer smaller than a cache
line?

The second question is related to this.  There are other parts of the
USB stack where structures are defined:

	struct something {
	        /* ... some members ... */
	        char buffer[SMALLER_THAN_L1_CACHE_LINE_SIZE];
	        /* ... some more members ... */
	};

Then a struct something is kmalloc()'ed and buffer is used to DMA
into.  However, even though the overall structure is aligned on a
cache line boundary, buffer is not aligned.  It seems to me that this
is not safe because access to members near buffer during a DMA could
cause corruption (as detailed above).  In my patch I changed code like
this to look like

	struct something {
	        /* ... some members ... */
	        char *buffer;
	        /* ... some more members ... */
	};

and then kmalloc()'ed buffer separately when kmalloc()'ing a struct
something.

However, there is some question about whether changing these buffers
is really necessary.  Code like the above doesn't cause immediately
obvious crashes the way buffers on the stack do (since we usually get
lucky and don't touch the members near buffer around the DMA access).
I felt that relying on this coincidence is not safe and should be
fixed at the same time.

DMA-mapping.txt says kmalloc()'ed memory is OK for DMAs and does not
mention cache alignment.  So the question is: did I misunderstand the
cache coherency issues or is my patch correct?  At a higher level: how
is this supposed to work?  Should code doing DMA into a smallish
buffer do

        buffer = kmalloc(max(BUFFER_SIZE, L1_CACHE_BYTES), GFP_XXX);

or is a kmalloc()'ed buffer always safe?  Does the code doing DMA need
to worry about the cache alignment of its buffer?

In any case this probably needs to be documented better.  Once I
understand the answer I'll write up a patch to DMA-mapping.txt so no
one has to rediscover all this.

Thanks,
  Roland

^ permalink raw reply	[flat|nested] 99+ messages in thread
* Re: PCI DMA to small buffers on cache-incoherent arch
@ 2002-06-11  5:31 David Brownell
  2002-06-11  5:44 ` David S. Miller
  0 siblings, 1 reply; 99+ messages in thread
From: David Brownell @ 2002-06-11  5:31 UTC (permalink / raw)
  To: David S. Miller; +Cc: linux-kernel

> From: Roland Dreier <roland@topspin.com>
> Date: 10 Jun 2002 21:39:27 -0700
> 
>        David> How about allocating struct something using pci_pool?
>    
>    The problem is the driver can't safely touch field1 or field2 near the
>    DMA (it might pull the cache line back in too soon, or dirty the cache
>    line and have it written back on top of DMA'ed data)
> 
> Oh duh, I see, then go to making the thing a pointer to the
> dma area.

If it's going to be a pointer, it might as well be normal kmalloc data,
avoiding obfuscation of the memory model used by USB device drivers.
(They don't have to worry about DMA addresses, which IMO is a feature.)

Seems like there are two basic options for how to handle all this.

(a) Expose the dma/cache interaction to device drivers, so
     they can manage (and prevent) bad ones like the cacheline
     sharing scenarios.

(b) Require drivers to provide I/O buffers that are slab/page/...
     pointers from some API that prevents such problems.

I think (a) is more or less a variant of the existing alignment
requirements that get embedded in ABIs, but which still show up
in code that's very close to the hardware.  Many device driver
folk are familiar with them, or performance tuners, but not so
many folk doing USB device drivers would be.  (They are thankfully
far from host controller hardware and its quirks!)

Personally I'd avoid (b) since I like to allocate memory all at
once in most cases ... lots fewer error cases to cope with (or,
more typically _not_ cope with :).

One question is whether to support only one of them, or allow both.
In either case the DMA-mapping.txt will need to touch on the issue.

- Dave





^ permalink raw reply	[flat|nested] 99+ messages in thread

end of thread, other threads:[~2002-06-14  4:46 UTC | newest]

Thread overview: 99+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-06-08 20:38 PCI DMA to small buffers on cache-incoherent arch Roland Dreier
2002-06-08 13:58 ` Anton Blanchard
2002-06-09  0:52   ` Roland Dreier
2002-06-08 23:03 ` David S. Miller
2002-06-09  0:40   ` Roland Dreier
2002-06-09  0:53     ` David S. Miller
2002-06-09  1:26       ` Roland Dreier
2002-06-09  5:29         ` David S. Miller
2002-06-09  6:16           ` Roland Dreier
2002-06-10 16:03             ` Roland Dreier
2002-06-11 14:04               ` David Woodhouse
2002-06-09  6:45           ` Oliver Neukum
2002-06-10  4:24             ` David S. Miller
2002-06-10 10:00               ` Oliver Neukum
2002-06-10 10:24                 ` David S. Miller
2002-06-09  9:51           ` Paul Mackerras
2002-06-09 10:54             ` Benjamin Herrenschmidt
2002-06-10  4:27             ` David S. Miller
2002-06-10 15:59               ` Roland Dreier
2002-06-10 17:03                 ` Tom Rini
2002-06-10 17:22                   ` Oliver Neukum
2002-06-10 17:29                     ` Tom Rini
2002-06-10 17:39                       ` Oliver Neukum
2002-06-10 19:03                       ` Roland Dreier
2002-06-10 19:14                         ` Tom Rini
2002-06-10 19:21                           ` Roland Dreier
2002-06-10 19:26                             ` Tom Rini
2002-06-10 17:57                     ` Russell King
2002-06-10 17:28                   ` Roland Dreier
2002-06-10 18:07               ` William Jhun
2002-06-10 18:29                 ` William Jhun
2002-06-10 18:33                 ` Mark Zealey
2002-06-10 18:44                   ` Oliver Neukum
2002-06-11  3:10                 ` David S. Miller
2002-06-11  4:04                   ` Roland Dreier
2002-06-11  4:16                     ` Brad Hards
2002-06-11  4:24                       ` Roland Dreier
2002-06-11  4:24                         ` David S. Miller
2002-06-11  4:21                     ` David S. Miller
2002-06-11  4:39                       ` Roland Dreier
2002-06-11  4:38                         ` David S. Miller
2002-06-11  6:23                           ` Oliver Neukum
2002-06-11  6:38                             ` David S. Miller
2002-06-11  7:38                               ` Oliver Neukum
2002-06-11  7:36                                 ` David S. Miller
2002-06-11  7:43                                   ` David S. Miller
2002-06-11  8:07                                     ` Oliver Neukum
2002-06-11  8:15                                       ` David S. Miller
2002-06-11 12:06                                         ` Oliver Neukum
2002-06-11 12:04                                           ` David S. Miller
2002-06-11 14:23                                             ` Oliver Neukum
2002-06-14  4:14                                               ` David S. Miller
2002-06-11 18:26                                             ` Roland Dreier
2002-06-11 17:29                                               ` Benjamin Herrenschmidt
2002-06-12 12:02                                                 ` Oliver Neukum
2002-06-11 20:06                                                   ` Benjamin Herrenschmidt
2002-06-12 12:02                                                   ` David S. Miller
2002-06-11 23:00                                               ` Thunder from the hill
2002-06-11 23:56                                                 ` Roland Dreier
2002-06-12  0:09                                                   ` Thunder from the hill
2002-06-11 15:57                                     ` William Jhun
2002-06-12  9:06                                     ` Pavel Machek
2002-06-12 20:16                                       ` David S. Miller
2002-06-12 11:47                 ` David S. Miller
2002-06-12 12:08                   ` Oliver Neukum
2002-06-14  4:41                     ` David S. Miller
2002-06-12 16:09                   ` William Jhun
2002-06-09  1:30   ` Albert D. Cahalan
2002-06-09  5:29     ` David S. Miller
2002-06-09  6:33       ` Albert D. Cahalan
2002-06-09  6:50         ` Oliver Neukum
2002-06-09  6:57           ` Albert D. Cahalan
2002-06-09  7:15             ` Oliver Neukum
2002-06-09  8:48         ` Russell King
2002-06-09 15:42           ` Albert D. Cahalan
2002-06-09 23:26           ` Oliver Neukum
  -- strict thread matches above, loose matches on Subject: below --
2002-06-11  5:31 David Brownell
2002-06-11  5:44 ` David S. Miller
2002-06-11 15:12   ` David Brownell
2002-06-11 15:44     ` Oliver Neukum
2002-06-12  3:25     ` David S. Miller
2002-06-11 17:33       ` Benjamin Herrenschmidt
2002-06-12  9:42         ` David S. Miller
2002-06-12 14:14           ` David Brownell
2002-06-12 15:00             ` Benjamin Herrenschmidt
2002-06-12 18:44             ` Roland Dreier
2002-06-12 19:13               ` David Brownell
2002-06-12 19:58                 ` Oliver Neukum
2002-06-12 22:51                   ` David S. Miller
2002-06-12 23:17                     ` Oliver Neukum
2002-06-13  4:57                   ` David Brownell
2002-06-12 22:46                 ` David S. Miller
2002-06-13  5:13                   ` David Brownell
2002-06-13  9:38                     ` David S. Miller
2002-06-12 22:50                 ` David S. Miller
2002-06-12  6:25       ` David Brownell
2002-06-12  6:24         ` David S. Miller
2002-06-12  7:06           ` David Brownell
2002-06-12  9:22             ` David S. Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox