Hello, I am trying to make a DMA transfer from userspace. My code looks like this (data.vi_buf is a pointer to the userspace address): down_read(¤t->mm->mmap_sem); rc = get_user_pages(current, current->mm, (unsigned long) data.vi_buf, 1, 1, 0, &acq_dev->vi_pg, NULL); up_read(¤t->mm->mmap_sem); if (rc != 1) { err("get_user_pages failed for VI."); return -EINVAL; } acq_dev->vi_d = dma_map_page(dev, acq_dev->vi_pg, 0, PAGE_SIZE, DMA_TO_DEVICE); if (acq_dev->vi_d == 0) { err("dma_map_page failed for VI."); goto cleanup_vi_2; } info("VI bus address: 0x%0lx", (unsigned long) acq_dev->vi_d); But when my PCI device then reads data from the bus address acq_dev->vi_d, it just gets \0 bytes rather then the contents of the acq_dev->userspace buffer. I tried to debug this with an additional info("VI Start: 0x%0x", ((uint32_t*) page_address(acq_dev->vi_pg))[0]); to print out the first byte of the mapped page, but this actually results in a kernel crash: BUG: unable to handle kernel NULL pointer dereference at (null) Can anyone tell why my debugging idea does not work? And does anyone have a suggestion how I could better debug my original problem? Thanks, -Nikolaus -- »Time flies like an arrow, fruit flies like a Banana.« PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
Nikolaus Rath <Nikolaus@rath.org> writes:
Hello,
I am trying to make a DMA transfer from userspace. My code looks like this (data.vi_buf is a pointer to the userspace address):
down_read(¤t->mm->mmap_sem); rc = get_user_pages(current, current->mm, (unsigned long) data.vi_buf, 1, 1, 0, &acq_dev->vi_pg, NULL); up_read(¤t->mm->mmap_sem); if (rc != 1) { err("get_user_pages failed for VI."); return -EINVAL; } acq_dev->vi_d = dma_map_page(dev, acq_dev->vi_pg, 0, PAGE_SIZE, DMA_TO_DEVICE); if (acq_dev->vi_d == 0) { err("dma_map_page failed for VI."); goto cleanup_vi_2; } info("VI bus address: 0x%0lx", (unsigned long) acq_dev->vi_d);
But when my PCI device then reads data from the bus address acq_dev->vi_d, it just gets \0 bytes rather then the contents of the acq_dev->userspace buffer.
I tried to debug this with an additional
info("VI Start: 0x%0x", ((uint32_t*) page_address(acq_dev->vi_pg))[0]);
to print out the first byte of the mapped page, but this actually results in a kernel crash:
BUG: unable to handle kernel NULL pointer dereference at (null)
I figured this one out myself, get_user_pages and dma_map_page do not create a mapping in kernel space for the buffer. With info("VI Start: 0x%0x", ((uint32_t*) kmap(acq_dev->vi_pg))[0]); kunmap(acq_dev->vi_pg); it works just fine. And for some reason, now my original problem has magically disappeared as well. Maybe it got scared by the suddenly immediate threat of being debugged :-). Best, -Nikolaus -- »Time flies like an arrow, fruit flies like a Banana.« PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6 02CF A9AD B7F8 AE4E 425C
On Tue, Feb 8, 2011 at 02:42, Nikolaus Rath <Nikolaus@rath.org> wrote:
I figured this one out myself, get_user_pages and dma_map_page do not create a mapping in kernel space for the buffer.
uhm, I recall when I read the get_user_pages function, it's kinda "please pin those pages in RAM, don't let it paged out"....but the mapping is still in user space AFAIK
With
info("VI Start: 0x%0x", ((uint32_t*) kmap(acq_dev->vi_pg))[0]); kunmap(acq_dev->vi_pg);
Nice!
it works just fine. And for some reason, now my original problem has magically disappeared as well. Maybe it got scared by the suddenly immediate threat of being debugged :-).
If this is Facebook, I'll put "Like (this post)" on your post above :D -- regards, Mulyadi Santosa Freelance Linux trainer and consultant blog: the-hydra.blogspot.com training: mulyaditraining.blogspot.com
participants (2)
-
Mulyadi Santosa -
Nikolaus Rath