dma_alloc_coherent () и физические адреса

В документе DMA-API-HOWTO говорится, что dma_alloc_coherent () возвращает два значения: виртуальный адрес, который вы можете использовать для доступа к нему из ЦП, и dma_handle, который вы передаете карте.

Разве виртуальный адрес и dma_handle не должны отображаться на один и тот же физический адрес? Это не то, что я вижу.

Ожидается ли, что dma_handle совпадает с его физическим адресом?

Я использую систему x86_64 с включенным IOMMU. Операционная система - Ubuntu 18.04, а ядро ​​- 4.15.0-47-generic.

Мой код:

ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));

dmabuffp = dma_alloc_coherent (dev_ptr, (size_t)4*1024*1024, &dma_hndl, GFP_KERNEL | GFP_DMA);

printk(KERN_INFO "init: dma_hndl = 0x%llX\n", dma_hndl);<br />
printk(KERN_INFO "init: dmabuffp VA = 0x%llX\n", (uint64_t)dmabuffp);<br />
printk(KERN_INFO "init: dma_hndl VA = 0x%llX\n", (uint64_t)bus_to_virt(dma_hndl));

printk(KERN_INFO "init: dmabuffp PA = 0x%010llX\n", (uint64_t)virt_to_phys(dmabuffp));<br />
printk(KERN_INFO "init: dma_hndl PA = 0x%010llX\n",(uint64_t)virt_to_phys(bus_to_virt(dma_hndl)));

После загрузки модуля dmesg показывает это:

init: dma_hndl = 0xFFC00000<br />
init: dmabuffp VA = 0xFFFF888E9B000000<br />
init: dma_hndl VA = 0xFFFF88873FC00000<br />
init: dmabuffp PA = 0x085B000000<br />
init: dma_hndl PA = 0x00FFC00000

Устройство может писать и читать, используя dma_hndl, но значение его пишет не в * buffptr.

Что я пропускаю и / или делаю неправильно?

2
задан 2 May 2019 в 21:39

2 ответа

Дополнительное тестирование показывает, что dma_hndl сопоставляется с тем же физическим адресом, что и dmabuffp. По-видимому, virt_to_phys(bus_to_virt(dma_hndl)) не разрешается должным образом и вместо этого является круглым, возвращая исходное значение dma_hndl вместо физического адреса, который отображается IOMMU.

0
ответ дан 2 May 2019 в 21:39

dma_addr_t - это Виртуальный адрес ввода-вывода (IOVA) - это адрес, который устройство использует для доступа к буферу, возвращаемому dma_alloc_coherent .

void * dma_alloc_coherent(struct device *dev, 
                          size_t size, 
                          dma_addr_t *dma_handle, 
                          gfp_t flag)

Причина dma_addr_t не такая же, как virt_to_phys (dmabuffp) , потому что IOMMU включен.

Только устройство использует dma_addr_t для доступа DMA. Для доступа к процессору необходимо использовать возвращенный void * или какую-то его версию virt_to_phys () , чтобы пользовательское пространство могло отображать его через devmem.

Без IOMMU dma_addr_t представляет собой просто virt_to_phy () / virt_to_bus () перевод буфера void * , поэтому его можно использовать для прямого доступа к процессору, но это неправильное использование DMA API.

0
ответ дан 3 December 2019 в 10:54

Другие вопросы по тегам:

Похожие вопросы: