Получить PFN с адреса DMA (dma_addr_t)? - PullRequest
1 голос
/ 21 января 2020

Я хотел бы получить PFN, связанный с блоком памяти, выделенным для dma_alloc_coherent для использования с устройством P CIe, как показано ниже:

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.

1 Ответ

2 голосов
/ 22 января 2020

То, что вы делаете, действительно неправильно. Со страницы руководства для 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(), а не buffer, поскольку вам, очевидно, нужно пройти DMA адрес (dma_addr_t) этой функции, а не виртуальный адрес.

Кажется также, что есть макрос PHYS_PFN(), определенный в include/linux/pfn.h для получения PFN для данного физического адрес, если вы предпочитаете использовать это:

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