2015-02-19 6 views
2

Скажем, у меня есть некоторый физический адрес (это автобус расположение моего источника DMA периферийный):Linux: как определить адрес DMA, соответствующий что вернулся из ioremap

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 непосредственно в качестве исходного адреса DMA на device_prep_dma_memcpy, все работает отлично - но опять я не могу этого сделать, потому что у меня нет прямого доступа к нему. Единственный возможный способ получить его - это ходить по страницам страниц ядра ... Я действительно не хочу, чтобы это делать вручную. Есть ли способ лучше?

UPDATE

struct page *kmap_to_page(void * vaddr) 

выглядит многообещающим. Я не уверен, что виртуальные адреса, возвращенные с ioremap, будут работать с этим. Другая возможность:

struct page* vmalloc_to_page(void* vmalloc_addr) 

Мне нужно дополнительно исследовать.

+2

Физические адреса не обязательно совпадают с адресами DMA. Во всяком случае, 'dma_map_single()' должен работать. И почему драйвер не имеет доступа к ресурсам своего устройства? –

ответ

0

Похоже, что vmalloc_to_page был тем, что я искал. Если я:

phys_addr = page_to_phys(vmalloc_to_page(virt_addr))) 

это дает, phys_addr == 0xffff0000. .

После CL консультируют я пытался делать все следующее:

wrong_phy_addr1 = dma_map_single(dev, 0xffff0000, size, DMA_FROM_DEVICE); 
wrong_phy_addr2 = dma_map_single(dev, virt_addr, size, DMA_FROM_DEVICE); 
correct_phy_addr = phys_to_dma(dev, 0xffff0000); 

После запуска этого я получаю:

wrong_phy_addr1 == 7fff0000 
wrong_phy_addr2 == 4091e000 
correct_phy_addr == ffff0000 

Таким образом, это выглядит, как phys_to_dma() побеждает здесь. Использование этого метода предпочтительнее использования необработанного физического адреса, потому что (как предложено CL) физические адреса не обязательно являются адресами DMA. На моей доске они просто бывают одинаковыми.

В заключение, это ответ на мой первоначальный вопрос:

dma_addr = phys_to_dma(dev, page_to_phys(vmalloc_to_page(virt_addr)); 

Это, как говорится, это дополнительный поиск дорого и можно было бы избежать, если phys_addr (0xffff0000) были доступны для моего водителя - - Я изучу изменение интерфейса.

Прежде чем принять свой собственный ответ, я дам другим время, чтобы предоставить свои (лучше?) Ответы.

+0

Я блуждаю, почему dma_map_single (dev, virt_addr, размер, DMA_FROM_DEVICE) не работает. , может быть, это должно быть DMA_TO_DEVICE? – ransh