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.
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));