【问题标题】:Get PFN from DMA address (dma_addr_t)?从 DMA 地址 (dma_addr_t) 获取 PFN?
【发布时间】:2020-01-21 18:30:10
【问题描述】:

我想获取与分配有dma_alloc_coherent 的内存块相关联的 PFN,以便与 PCIe 设备一起使用,如下所示:

unsigned long pfn;

buffer = dma_alloc_coherent(&pcie->dev, size, &bus_addr, GFP_KERNEL);

// Get PFN?
virt_to_phys(buffer) >> PAGE_SHIFT;

我知道这可能不是正确的方法,但它似乎有效......我只是在寻找正确的解决方案来转换潜在的总线地址(因为我不知道是否有 IOMMU ) 到 PFN。提前致谢。

注意:内核中似乎有一个名为 dma_to_pfn 的 ARM 函数,这似乎正是我需要的,但对于 x86。

【问题讨论】:

  • 我认为正确的方法是通过 PFN 遍历并比较必要的信息。我可以问你为什么需要那个吗?是的,IOMMU 可能会做一些有趣的事情,而这些事情不允许你做上述事情(例如,在使用反弹缓冲区时)。

标签: linux-kernel linux-device-driver


【解决方案1】:

你所做的确实是错误的。来自virt_to_phys() 的手册页:

此函数不提供 DMA 传输的总线映射。在几乎所有可以想象的情况下,设备驱动程序都不应该使用这个函数。

DMA地址的等效函数是dma_to_phys(),在include/linux/dma-direct.h中定义如下:

phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);

因此你可以这样做:

dma_to_phys(&pcie->dev, bus_addr) >> PAGE_SHIFT;

请注意,我使用的是 dma_alloc_coherent() 返回的 bus_addr,而不是 buffer,因为您显然需要将 DMA 地址 (dma_addr_t) 传递给此函数,而不是虚拟地址。

include/linux/pfn.h 中似乎还定义了一个宏 PHYS_PFN() 来获取给定物理地址的 PFN,如果您更喜欢使用它:

PHYS_PFN(dma_to_phys(&pcie->dev, bus_addr));

【讨论】:

    猜你喜欢
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多