linux-kernel - 从 DMA 地址 (dma_addr_t) 获取 PFN?
问题描述
我想获得与分配dma_alloc_coherent
用于 PCIe 设备的内存块相关联的 PFN,如下所示:
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()
:
此函数不提供 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;
请注意,我使用的是bus_addr
返回的dma_alloc_coherent()
, not buffer
,因为您显然需要将 DMA 地址 ( dma_addr_t
) 传递给此函数,而不是虚拟地址。
如果您更喜欢使用它,似乎还PHYS_PFN()
定义了一个宏include/linux/pfn.h
来获取给定物理地址的 PFN:
PHYS_PFN(dma_to_phys(&pcie->dev, bus_addr));
推荐阅读
- angularjs - 当后台浏览器选项卡时,Angular / AngularJS升级应用程序无响应
- reactjs - Firebase 数据库抛出“错误:Reference.set 失败”
- c++ - 在 ANTLR4 的 Lexer 中切换流
- javascript - 如何在网站中更改 google vr 全屏图标的背景
- .net - 如何抑制我的事件处理函数发出不需要的文本?
- azure - Azure AD B2C 来宾用户无法登录
- visual-studio - 如何使用 .net 安装程序文件
- database - DBMS 在 POSIX 或类 UNIX 操作系统中的 ACIDity
- c# - 无法使用 C# 连接到 MySQL 服务器,但使用 Workbench 没有问题
- c# - 我需要这个 C# 代码的 Swift 代码