convert remap_page_range() to remap_pfn_range() vs. 2.6.9-rc2-mm3
Subsystems (5)
cover convert remap_page_range() to remap_pfn_range() vs. 2.6.9-rc2-mm3
This series resolves a physical address overflow issue in the remap_page_range() API by replacing it with remap_pfn_range(), which accepts its physical address argument as a pfn, hence allowing the use of a single-precision physical address argument without the risk of overflow at the API boundary. The above issue has hobbled support for various 32-bit architectures, including some embedded systems (ppc440 IIRC), caused persistent portability issues for sound drivers for legacy systems (sparc32; unfortunately this patch alone does not fully resolve those), and according to John Fusco's reports, made drivers for some PCI-X hardware infeasible to port to recent ia32 PAE enterprise systems. With this patch series applied, physical address overflows on 32-bit systems caused directly by remap_page_range() are gone forever, and ca. 100LOC of cut-and-waste driver code are swept out of existence alongside them.
vs. 2.6.9-rc2-mm3 and the scheduler header cleanups. The parts touching mm.h should apply with just offsets if those aren't applied beforehand. Successfully tested on x86-64.
-- wli
P.S.: The existing solution to the sparc32 issue was to pass a double
precision representation of the physical address as 2 single- precision arguments in an API (io_remap_page_range()) whose argument corresponding to those two was a single single- precision argument on most/all other architectures. The sparc32-specific issue requires more work beyond these patches to rectify. The most apparent consequence of the API skew is that drivers don't compile on sparc32 when they use io_remap_page_range() due to passing insufficient arguments, or vice-versa for drivers originally written for sparc32.
PATCH 1/76 introduce remap_pfn_range()
This patch introduces remap_pfn_range(), destined to replace remap_page_range(). In the sequel, the callers of remap_page_range() will be converted one at a time.
By using a pfn to specify its physical address argument, remap_pfn_range() resolves a longstanding physical address overflow issue.
include/linux/mm.h +9 -2
@@ -856,8 +856,15 @@extern struct page *vmalloc_to_page (void *addr);extern struct page *follow_page (struct mm_struct *mm,unsigned long address,int write); -extern int remap_page_range (struct vm_area_struct *vma,unsigned long from, -unsigned long to,unsigned long size,pgprot_t prot); +int remap_pfn_range (struct vm_area_struct *,unsigned long , +unsigned long ,unsigned long ,pgprot_t ); + +static inline +int remap_page_range (struct vm_area_struct *vma,unsigned long uvaddr, +unsigned long paddr,unsigned long size,pgprot_t prot) +{ +return remap_pfn_range (vma, uvaddr, paddr >>PAGE_SHIFT , size, prot); +}#ifdef CONFIG_PROC_FS void __vm_stat_account (struct mm_struct *,unsigned long ,struct file *,long );
mm/memory.c +8 -11
@@ -945,16 +945,14 @@* in null mappings (currently treated as "copy-on-access") */ static inline void remap_pte_range (pte_t * pte,unsigned long address,unsigned long size, -unsigned long phys_addr,pgprot_t prot) +unsigned long pfn,pgprot_t prot) {unsigned long end; -unsigned long pfn; address &= ~PMD_MASK ; end = address + size;if (end >PMD_SIZE ) end =PMD_SIZE ; - pfn = phys_addr >>PAGE_SHIFT ; do { BUG_ON(!pte_none(*pte)); if (!pfn_valid(pfn) || PageReserved(pfn_to_page(pfn)))
@@ -966,7 +964,7 @@ }static inline int remap_pmd_range (struct mm_struct *mm,pmd_t * pmd,unsigned long address,unsigned long size, -unsigned long phys_addr,pgprot_t prot) +unsigned long pfn,pgprot_t prot) {unsigned long base, end;
@@ -975,12 +973,12 @@ end = address + size;if (end >PGDIR_SIZE ) end =PGDIR_SIZE ; - phys_addr -= address; + pfn -= address >>PAGE_SHIFT ; do { pte_t * pte = pte_alloc_map(mm, pmd, base + address); if (!pte) return -ENOMEM; - remap_pte_range(pte, base + address, end - address, address + phys_addr, prot); + remap_pte_range(pte, base + address, end - address, pfn + (address >> PAGE_SHIFT), prot); pte_unmap(pte); address = (address + PMD_SIZE) & PMD_MASK; pmd++;
@@ -989,7 +987,7 @@ }/* Note: this is only safe if the mm semaphore is held when called. */ -int remap_page_range (struct vm_area_struct *vma,unsigned long from,unsigned long phys_addr,unsigned long size,pgprot_t prot) +int remap_pfn_range (struct vm_area_struct *vma,unsigned long from,unsigned long pfn,unsigned long size,pgprot_t prot) {int error =0 ;pgd_t * dir;
@@ -997,7 +995,7 @@unsigned long end = from + size;struct mm_struct *mm = vma->vm_mm; - phys_addr -= from; + pfn -= from >>PAGE_SHIFT ; dir =pgd_offset (mm, from);flush_cache_range (vma, beg, end);if (from >= end)
@@ -1009,7 +1007,7 @@ error = -ENOMEM ;if (!pmd)break ; - error =remap_pmd_range (mm, pmd, from, end - from, phys_addr + from, prot); + error =remap_pmd_range (mm, pmd, from, end - from, pfn + (from >>PAGE_SHIFT ), prot);if (error)break ; from = (from +PGDIR_SIZE ) &PGDIR_MASK ;
@@ -1022,8 +1020,7 @@spin_unlock (&mm->page_table_lock);return error; } - -EXPORT_SYMBOL (remap_page_range); +EXPORT_SYMBOL (remap_pfn_range);/* * Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when
mm/nommu.c +1 -1
@@ -560,7 +560,7 @@return NULL ; } -int remap_page_range (struct vm_area_struct *vma,unsigned long from, +int remap_pfn_range (struct vm_area_struct *vma,unsigned long from,unsigned long to,unsigned long size,pgprot_t prot) {return -EPERM ;
PATCH 2/76 convert atyfb.c to use remap_pfn_range()
Quoted 3 lines · William Lee Irwin III
This patch introduces
remap_pfn_range(), destined to replaceremap_page_range(). In the sequel, the callers ofremap_page_range()will be converted one at a time.
Convert atyfb.c to use remap_pfn_range(). Here (as in numerous other cases) shifting the argument right by PAGE_SHIFT suffices.
drivers/video/aty/atyfb_base.c +2 -2
@@ -1174,8 +1174,8 @@ ~(par->mmap_map[i].prot_mask);pgprot_val (vma->vm_page_prot) |= par->mmap_map[i].prot_flag; -if (remap_page_range (vma, vma->vm_start + page, map_offset, - map_size, vma->vm_page_prot)) +if (remap_pfn_range (vma, vma->vm_start + page, + map_offset >>PAGE_SHIFT , map_size, vma->vm_page_prot))return -EAGAIN ; page += map_size;
PATCH 3/76 convert gbefb.c to use remap_pfn_range()
Quoted 2 lines · William Lee Irwin III
Convert
atyfb.cto useremap_pfn_range(). Here (as in numerous other cases) shifting the argument right byPAGE_SHIFTsuffices.
Conver the SGI GBE framebuffer driver to use remap_pfn_range().
drivers/video/gbefb.c +2 -2
@@ -1018,8 +1018,8 @@else phys_size =TILE_SIZE - offset; -if (remap_page_range - (vma, addr, phys_addr, phys_size, vma->vm_page_prot)) +if (remap_pfn_range (vma, addr, phys_addr >>PAGE_SHIFT , + phys_size, vma->vm_page_prot))return -EAGAIN ; offset =0 ;
PATCH 4/76 convert sgivwfb.c to use remap_pfn_range()
Quoted 1 line · William Lee Irwin III
Conver the SGI GBE framebuffer driver to use
remap_pfn_range().
Convert the SGI DBE framebuffer driver to use remap_pfn_range().
drivers/video/sgivwfb.c +2 -2
@@ -719,8 +719,8 @@pgprot_val (vma->vm_page_prot) =pgprot_val (vma->vm_page_prot) | _PAGE_PCD; vma->vm_flags |=VM_IO ; -if (remap_page_range - (vma, vma->vm_start, offset, size, vma->vm_page_prot)) +if (remap_pfn_range (vma, vma->vm_start, offset >>PAGE_SHIFT , + size, vma->vm_page_prot))return -EAGAIN ; vma->vm_file = file; printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
PATCH 5/76 convert igafb.c to use remap_pfn_range()
Quoted 1 line · William Lee Irwin III
Convert the SGI DBE framebuffer driver to use
remap_pfn_range().
Convert the IGA 1682 framebuffer driver to use remap_pfn_range().
drivers/video/igafb.c +2 -2
@@ -262,8 +262,8 @@pgprot_val (vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);pgprot_val (vma->vm_page_prot) |= par->mmap_map[i].prot_flag; -if (remap_page_range (vma, vma->vm_start + page, map_offset, - map_size, vma->vm_page_prot)) +if (remap_pfn_range (vma, vma->vm_start + page, + map_offset >>PAGE_SHIFT , map_size, vma->vm_page_prot))return -EAGAIN ; page += map_size;
PATCH 6/76 convert zr36120.c to use remap_pfn_range()
Quoted 1 line · William Lee Irwin III
Convert the IGA 1682 framebuffer driver to use
remap_pfn_range().
Conver the Zoran 36120/36125 framegrabber driver to use remap_pfn_range().
drivers/media/video/zr36120.c +2 -2
@@ -1474,8 +1474,8 @@/* start mapping the whole shabang to user memory */ pos = (unsigned long )ztv->fbuffer;while (size>0 ) { -unsigned long page =virt_to_phys ((void *)pos); -if (remap_page_range (vma, start, page,PAGE_SIZE ,PAGE_SHARED )) +unsigned long pfn =virt_to_phys ((void *)pos) >>PAGE_SHIFT ; +if (remap_pfn_range (vma, start, pfn,PAGE_SIZE ,PAGE_SHARED ))return -EAGAIN ; start +=PAGE_SIZE ; pos +=PAGE_SIZE ;