从 DMA 地址 (dma_addr_t) 获取 PFN?
Get PFN from DMA address (dma_addr_t)?
我想获取与分配给 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。提前致谢。
注意:内核中似乎有一个ARM函数叫做dma_to_pfn
,这似乎正是我所需要的,但是对于x86。
你这样做确实是错误的。来自 virt_to_phys()
的手册页:
This function does not give bus mappings for DMA transfers. In almost all conceivable cases a device driver should not be using this function.
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));
我想获取与分配给 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。提前致谢。
注意:内核中似乎有一个ARM函数叫做dma_to_pfn
,这似乎正是我所需要的,但是对于x86。
你这样做确实是错误的。来自 virt_to_phys()
的手册页:
This function does not give bus mappings for DMA transfers. In almost all conceivable cases a device driver should not be using this function.
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));