dma_alloc_coherent在x86_64上失败但在i686上运行

时间:2016-02-15 15:16:39

标签: linux-kernel driver x86-64 dma

我有一个pci设备驱动程序,它使用CMA分配机制进行DMA分配。它在32位模式下在内核3.18上工作正常但是当我尝试在64内核中使用它时(与32位相同的配置,但在64位模式下切换)dma分配失败。

我在dmesg中看到的只有:

 fallback device: swiotlb buffer is full (sz: 8388608 bytes)

我使用内核cmdline:

swiotlb=16384 iommu=soft cma=256M

并分配8Mb。

函数调用是:

new_region->kaddr = dma_alloc_coherent( NULL, size, &new_region->paddr, GFP_KERNEL | GFP_DMA32 );

有人可以用64位模式解释这种行为吗?

1 个答案:

答案 0 :(得分:2)

经过更多调查,我认为你可能和我有同样的根源,只是列出来供你参考。 CMA分配将从最高内存块开始,因此如果你有更多的3G内存,最后一个物理内存将高于0xFFFFFFFF,这意味着CMA的基地址高于4GB,但dma_allocat_coherent()要求地址低于掩码[(0x1<< 32)-1] = 0xFFFFFFFF,如果同步的dma结束地址大于0xFFFFFFFF,它将回退到swiotlb缓冲区,然后你会看到你描述的错误。请看下面的内存映射,最后2G是4GB以上的内存空间。

要解决此问题,我们可以指定cma起始地址,大小和限制大小以手动控制CMA保留位置。

e820: BIOS-provided physical RAM map:
BIOS-e820: [mem 0x0000000000000000-0x000000000009ffff] usable
BIOS-e820: [mem 0x00000000000a0000-0x00000000000fffff] reserved
BIOS-e820: [mem 0x0000000000100000-0x00000000779c4fff] usable
BIOS-e820: [mem 0x00000000779c5000-0x0000000077a45fff] reserved
BIOS-e820: [mem 0x0000000077a46000-0x0000000079426fff] usable
BIOS-e820: [mem 0x0000000079427000-0x000000007b32efff] reserved
BIOS-e820: [mem 0x000000007b32f000-0x000000007b985fff] ACPI NVS
BIOS-e820: [mem 0x000000007b986000-0x000000007bad3fff] ACPI data
BIOS-e820: [mem 0x000000007bad4000-0x000000007bafffff] usable
BIOS-e820: [mem 0x000000007bb00000-0x000000008fffffff] reserved
BIOS-e820: [mem 0x00000000fed1c000-0x00000000fed1ffff] reserved
BIOS-e820: [mem 0x0000000100000000-0x000000017fffffff] usable

cma=nn[MG]@[start[MG][-end[MG]]]
            [ARM,X86,KNL]
            Sets the size of kernel global memory area for
            contiguous memory allocations and optionally the
            placement constraint by the physical address range of
            memory allocations. A value of 0 disables CMA
            altogether. For more information, see
            include/linux/dma-contiguous.h

首先为您提供解决方法,请在内核中添加“mem = 3072M”  命令行。然后它将适用于您的情况。你之所以看到  这可能与传递给函数的NULL有关  dma_alloc_coherent()。它默认使用x86_dma_fallback_dev。  一旦我获得更多信息,将会更新。