【发布时间】:2015-04-20 06:27:15
【问题描述】:
假设我有一些物理地址(这是我的 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)
我需要进一步调查。
【问题讨论】:
-
物理地址不一定与 DMA 地址相同。无论如何,
dma_map_single()应该可以工作。为什么驱动程序无法访问其设备的资源?
标签: c linux memory-management linux-kernel dma