8
votes

LDD3 (p:453) demos dma_map_single using a buffer passed in as a parameter.

bus_addr = dma_map_single(&dev->pci_dev->dev, buffer, count, dev->dma_dir);

Q1: What/where does this buffer come from?

kmalloc?

Q2: Why does DMA-API-HOWTO.txt state I can use raw kmalloc to DMA into?

Form http://www.mjmwired.net/kernel/Documentation/DMA-API-HOWTO.txt

L:51 If you acquired your memory via the page allocator kmalloc() then you may DMA to/from that memory using the addresses returned from those routines.

L:74 you cannot take the return of a kmap() call and DMA to/from that.

  1. So I can pass the address returned from kmalloc to my hardware device?
  2. Or should I run virt_to_bus on it first?
  3. Or should I pass this into dma_map_single?

Q3: When the DMA transfer is complete, can I read the data in the kernel driver via the kmalloc address?

addr = kmalloc(...);
...
printk("test result : 0x%08x\n", addr[0]);

Q4: Whats the best way to get this to user-space?

  1. copy_to_user?
  2. mmap the kmalloc memory?
  3. others?
1

1 Answers

16
votes
  1. kmalloc is indeed one source to get the buffer. Another can be alloc_page with the GFP_DMA flag.

  2. The meaning is that the memory that kmalloc returns is guaranteed to be contiguous in physical memory, not just virtual memory, so you can give the bus address of that pointer to your hardware. You do need to use dma_map_single() on the address returned which depending on exact platform might be no more then wrapper around virt_to_bus or might do more then do (set up IOMMU or GART tables)

  3. Correct, just make sure to follow cache coherency guidelines as the DMA guide explains.

  4. copy_to_user will work fine and is the easiest answer. Depending on your specific case it might be enough or you might need something with better performance. You cannot normaly map kmalloced addresses to user space, but you can DMA into user provided address (some caveats apply) or allocate user pages (alloc_page with GFP_USER)

Good luck!