Skip to content

Commit b4cbb19

Browse files
committed
vm: add vm_iomap_memory() helper function
Various drivers end up replicating the code to mmap() their memory buffers into user space, and our core memory remapping function may be very flexible but it is unnecessarily complicated for the common cases to use. Our internal VM uses pfn's ("page frame numbers") which simplifies things for the VM, and allows us to pass physical addresses around in a denser and more efficient format than passing a "phys_addr_t" around, and having to shift it up and down by the page size. But it just means that drivers end up doing that shifting instead at the interface level. It also means that drivers end up mucking around with internal VM things like the vma details (vm_pgoff, vm_start/end) way more than they really need to. So this just exports a function to map a certain physical memory range into user space (using a phys_addr_t based interface that is much more natural for a driver) and hides all the complexity from the driver. Some drivers will still end up tweaking the vm_page_prot details for things like prefetching or cacheability etc, but that's actually relevant to the driver, rather than caring about what the page offset of the mapping is into the particular IO memory region. Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent bb33db7 commit b4cbb19

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

include/linux/mm.h

+2
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,8 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
16111611
unsigned long pfn);
16121612
int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
16131613
unsigned long pfn);
1614+
int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len);
1615+
16141616

16151617
struct page *follow_page_mask(struct vm_area_struct *vma,
16161618
unsigned long address, unsigned int foll_flags,

mm/memory.c

+47
Original file line numberDiff line numberDiff line change
@@ -2393,6 +2393,53 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
23932393
}
23942394
EXPORT_SYMBOL(remap_pfn_range);
23952395

2396+
/**
2397+
* vm_iomap_memory - remap memory to userspace
2398+
* @vma: user vma to map to
2399+
* @start: start of area
2400+
* @len: size of area
2401+
*
2402+
* This is a simplified io_remap_pfn_range() for common driver use. The
2403+
* driver just needs to give us the physical memory range to be mapped,
2404+
* we'll figure out the rest from the vma information.
2405+
*
2406+
* NOTE! Some drivers might want to tweak vma->vm_page_prot first to get
2407+
* whatever write-combining details or similar.
2408+
*/
2409+
int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)
2410+
{
2411+
unsigned long vm_len, pfn, pages;
2412+
2413+
/* Check that the physical memory area passed in looks valid */
2414+
if (start + len < start)
2415+
return -EINVAL;
2416+
/*
2417+
* You *really* shouldn't map things that aren't page-aligned,
2418+
* but we've historically allowed it because IO memory might
2419+
* just have smaller alignment.
2420+
*/
2421+
len += start & ~PAGE_MASK;
2422+
pfn = start >> PAGE_SHIFT;
2423+
pages = (len + ~PAGE_MASK) >> PAGE_SHIFT;
2424+
if (pfn + pages < pfn)
2425+
return -EINVAL;
2426+
2427+
/* We start the mapping 'vm_pgoff' pages into the area */
2428+
if (vma->vm_pgoff > pages)
2429+
return -EINVAL;
2430+
pfn += vma->vm_pgoff;
2431+
pages -= vma->vm_pgoff;
2432+
2433+
/* Can we fit all of the mapping? */
2434+
vm_len = vma->vm_end - vma->vm_start;
2435+
if (vm_len >> PAGE_SHIFT > pages)
2436+
return -EINVAL;
2437+
2438+
/* Ok, let it rip */
2439+
return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
2440+
}
2441+
EXPORT_SYMBOL(vm_iomap_memory);
2442+
23962443
static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
23972444
unsigned long addr, unsigned long end,
23982445
pte_fn_t fn, void *data)

0 commit comments

Comments
 (0)