Re: swiotlb_alloc_coherent: allocated memory is out of range for device

From: Takashi Iwai
Date: Wed Oct 22 2008 - 07:08:08 EST


At Wed, 22 Oct 2008 12:53:58 +0200,
I wrote:
>
> At Sun, 19 Oct 2008 12:09:32 +0200,
> Sven Schnelle wrote:
> >
> > Hi List,
> >
> > my kernel dies while probing parport with the following last words:
> >
> > [ 3.672199] parport_pc 00:0b: reported by Plug and Play ACPI
> > [ 3.677969] parport0: PC-style at 0x378 (0x778), irq 7, dma 3 [PCSPP,TRISTATE,COMPAT,EPP,ECP,DMA]
> > [ 3.687691] hwdev DMA mask = 0x0000000000ffffff, dev_addr = 0x0000000020000000
> > [ 3.694916] Kernel panic - not syncing: swiotlb_alloc_coherent: allocated memory is out of range for device
> >
> > I haven't started a bisection yet, but this seems to be introduced
> > somewhere between 2.6.26 and 2.6.27, at least 2.6.26 was working without
> > problems. The dmesg log + config was obtained from a kernel compiled
> > from git on 10/16/2008.
>
> This bug hits me, too. Looks like swiotlb assumes that the alloc caller
> must set GFP_DMA appropriately by itself since GFP_DMA hack was
> removed. The patch below should fix this particular case.
>
> HOWEVER: the fundamental problem appears to be in swiotlb itself.
> It assumes that iotlb pages are in DMA area. But, in this case, the
> driver sets 24bit DMA (as of PnP) while iotlb pages are allocated
> under 32bit DMA via alloc_bootmem_low_pages(). This doesn't work, of
> course.
>
> So, even adding GFP_DMA works mostly, it has still potentially
> breakage when you can't get the page and fall back to iotlb pages,
> just like the panic above.
>
> Also, the removal of GFP_DMA hack is a bad idea. For example, if a
> device requires 28bit DMA mask, it doesn't set always GFP_DMA for
> allocation because pages in ZONE_NORMAL may be inside that DMA mask.
> Normal allocators allow this behavior but swiotlb allocator doesn't.
> (Correct me if I'm wrong here -- I haven't followed much the recent
> changes.)

The patch below is to a workaround for that.


Takashi

diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index f8eebd4..cb20149 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -468,6 +468,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
void *ret;
int order = get_order(size);

+ again:
ret = (void *)__get_free_pages(flags, order);
if (ret && address_needs_mapping(hwdev, virt_to_bus(ret), size)) {
/*
@@ -478,6 +479,10 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
ret = NULL;
}
if (!ret) {
+ if (!(flags & __GFP_DMA)) {
+ flags |= __GFP_DMA;
+ goto again;
+ }
/*
* We are either out of memory or the device can't DMA
* to GFP_DMA memory; fall back on
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/