gpt4 book ai didi

c - Linux:如何确定与 ioremap 返回的内容对应的 DMA 地址

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:08:23 29 4
gpt4 key购买 nike

假设我有一些物理地址(这是我的 DMA 源外设的总线位置):

phys_addr = 0xffff0000;

我这样做:

virt_addr = ioremap(phys_addr, PAGE_SIZE);

在这样做之后,我不再直接访问 phys_addr(在我的例子中,我没有访问权限,因为我正在编写的驱动程序只通过了 virt_addr) .

我第一次失败的尝试:

wrong_phys_addr = virt_to_dma(dev,virt_addr);

顺便说一句,我不知道为什么设备 dev 在这个查找中是相关的......

这当然是行不通的,因为 virt_addr 不是直接映射的内核内存。 DMA-API似乎暗示所有类似 virt_to_bus 的翻译都已弃用,每个人都应该使用 dma_map_single 等来获取 DMA 总线地址。所以我接下来尝试了这个:

wrong_phys_addr = dma_map_single(dev, virt_addr, size, DMA_FROM_DEVICE);

同样,这仍然不起作用。当然,如果我直接使用 0xffff0000 作为 device_prep_dma_memcpy 的源 DMA 地址,一切都很好——但我还是不能这样做,因为我无法直接访问它。我能想到的获得它的唯一可能方法是遍历内核的页表……我真的不想手动执行此操作。有没有更好的办法?

更新

struct page *kmap_to_page(void * vaddr)

看起来很有前途。我不确定从 ioremap 返回的虚拟地址是否适用于此。另一种可能是

struct page* vmalloc_to_page(void* vmalloc_addr)

我需要进一步调查。

最佳答案

看起来 vmalloc_to_page 正是我要找的。如果我这样做:

phys_addr = page_to_phys(vmalloc_to_page(virt_addr)))

这会产生,phys_addr == 0xffff0000

按照 CL. 的建议,我还尝试执行以下所有操作:

wrong_phy_addr1 = dma_map_single(dev, 0xffff0000, size, DMA_FROM_DEVICE);
wrong_phy_addr2 = dma_map_single(dev, virt_addr, size, DMA_FROM_DEVICE);
correct_phy_addr = phys_to_dma(dev, 0xffff0000);

运行后我得到:

wrong_phy_addr1 == 7fff0000
wrong_phy_addr2 == 4091e000
correct_phy_addr == ffff0000

因此,看起来 phys_to_dma() 在这里胜出。使用此方法比使用原始物理地址更可取,因为(如 CL. 建议的那样)物理地址不一定是 DMA 地址——在我的板上它们恰好是相同的。

总而言之,这是我最初问题的答案:

dma_addr = phys_to_dma(dev, page_to_phys(vmalloc_to_page(virt_addr));

话虽这么说,但如果 phys_addr (0xffff0000) 对我的驱动程序可用,则这种额外的查找成本很高,可以避免——我会考虑更改接口(interface)。

在接受我自己的答案之前,我会给其他人一些时间来提供他们自己的(更好的?)答案。

关于c - Linux:如何确定与 ioremap 返回的内容对应的 DMA 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28597417/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com