Hello.
I am trying to write a kernel driver which copies a large buffer (say 25KB in length) from user space into kernel space with a final destination to the PCIe EP (endpoint) device which is an FPGA device having a memory FIFO to be written into.
I am using an old kernel linux: 3.8.13
The DMA allocation should be consistent/coherent DMA mapping.
Already written in driver:
//check if core device has properly DMA access:
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
{ ... }
else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
{ ... }
else
{ ... //no suitable DMA avilable... }
dma_buffer = pci_alloc_consistent(pdevice, BUFFER_SIZE, &dma_bus);
...
// at the ioctl function:
copy_from_user(...);
memcpy(dma_buffer, &WriteBuffer.Buffer[0], BUFFER_SIZE);
Please your advice - why the memcpy() function does not copy the content of the buffer into the DMA allocated buffer?
To allocate and map large (PAGE_SIZE or so) consistent DMA regions, you should do:
dma_addr_t dma_handle;
cpu_addr = pci_alloc_consistent(dev, size, &dma_handle);
This routine will allocate RAM for that region, so it acts similarly to __get_free_pages (but takes size instead of a page order). If your
driver needs regions sized smaller than a page, you may prefer using the pci_pool interface, described below.
It returns two values: the virtual address which you can use to access it from the CPU and dma_handle which you pass to the card.
The cpu return address and the DMA bus master address are both guaranteed to be aligned to the smallest PAGE_SIZE order which
is greater than or equal to the requested size. This invariant exists (for example) to guarantee that if you allocate a chunk which is smaller than or equal to 64 kilobytes, the extent of the buffer you receive will not cross a 64K boundary.
Please refer to drivers/net/ethernet/intel/e100.c.
static int e100_alloc(struct nic *nic)
{
nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem),
&nic->dma_addr);
return nic->mem ? 0 : -ENOMEM;
}
if ((err = e100_alloc(nic))) {
netif_err(nic, probe, nic->netdev, "Cannot alloc driver memory, aborting\n");
goto err_out_iounmap
}
... ...
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
Thanks,
Yiping
Hello Yiping.
I am not able to use memcpy to copy the source buffer content into that DMA-allocated buffer.
Is there an example (a kernel driver and a userspace application) to test the DMA?
Also: what is it :uio-dma? - how it can be used?
Thanks,
I.H.