I was looking at allocating a buffer for a DMA transaction. I read that there are two ways of doing this - coherent mappings or streaming mappings.
Now, we want cache coherent buffers. However, we are not doing any scatter/gather so we want the benefits of the dma_map_single call. We have set aside some contiguous memory in the bootargs so we always have enough contiguous memory available.
So I was wondering, can we call dma_alloc_coherent and then dma_map_single after it with the virtual address that dma_alloc_coherent returns? The returned physical address of the map single would then be set as the dma handle that dma_alloc_coherent returned in its call.
Does this make sense? Or is it superfluous/incorrect to do it this way?
You can't use both. But you're also trying to solve a nonexistent problem. Just use dma_alloc_coherent(), which gives you a contiguous DMA memory buffer with both virtual and physical addresses. DMA to the physical address, access it from the CPU with the virtual address. What's the issue?
Related
I am implementing a device driver in guest OS. For this I need to allocate a buffer space which is required to be contiguous physical memory. Does allocating buffer using kmalloc in guest OS guarantee contiguous physical address? If not, how can I achieve this?
kmalloc() will guarantee contiguous physical memory, and is supposed to be used for small objects, as stated in the function documentation:
* kmalloc is the normal method of allocating memory
* for objects smaller than page size in the kernel.
For bigger physically contiguous allocations, you should use alloc_pages() instead.
However, since you are in a guest OS, the physical memory you will be allocating is the one seen by the guest, not by the hypervisor (the "real" one). Whether the memory allocated is actually physically contiguous depends on how your hypervisor exposes memory to the guest OS.
I have a Linux device driver that allocates physical memory/pages. I have a single ioctl, which any application can call, which simply allocates a physical page and maps it to process memory using vm_insert_pfn.
I have already allocated a contiguous VMA based on the total number of pages required by the application. I am using alloc_page() to allocate a physical page.
What I want to know is, if the physical page allocated by alloc_page() is counted against the process making the IOCTL or if it is simply a physical page that belongs to the driver even after mapping it to pre-allocated VMA. If not how can I achieve this?
I am using flags like GFP_MOVABLE|GFP_HIGHUSER.
Of course in general the physical memory behind user mode allocations (e. g. pointers returned by malloc()) might very well move to some different physical address at the discretion of the kernel (for example if the memory is swapped to disk and is later recalled to some other segment of physical memory). However the user mode code will be unaffected as on those occasions the kernel will update the page tables to point to the new location with no change to the virtual address being used by the user.
If this (perhaps discontiguous) physical memory is to be the target of some DMA then there are the user mode mlock() and munlock() calls to prevent this this memory from being paged out and you can call get_user_pages() etc. to get the physical addresses to feed to the DMA hardware and so on. That’s all well and good- but that’s not my case.
Rather I have done some kernel mode allocations (using __get_free_pages()) to obtain physically contiguous memory as our PCIe card-based DMA engine does not support scatter-gather. All of this has been working fine for some time- until I encountered a motherboard on which I see hard crashes.
I have thus far not worried that the kernel might at any time just move the physical memory locations for these ranges (resulting in my DMA card writing data to the wrong locations).
But with the new crashes on this motherboard now have me questioning that assumption.
Can that kernel memory allocated with __get_free_pages() too be moved by the kernel at any time to a different physical address range?
And if so is there any kernel facility to prevent these moves?
I have an SoC which has both DSP and ARM cores on it and I would like to create a section of shared memory that both my userspace software, and DSP software are able to access. What would be the best way to allocate a buffer like this in Linux? Here is a little background, right now what I have is a kernel module in which I use kmalloc() to get a kernel buffer, I then use the __pa() macro from asm/page.h to get the physical address of my kernel buffer. I save this address as a sysfs entry so that my userspace code can get the physical address of this buffer. I can then write this address to the DSP so it knows where the shared memory location is, and I can also mmap /dev/mem or my own kernel module so that I can access this buffer from userspace (I could also use the read/write fileops).
For some reason I feel like this is overboard but I cannot find the best way to do what I am trying to do.
Would it be possible to just mmap \dev\mem a section of memory and just read and write to this section? My feeling is that this would not 'lock' this section of memory from the kernel, thus the kernel could still read/write to this memory without me knowing. Is this the case. After reading the memory management chapter of LDD3 I see that mmap creates a new VMA of the mapping. Would this lock this area of memory so that other processes would not get allocated this section of memory?
Any and all help is appreciated
Depending on the kind of DMA you're using, you need to allocate the buffer with dma_alloc_coherent(), or use standard allocations and the dma_map_* functions.
(You must not use __pa(); physical addresses are not necessarily the same as DMA bus addresses.)
To map the buffers to user space, use dma_mmap_coherent() for coherent buffers, or map the memory pages manually for streaming buffers.
For a similar requirement of mine, I had reserved about 16 MB of memory towards the end of ram and used it in both kernel and user space. Suppose you have 128 MB ram, you can set BOOTMEM argument as 112 MB in your boot loader. I am assuming you are using uboot. This will reserve 16 MB towards the end of the ram. Now in kernel and user space you can map this area and use it as shared memory.
Is the DMA address returned from this call the same as the physical address? LDD3 says the DMA address should be treated as opaque by the driver. I want to mmap this DMA buffer so user-space can read/write directly to it. Question is what PFN should I specify for the remap_pfn_range (which to my pleasant surprise now (kernel 3.4+) works for conventional memory same as for I/O memory). Can I just cast the DMA address to unsigned long and convert that to PFN? Isn't this a violation of what LDD3 said about opaqueness?
Does dma_alloc_coherent always use __get_free_pages internally? Does this mean the region is potentially always over-allocated (since first function takes bytes but second function allocates in units of pages)?
Is there a way to setup a single streaming mapping for multiple consecutive pages obtained from call to __get_free_pages? dma_map_page applies to only single pages.
No, the address returned is a virtual address, otherwise you wouldn't be able to access it from kernel space. It's dma_handle which represents the physical address, but it's opaque. You need to use virt_to_phys on the address it returns and then pass this to remap_pfn_range.
I don't believe it does (it's likely to be platform dependent though), but it does allocate pages. If you want smaller amounts of memory for DMA you should use dma_pool_create and then allocate regions from there.
You can use dma_map_single instead of dma_map_page.
I'd recommend consulting DMA-API.txt for more details on some of this stuff.