LINUX.ORG.RU

DMA для PCI в режиме Bus Master


0

0

Помогите плиз! Выделяю блок памяти в драйвере PCI устройства с помощью функций kmalloc() или pci_alloc_consistent(), далее проходит цикл DMA. Внутри ядра по адресам, возвращенным этими функциями данные читаю нормально. Далее не удаляя блок из памяти делаю mmap для него, с пометкой блока RESERVED и вызываю remap_page_range(), ошибок не происходит, но читаю из приложения одни нули... Помогите понять в чем проблема... karakozov@inbox.ru Спасибо.


при чем здесь dma и busmustering.

вы же читаете правильные даннные в kernel-space?
значит, у вас не работает mmap, с этим и разбирайтесь.
remap_page_range() c PageReserved должно работать.

если покажете код (упрощенный и отформатированный),
можно будет посмотреть.

в 2.6, кстати, можно делать DMA прямо в user-level
память процесса. см get_user_pages().

idle ★★★★★
()
Ответ на: комментарий от idle

С замечанием полностью согласен. Спасибо, что поправили. Мой код mmap выглядит так: int dev_mmap(struct file *filp, struct vm_area_struct *vma) { int x = 0; unsigned long offset = VMA_OFFSET(vma); vma->vm_flags |= VM_RESERVED;

if(offset >= __pa(high_memory) || (filep->f_flags & O_SYNC)) vma->vm_flags |= VM_IO;

x = remap_page_range( vma, vma->start, offset, vma->end-vma->vma_start, vma->vm_page_prot );

if(x < 0) { printk("<0> remap_page_range error.\n"); return x; }

return 0; }

Этот dev_mmap проецирует регистры устройства в приложение правильно. А вот с памятью, выделенной pci_alloc_consistent или kmalloc проблемы. Исходник вызова mmap приведу позже. Его сейчас нет по руками... :-) Спасибо.

karak
() автор топика
Ответ на: комментарий от karak

эх, ведь просил же отформатировать....

код неправильный целиком и полностью.

что такое VMA_OFFSET() ? вы передаете его remap_page_range()
там, где должен быть физический адрес памяти.

всем страницам (а не vma !!!), которые попадают в диапазон
физических адресов должен быть выставлен SetPageReserved().

вот эта проверка: if(offset >= __pa(high_memory) лишняя.

не выделяйте память с помощью kmalloc()! это неправильно
в данном случае. можно __get_free_pages().

не пользуйтесь pci_alloc_consistent() если 2.6, устарела.
dma_alloc_coherent().

может еще чего забыл, но читать это совершенно невозможно.
форматируйте!

idle ★★★★★
()
Ответ на: комментарий от idle

Сорри, но я не совсем понимаю, как его отформатировать. Может оставите E-mail, чтобы я вам прислал фрагменты, кода. Или пришлите мне свой E-mail на karakozov@inbox.ru. Ядро у меня 2.4.х. Спасибо...

karak
() автор топика
Ответ на: комментарий от karak

> Сорри, но я не совсем понимаю, как его отформатировать

я тоже долго не мог понять, как сделать.

внизу, выше кнопки 'Post/Поместить', выберите
'Preformatted text'.

imho, должно быть deafult.

idle ★★★★★
()
Ответ на: комментарий от idle

Не знаю получится или нет? Вот текст mmap, а внизу макрос VMA_OFFSET()
P. S. Что такое "imho"?

int dev_mmap(struct file *filp, struct vm_area_struct *vma )
{

	  int x = 0;
        unsigned long offset = VMA_OFFSET(vma);

        vma->vm_flags |= VM_RESERVED;

        if (offset >= __pa(high_memory) || (filp->f_flags & O_SYNC))
                vma->vm_flags |= VM_IO;

        x = remap_page_range(vma, vma->vm_start, offset,
                             vma->vm_end-vma->vm_start,
                             vma->vm_page_prot);

	if( x < 0) {
	  printk("<0>remap_page_range error.\n" );
          return x;
	}


	return 0;
}
//----------------------------------------------------------------
#ifdef LINUX_24 	
#define VMA_OFFSET(vma)  ((vma)->vm_pgoff << PAGE_SHIFT)
#else 			
#define VMA_OFFSET(vma)  ((vma)->vm_offset)
#endif

karak
() автор топика
Ответ на: комментарий от karak

похоже, тот же код, только отформатированный.

я же писал уже, что в нем неправильно?

или вы действительно хотите повторить /dev/mem?
тогда не удивляйтесь, что приложение будет читать
нули. я уже писал про PageReserved.

на этом форуме я уже дважды обьяснял, почему
не работает remap_page_range(). в одной нитке
очень подробно говорил про Reserved и т.д.
поищите.

idle ★★★★★
()
Ответ на: комментарий от idle

idle:
А почему нельзя использовать kmalloc для отображения в процесс и для использования при Bus Mastering. Ну разве что на машине больше 4 Гб ОЗУ и адрес страницы уползет за 32 бита... Опять же, есть же всякие широкие PCI, которые вполне могут адресовать за 32 бита.

Murr ★★
()
Ответ на: комментарий от Murr

А пардон, там про 128 Мб и более речь шла.
Ну тогда да, из slab столько можно и не вытянуть. :)

Ну тогда gfp и правда поможет товарищу :)

Murr ★★
()
Ответ на: комментарий от karak

karak:

К offset= VMA_OFFSET(...) надо бы прибавить базу в величине физического адреса куска памяти (если выделяете куском)

типа
init (...) {
 mybuf = kmalloc(BUFFER_SIZE);
 mybuf_phys = virt_to_phys(mybuf);
 mybuf_page = virt_to_page(mybuf);
}

xxx_mmap(...) {
...
unsigned long offset = mybuf_phys + VMA_OFFSET(vma);
vma->vm_flags |= VM_RESERVED;

for (i=0; i<BUFFER_SIZE>>PAGE_CACHE_SIZE; i++)
   SetPageReserved(mybuf_page+i);
...
remap_page_range(...);
...
}

Надеюсь не сильно налажался, бо линуксячьих исходников нет под рукой.

P.S. Ну или можно переписать на gfp, если и правда надо много памяти.

Murr ★★
()
Ответ на: комментарий от Murr

Murr:
> А почему нельзя использовать kmalloc для отображения
> в процесс и для использования при Bus Mastering.

на i386 можно, она вся когерентная и даже cache snooping
делает, даже dma_sync_xxx() можно не делать.

но вообще нельзя. мы можем получить от kmalloc() память,
в которую DMA невозможен, и у нас нет для нее dma_handle.
__pa() не достаточно. на всякий случай, GFP_DMA к DMA не
имеет отношения.

на самом деле, не совсем верно и экспортировать такую
память в user level. во первых, нам иногда нужно и
меньше страницы, тогда это сразу bug. во вторых, slab
может использовать page->flags для собственных нужд или
отладки. в частности, начиная с некоторого момента он
забрал себе page->lru без предупреждения. так что это
небезопасно.

собственно, slab не дает _никаких_ гарантий, что что-то
можно делать с struct page ассоциированной с выделенной
памятью.

хотя сейчас работать будет, не спорю.

idle ★★★★★
()
Ответ на: комментарий от idle

Спасибо за помощь. Проблема была решена с помощью SetPageReserved(), о необходимости вызова которой я не сразу понял. (Спутал с VM_RESERVED). 
Подскажите теперь как правильно освободить память, которую я пометил SetPageReserved()?

karak
() автор топика
Ответ на: комментарий от idle

Спасибо за помощь. Виртуально всем по баночке пивка... А будете в Серпухове, можно и реально...

karak
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.