Get PFN from DMA address (dma_addr_t)?

£可爱£侵袭症+ 提交于 2020-01-24 19:31:08

问题


I would like to get the PFN associated with a memory block allocated with dma_alloc_coherent for use with a PCIe device as shown below:

unsigned long pfn;

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

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

I'm aware that this is probably not the correct method, but it seems to work... I'm just looking for the right solution to translate the potential bus address (since I do not know if there is an IOMMU) to a PFN. Thanks in advance.

Note: There seems to be an ARM function in the kernel called dma_to_pfn, which seems to be exactly what I need, but for x86.


回答1:


What you're doing is indeed wrong. From the man page for 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.

The equivalent function for DMA addresses is dma_to_phys(), defined in include/linux/dma-direct.h as follows:

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

Therefore you can do:

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

Notice that I am using the bus_addr returned by dma_alloc_coherent(), not buffer, since you obviously need to pass a DMA address (dma_addr_t) to this function, not a virtual address.

There also seems to be a macro PHYS_PFN() defined in include/linux/pfn.h to get the PFN for a given physical address, if you prefer to use that:

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


来源:https://stackoverflow.com/questions/59847162/get-pfn-from-dma-address-dma-addr-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!