ARM coherent allocs, Was: ixp4xx eth broken in 3.7.0/3.8-rc5?
Mikael Pettersson
mikpe at it.uu.se
Mon Feb 18 04:08:53 EST 2013
Krzysztof Halasa writes:
> Hi,
>
> I'm not sure how is it supposed to work. Environment: IXP4xx CPU,
> only 64 MB (of 256 MB) of RAM is available for PCI bus master DMA,
> /dev/sda is a PATA CF or SATA SSD using CS5536-based PATA interface
> (SATA - with a bridge) in DMA (PCI bus master) mode.
>
> It works in PIO mode.
> The problem seems to be this: pci_dev->dev.coherent_dma_mask is 0x3FFFFFF
> (64MB-1). Yet __dma_alloc() called with GFP_DMA returns memory
> physically located (dma_handle) above 64MB region.
Isn't that what the ARM-specific dma bounce allocator is supposed to
handle? Or did e9da6e9905e639b0f842a244bc770b48ad0523e9 disable that one?
My ixp4xx box only has 64MB RAM so there is never any bouncing there,
in fact I patch my kernel to disable the bounce support entirely.
/Mikael
>
> Bisecting shows this commit broke it:
>
> > I haven't yet tried the Ethernet driver but it seems my IXP425 box
> > doesn't like this while mounting a disk (PCI CS3356-based IDE CF card).
> >
> > commit e9da6e9905e639b0f842a244bc770b48ad0523e9
> > Author: Marek Szyprowski <m.szyprowski at samsung.com>
> > Date: Mon Jul 30 09:11:33 2012 +0200
> >
> > ARM: dma-mapping: remove custom consistent dma region
> >
> > This patch changes dma-mapping subsystem to use generic vmalloc areas
> > for all consistent dma allocations. This increases the total size limit
> > of the consistent allocations and removes platform hacks and a lot of
> > duplicated code.
> >
> > Atomic allocations are served from special pool preallocated on boot,
> > because vmalloc areas cannot be reliably created in atomic context.
>
> I'm trying to understand it (current code as of v3.8rc-7):
>
> static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
> gfp_t gfp, pgprot_t prot, bool is_coherent, const void *caller)
> {
> u64 mask = get_coherent_dma_mask(dev);
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This gets 64MB - 1
> struct page *page = NULL;
> void *addr;
>
> #ifdef CONFIG_DMA_API_DEBUG
> u64 limit = (mask + 1) & ~mask;
> if (limit && size >= limit) {
> dev_warn(dev, "coherent allocation too big (requested %#x mask %#llx)\n",
> size, mask);
> return NULL;
> }
> #endif
>
> if (!mask)
> return NULL;
>
> if (mask < 0xffffffffULL)
> gfp |= GFP_DMA;
>
> /*
> * Following is a work-around (a.k.a. hack) to prevent pages
> * with __GFP_COMP being passed to split_page() which cannot
> * handle them. The real problem is that this flag probably
> * should be 0 on ARM as it is not supported on this
> * platform; see CONFIG_HUGETLBFS.
> */
> gfp &= ~(__GFP_COMP);
>
> *handle = DMA_ERROR_CODE;
> size = PAGE_ALIGN(size);
>
> if (is_coherent || nommu())
> addr = __alloc_simple_buffer(dev, size, gfp, &page);
> else if (!(gfp & __GFP_WAIT))
> addr = __alloc_from_pool(size, &page);
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> else ...
>
> Is the pool supposed to live in GFP_DMA area or should we use more
> pools? We call __alloc_from_pool() but it knows nothing about our
> device's coherent_dma_mask or GFP flags.
> --
> Krzysztof Halasa
>
More information about the linux-arm-kernel
mailing list