Patchwork [BUG] Bad page map in process ibv_devinfo

login
register
mail settings
Submitter David Miller
Date Nov. 18, 2011, 2:28 a.m.
Message ID <20111117.212847.1778246801048496855.davem@davemloft.net>
Download mbox | patch
Permalink /patch/126339/
State Accepted
Delegated to: David Miller
Headers show

Comments

David Miller - Nov. 18, 2011, 2:28 a.m.
From: David Miller <davem@davemloft.net>
Date: Thu, 17 Nov 2011 21:03:16 -0500 (EST)

> Patch coming up for testing in a bit.

Can someone with the effected hardware please test this?

--------------------
[PATCH] sparc: Kill custom io_remap_pfn_range().

To handle the large physical addresses, just make a simple wrapper
around remap_pfn_range() like MIPS does.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 arch/sparc/include/asm/pgtable_32.h |   20 ++++-
 arch/sparc/include/asm/pgtable_64.h |   20 ++++-
 arch/sparc/mm/Makefile              |    1 -
 arch/sparc/mm/generic_32.c          |   99 ---------------------
 arch/sparc/mm/generic_64.c          |  165 -----------------------------------
 5 files changed, 32 insertions(+), 273 deletions(-)
 delete mode 100644 arch/sparc/mm/generic_32.c
 delete mode 100644 arch/sparc/mm/generic_64.c
Lukas Razik - Nov. 18, 2011, 2:33 a.m.
David Miller <davem@davemloft.net> wrote:

> Can someone with the effected hardware please test this?
> 
> --------------------
> [PATCH] sparc: Kill custom io_remap_pfn_range().
> 
> To handle the large physical addresses, just make a simple wrapper
> around remap_pfn_range() like MIPS does.
> 
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> arch/sparc/include/asm/pgtable_32.h |   20 ++++-
> arch/sparc/include/asm/pgtable_64.h |   20 ++++-
> arch/sparc/mm/Makefile              |    1 -
> arch/sparc/mm/generic_32.c          |   99 ---------------------
> arch/sparc/mm/generic_64.c          |  165 -----------------------------------
> 5 files changed, 32 insertions(+), 273 deletions(-)
> delete mode 100644 arch/sparc/mm/generic_32.c
> delete mode 100644 arch/sparc/mm/generic_64.c
> 
> diff --git a/arch/sparc/include/asm/pgtable_32.h 
> b/arch/sparc/include/asm/pgtable_32.h
> index 5b31a8e..a790cc6 100644
> --- a/arch/sparc/include/asm/pgtable_32.h
> +++ b/arch/sparc/include/asm/pgtable_32.h
> @@ -431,10 +431,6 @@ extern unsigned long *sparc_valid_addr_bitmap;
> #define kern_addr_valid(addr) \
>     (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
> 
> -extern int io_remap_pfn_range(struct vm_area_struct *vma,
> -                  unsigned long from, unsigned long pfn,
> -                  unsigned long size, pgprot_t prot);
> -
> /*
>   * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> 
> in
>   * its high 4 bits.  These macros/functions put it there or get it from there.
> @@ -443,6 +439,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma,
> #define GET_IOSPACE(pfn)        (pfn >> (BITS_PER_LONG - 4))
> #define GET_PFN(pfn)            (pfn & 0x0fffffffUL)
> 
> +extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned 
> long,
> +               unsigned long, pgprot_t);
> +
> +static inline int io_remap_pfn_range(struct vm_area_struct *vma,
> +                     unsigned long from, unsigned long pfn,
> +                     unsigned long size, pgprot_t prot)
> +{
> +    unsigned long long offset, space, phys_base;
> +
> +    offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT;
> +    space = GET_IOSPACE(pfn);
> +    phys_base = offset | (space << 32ULL);
> +
> +    return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, 
> prot);
> +}
> +
> #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
> #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
> ({                                      \
> diff --git a/arch/sparc/include/asm/pgtable_64.h 
> b/arch/sparc/include/asm/pgtable_64.h
> index adf8932..38ebb2c 100644
> --- a/arch/sparc/include/asm/pgtable_64.h
> +++ b/arch/sparc/include/asm/pgtable_64.h
> @@ -757,10 +757,6 @@ static inline bool kern_addr_valid(unsigned long addr)
> 
> extern int page_in_phys_avail(unsigned long paddr);
> 
> -extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
> -                   unsigned long pfn,
> -                   unsigned long size, pgprot_t prot);
> -
> /*
>   * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> 
> in
>   * its high 4 bits.  These macros/functions put it there or get it from there.
> @@ -769,6 +765,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, 
> unsigned long from,
> #define GET_IOSPACE(pfn)        (pfn >> (BITS_PER_LONG - 4))
> #define GET_PFN(pfn)            (pfn & 0x0fffffffffffffffUL)
> 
> +extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned 
> long,
> +               unsigned long, pgprot_t);
> +
> +static inline int io_remap_pfn_range(struct vm_area_struct *vma,
> +                     unsigned long from, unsigned long pfn,
> +                     unsigned long size, pgprot_t prot)
> +{
> +    unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
> +    int space = GET_IOSPACE(pfn);
> +    unsigned long phys_base;
> +
> +    phys_base = offset | (((unsigned long) space) << 32UL);
> +
> +    return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, 
> prot);
> +}
> +
> #include <asm-generic/pgtable.h>
> 
> /* We provide our own get_unmapped_area to cope with VA holes and
> diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
> index e3cda21..301421c 100644
> --- a/arch/sparc/mm/Makefile
> +++ b/arch/sparc/mm/Makefile
> @@ -8,7 +8,6 @@ obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o gup.o
> obj-y                   += fault_$(BITS).o
> obj-y                   += init_$(BITS).o
> obj-$(CONFIG_SPARC32)   += loadmmu.o
> -obj-y                   += generic_$(BITS).o
> obj-$(CONFIG_SPARC32)   += extable.o btfixup.o srmmu.o iommu.o io-unit.o
> obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
> obj-$(CONFIG_SPARC_LEON)+= leon_mm.o
> diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c
> deleted file mode 100644
> index 6ca39a6..0000000
> --- a/arch/sparc/mm/generic_32.c
> +++ /dev/null
> @@ -1,99 +0,0 @@
> -/*
> - * generic.c: Generic Sparc mm routines that are not dependent upon
> - *            MMU type but are Sparc specific.
> - *
> - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/mm.h>
> -#include <linux/swap.h>
> -#include <linux/pagemap.h>
> -#include <linux/export.h>
> -
> -#include <asm/pgalloc.h>
> -#include <asm/pgtable.h>
> -#include <asm/page.h>
> -#include <asm/cacheflush.h>
> -#include <asm/tlbflush.h>
> -
> -/* Remap IO memory, the same way as remap_pfn_range(), but use
> - * the obio memory space.
> - *
> - * They use a pgprot that sets PAGE_IO and does not check the
> - * mem_map table as this is independent of normal memory.
> - */
> -static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, 
> unsigned long address, unsigned long size,
> -    unsigned long offset, pgprot_t prot, int space)
> -{
> -    unsigned long end;
> -
> -    address &= ~PMD_MASK;
> -    end = address + size;
> -    if (end > PMD_SIZE)
> -        end = PMD_SIZE;
> -    do {
> -        set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
> -        address += PAGE_SIZE;
> -        offset += PAGE_SIZE;
> -        pte++;
> -    } while (address < end);
> -}
> -
> -static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, 
> unsigned long address, unsigned long size,
> -    unsigned long offset, pgprot_t prot, int space)
> -{
> -    unsigned long end;
> -
> -    address &= ~PGDIR_MASK;
> -    end = address + size;
> -    if (end > PGDIR_SIZE)
> -        end = PGDIR_SIZE;
> -    offset -= address;
> -    do {
> -        pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
> -        if (!pte)
> -            return -ENOMEM;
> -        io_remap_pte_range(mm, pte, address, end - address, address + offset, 
> prot, space);
> -        address = (address + PMD_SIZE) & PMD_MASK;
> -        pmd++;
> -    } while (address < end);
> -    return 0;
> -}
> -
> -int io_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;
> -    unsigned long beg = from;
> -    unsigned long end = from + size;
> -    struct mm_struct *mm = vma->vm_mm;
> -    int space = GET_IOSPACE(pfn);
> -    unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
> -
> -    /* See comment in mm/memory.c remap_pfn_range */
> -    vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
> -    vma->vm_pgoff = (offset >> PAGE_SHIFT) |
> -        ((unsigned long)space << 28UL);
> -
> -    offset -= from;
> -    dir = pgd_offset(mm, from);
> -    flush_cache_range(vma, beg, end);
> -
> -    while (from < end) {
> -        pmd_t *pmd = pmd_alloc(mm, dir, from);
> -        error = -ENOMEM;
> -        if (!pmd)
> -            break;
> -        error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, 
> prot, space);
> -        if (error)
> -            break;
> -        from = (from + PGDIR_SIZE) & PGDIR_MASK;
> -        dir++;
> -    }
> -
> -    flush_tlb_range(vma, beg, end);
> -    return error;
> -}
> -EXPORT_SYMBOL(io_remap_pfn_range);
> diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c
> deleted file mode 100644
> index 9b357dd..0000000
> --- a/arch/sparc/mm/generic_64.c
> +++ /dev/null
> @@ -1,165 +0,0 @@
> -/*
> - * generic.c: Generic Sparc mm routines that are not dependent upon
> - *            MMU type but are Sparc specific.
> - *
> - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/mm.h>
> -#include <linux/swap.h>
> -#include <linux/export.h>
> -#include <linux/pagemap.h>
> -
> -#include <asm/pgalloc.h>
> -#include <asm/pgtable.h>
> -#include <asm/page.h>
> -#include <asm/tlbflush.h>
> -
> -/* Remap IO memory, the same way as remap_pfn_range(), but use
> - * the obio memory space.
> - *
> - * They use a pgprot that sets PAGE_IO and does not check the
> - * mem_map table as this is independent of normal memory.
> - */
> -static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
> -                      unsigned long address,
> -                      unsigned long size,
> -                      unsigned long offset, pgprot_t prot,
> -                      int space)
> -{
> -    unsigned long end;
> -
> -    /* clear hack bit that was used as a write_combine side-effect flag */
> -    offset &= ~0x1UL;
> -    address &= ~PMD_MASK;
> -    end = address + size;
> -    if (end > PMD_SIZE)
> -        end = PMD_SIZE;
> -    do {
> -        pte_t entry;
> -        unsigned long curend = address + PAGE_SIZE;
> -        
> -        entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
> -        if (!(address & 0xffff)) {
> -            if (PAGE_SIZE < (4 * 1024 * 1024) &&
> -                !(address & 0x3fffff) &&
> -                !(offset & 0x3ffffe) &&
> -                end >= address + 0x400000) {
> -                entry = mk_pte_io(offset, prot, space,
> -                          4 * 1024 * 1024);
> -                curend = address + 0x400000;
> -                offset += 0x400000;
> -            } else if (PAGE_SIZE < (512 * 1024) &&
> -                   !(address & 0x7ffff) &&
> -                   !(offset & 0x7fffe) &&
> -                   end >= address + 0x80000) {
> -                entry = mk_pte_io(offset, prot, space,
> -                          512 * 1024 * 1024);
> -                curend = address + 0x80000;
> -                offset += 0x80000;
> -            } else if (PAGE_SIZE < (64 * 1024) &&
> -                   !(offset & 0xfffe) &&
> -                   end >= address + 0x10000) {
> -                entry = mk_pte_io(offset, prot, space,
> -                          64 * 1024);
> -                curend = address + 0x10000;
> -                offset += 0x10000;
> -            } else
> -                offset += PAGE_SIZE;
> -        } else
> -            offset += PAGE_SIZE;
> -
> -        if (pte_write(entry))
> -            entry = pte_mkdirty(entry);
> -        do {
> -            BUG_ON(!pte_none(*pte));
> -            set_pte_at(mm, address, pte, entry);
> -            address += PAGE_SIZE;
> -            pte_val(entry) += PAGE_SIZE;
> -            pte++;
> -        } while (address < curend);
> -    } while (address < end);
> -}
> -
> -static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, 
> unsigned long address, unsigned long size,
> -    unsigned long offset, pgprot_t prot, int space)
> -{
> -    unsigned long end;
> -
> -    address &= ~PGDIR_MASK;
> -    end = address + size;
> -    if (end > PGDIR_SIZE)
> -        end = PGDIR_SIZE;
> -    offset -= address;
> -    do {
> -        pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
> -        if (!pte)
> -            return -ENOMEM;
> -        io_remap_pte_range(mm, pte, address, end - address, address + offset, 
> prot, space);
> -        pte_unmap(pte);
> -        address = (address + PMD_SIZE) & PMD_MASK;
> -        pmd++;
> -    } while (address < end);
> -    return 0;
> -}
> -
> -static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, 
> unsigned long address, unsigned long size,
> -    unsigned long offset, pgprot_t prot, int space)
> -{
> -    unsigned long end;
> -
> -    address &= ~PUD_MASK;
> -    end = address + size;
> -    if (end > PUD_SIZE)
> -        end = PUD_SIZE;
> -    offset -= address;
> -    do {
> -        pmd_t *pmd = pmd_alloc(mm, pud, address);
> -        if (!pud)
> -            return -ENOMEM;
> -        io_remap_pmd_range(mm, pmd, address, end - address, address + offset, 
> prot, space);
> -        address = (address + PUD_SIZE) & PUD_MASK;
> -        pud++;
> -    } while (address < end);
> -    return 0;
> -}
> -
> -int io_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;
> -    unsigned long beg = from;
> -    unsigned long end = from + size;
> -    struct mm_struct *mm = vma->vm_mm;
> -    int space = GET_IOSPACE(pfn);
> -    unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
> -    unsigned long phys_base;
> -
> -    phys_base = offset | (((unsigned long) space) << 32UL);
> -
> -    /* See comment in mm/memory.c remap_pfn_range */
> -    vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
> -    vma->vm_pgoff = phys_base >> PAGE_SHIFT;
> -
> -    offset -= from;
> -    dir = pgd_offset(mm, from);
> -    flush_cache_range(vma, beg, end);
> -
> -    while (from < end) {
> -        pud_t *pud = pud_alloc(mm, dir, from);
> -        error = -ENOMEM;
> -        if (!pud)
> -            break;
> -        error = io_remap_pud_range(mm, pud, from, end - from, offset + from, 
> prot, space);
> -        if (error)
> -            break;
> -        from = (from + PGDIR_SIZE) & PGDIR_MASK;
> -        dir++;
> -    }
> -
> -    flush_tlb_range(vma, beg, end);
> -    return error;
> -}
> -EXPORT_SYMBOL(io_remap_pfn_range);
> -- 
> 1.7.6.401.g6a319
> 

I'll try them immediately and write back ASAP.
Thanks once already!

Regards,
Lukas
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lukas Razik - Nov. 18, 2011, 5:02 a.m.
David Miller <davem@davemloft.net> wrote:

> Can someone with the effected hardware please test this?
> 
> --------------------
> [PATCH] sparc: Kill custom io_remap_pfn_range().
> 
> To handle the large physical addresses, just make a simple wrapper
> around remap_pfn_range() like MIPS does.
> 
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> arch/sparc/include/asm/pgtable_32.h |   20 ++++-
> arch/sparc/include/asm/pgtable_64.h |   20 ++++-
> arch/sparc/mm/Makefile              |    1 -
> arch/sparc/mm/generic_32.c          |   99 ---------------------
> arch/sparc/mm/generic_64.c          |  165 -----------------------------------
> 5 files changed, 32 insertions(+), 273 deletions(-)
> delete mode 100644 arch/sparc/mm/generic_32.c
> delete mode 100644 arch/sparc/mm/generic_64.c
> 

Hello David!

After applying your patch I still get the errors:
[ 1117.556582] swap_free: Bad swap file entry 100004e000061800
[ 1117.556710] BUG: Bad page map in process ibv_devinfo  pte:9c0000c300104608 pmd:00f882d0
[ 1117.556827] addr:fffff80100114000 vm_flags:400844fa anon_vma:          (null) mapping:fffff807f623a410 index:6180082
[ 1117.557007] vma->vm_file->f_op->mmap: ib_uverbs_mmap+0x8/0x38 [ib_uverbs]
[ 1117.557054] Call Trace:
[ 1117.557093]  [00000000004ccff8] unmap_vmas+0x514/0x7f4
[ 1117.557143]  [00000000004d0d14] unmap_region+0xb4/0x164
[ 1117.557192]  [00000000004d1d60] do_munmap+0x2a8/0x31c
[ 1117.557247]  [000000000042d340] SyS_64_munmap+0x88/0xa8
[ 1117.557302]  [0000000000406154] linux_sparc_syscall+0x34/0x44
[ 1117.557347] Disabling lock debugging due to kernel taint


Regards,
Lukas
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller - Nov. 18, 2011, 6:04 a.m.
From: Lukas Razik <linux@razik.name>
Date: Fri, 18 Nov 2011 05:02:57 +0000 (GMT)

> Hello David!
> 
> After applying your patch I still get the errors:

Thanks for testing, while I continue to look into this please double
check to make sure you really did run a kernel with the patch applied
:-)
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller - Nov. 18, 2011, 6:17 a.m.
From: Lukas Razik <linux@razik.name>
Date: Fri, 18 Nov 2011 05:02:57 +0000 (GMT)

> After applying your patch I still get the errors:
> [ 1117.556582] swap_free: Bad swap file entry 100004e000061800
> [ 1117.556710] BUG: Bad page map in process ibv_devinfo  pte:9c0000c300104608 pmd:00f882d0

This looks almost like it's actually a mapping to physical memory, or
at least it is a PTE which hasn't had pgprot_noncached() applied to
it's protections.

Another hint is that pte_mkspecial() hasn't been performed on this PTE
either.

The PTE is:			0x9c0000c300104608

which amounts to:

	_PAGE_VALID		0x8000000000000000
	_PAGE_ACCESSED_4V	0x1000000000000000
	_PAGE_READ_4V		0x0800000000000000
	_PAGE_WRITE_4V		0x0400000000000000
	physical page		0x000000c300104000
	_PAGE_CP_4V		0x0000000000000400
	_PAGE_CV_4V		0x0000000000000200
	_PAGE_RESV_4V		0x0000000000000008

That last bit is mysterious, there shouldn't be anything setting
the reserved bit 0x8.

But that just so happens to be equal to the SUN4U PTE's "side effect"
bit, _PAGE_E_4U.

Hmmm...

That explains everything.  The problem is that we don't do the sparc64
PTE handling code patching in modules.  So it's left at the default 4U
versions.

So the PTE did have pgprot_noncached() applied to it's protections,
it's just that this function is inlined into the driver module and
hasn't been patched properly by the sun4v code patcher when the module
got loaded.

I'll work on a fix for this.
--
To unsubscribe from this list: send the line "unsubscribe sparclinux" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 5b31a8e..a790cc6 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -431,10 +431,6 @@  extern unsigned long *sparc_valid_addr_bitmap;
 #define kern_addr_valid(addr) \
 	(test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
 
-extern int io_remap_pfn_range(struct vm_area_struct *vma,
-			      unsigned long from, unsigned long pfn,
-			      unsigned long size, pgprot_t prot);
-
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
  * its high 4 bits.  These macros/functions put it there or get it from there.
@@ -443,6 +439,22 @@  extern int io_remap_pfn_range(struct vm_area_struct *vma,
 #define GET_IOSPACE(pfn)		(pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)			(pfn & 0x0fffffffUL)
 
+extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
+			   unsigned long, pgprot_t);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+				     unsigned long from, unsigned long pfn,
+				     unsigned long size, pgprot_t prot)
+{
+	unsigned long long offset, space, phys_base;
+
+	offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT;
+	space = GET_IOSPACE(pfn);
+	phys_base = offset | (space << 32ULL);
+
+	return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
+}
+
 #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
 ({									  \
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index adf8932..38ebb2c 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -757,10 +757,6 @@  static inline bool kern_addr_valid(unsigned long addr)
 
 extern int page_in_phys_avail(unsigned long paddr);
 
-extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-			       unsigned long pfn,
-			       unsigned long size, pgprot_t prot);
-
 /*
  * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
  * its high 4 bits.  These macros/functions put it there or get it from there.
@@ -769,6 +765,22 @@  extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
 #define GET_IOSPACE(pfn)		(pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)			(pfn & 0x0fffffffffffffffUL)
 
+extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
+			   unsigned long, pgprot_t);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+				     unsigned long from, unsigned long pfn,
+				     unsigned long size, pgprot_t prot)
+{
+	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+	int space = GET_IOSPACE(pfn);
+	unsigned long phys_base;
+
+	phys_base = offset | (((unsigned long) space) << 32UL);
+
+	return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
+}
+
 #include <asm-generic/pgtable.h>
 
 /* We provide our own get_unmapped_area to cope with VA holes and
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
index e3cda21..301421c 100644
--- a/arch/sparc/mm/Makefile
+++ b/arch/sparc/mm/Makefile
@@ -8,7 +8,6 @@  obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o gup.o
 obj-y                   += fault_$(BITS).o
 obj-y                   += init_$(BITS).o
 obj-$(CONFIG_SPARC32)   += loadmmu.o
-obj-y                   += generic_$(BITS).o
 obj-$(CONFIG_SPARC32)   += extable.o btfixup.o srmmu.o iommu.o io-unit.o
 obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
 obj-$(CONFIG_SPARC_LEON)+= leon_mm.o
diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c
deleted file mode 100644
index 6ca39a6..0000000
--- a/arch/sparc/mm/generic_32.c
+++ /dev/null
@@ -1,99 +0,0 @@ 
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-#include <linux/export.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
-		address += PAGE_SIZE;
-		offset += PAGE_SIZE;
-		pte++;
-	} while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	offset -= address;
-	do {
-		pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-	return 0;
-}
-
-int io_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;
-	unsigned long beg = from;
-	unsigned long end = from + size;
-	struct mm_struct *mm = vma->vm_mm;
-	int space = GET_IOSPACE(pfn);
-	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-
-	/* See comment in mm/memory.c remap_pfn_range */
-	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-	vma->vm_pgoff = (offset >> PAGE_SHIFT) |
-		((unsigned long)space << 28UL);
-
-	offset -= from;
-	dir = pgd_offset(mm, from);
-	flush_cache_range(vma, beg, end);
-
-	while (from < end) {
-		pmd_t *pmd = pmd_alloc(mm, dir, from);
-		error = -ENOMEM;
-		if (!pmd)
-			break;
-		error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
-		if (error)
-			break;
-		from = (from + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	}
-
-	flush_tlb_range(vma, beg, end);
-	return error;
-}
-EXPORT_SYMBOL(io_remap_pfn_range);
diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c
deleted file mode 100644
index 9b357dd..0000000
--- a/arch/sparc/mm/generic_64.c
+++ /dev/null
@@ -1,165 +0,0 @@ 
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/export.h>
-#include <linux/pagemap.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
-				      unsigned long address,
-				      unsigned long size,
-				      unsigned long offset, pgprot_t prot,
-				      int space)
-{
-	unsigned long end;
-
-	/* clear hack bit that was used as a write_combine side-effect flag */
-	offset &= ~0x1UL;
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	do {
-		pte_t entry;
-		unsigned long curend = address + PAGE_SIZE;
-		
-		entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
-		if (!(address & 0xffff)) {
-			if (PAGE_SIZE < (4 * 1024 * 1024) &&
-			    !(address & 0x3fffff) &&
-			    !(offset & 0x3ffffe) &&
-			    end >= address + 0x400000) {
-				entry = mk_pte_io(offset, prot, space,
-						  4 * 1024 * 1024);
-				curend = address + 0x400000;
-				offset += 0x400000;
-			} else if (PAGE_SIZE < (512 * 1024) &&
-				   !(address & 0x7ffff) &&
-				   !(offset & 0x7fffe) &&
-				   end >= address + 0x80000) {
-				entry = mk_pte_io(offset, prot, space,
-						  512 * 1024 * 1024);
-				curend = address + 0x80000;
-				offset += 0x80000;
-			} else if (PAGE_SIZE < (64 * 1024) &&
-				   !(offset & 0xfffe) &&
-				   end >= address + 0x10000) {
-				entry = mk_pte_io(offset, prot, space,
-						  64 * 1024);
-				curend = address + 0x10000;
-				offset += 0x10000;
-			} else
-				offset += PAGE_SIZE;
-		} else
-			offset += PAGE_SIZE;
-
-		if (pte_write(entry))
-			entry = pte_mkdirty(entry);
-		do {
-			BUG_ON(!pte_none(*pte));
-			set_pte_at(mm, address, pte, entry);
-			address += PAGE_SIZE;
-			pte_val(entry) += PAGE_SIZE;
-			pte++;
-		} while (address < curend);
-	} while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	offset -= address;
-	do {
-		pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
-		if (!pte)
-			return -ENOMEM;
-		io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-		pte_unmap(pte);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-	return 0;
-}
-
-static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size,
-	unsigned long offset, pgprot_t prot, int space)
-{
-	unsigned long end;
-
-	address &= ~PUD_MASK;
-	end = address + size;
-	if (end > PUD_SIZE)
-		end = PUD_SIZE;
-	offset -= address;
-	do {
-		pmd_t *pmd = pmd_alloc(mm, pud, address);
-		if (!pud)
-			return -ENOMEM;
-		io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space);
-		address = (address + PUD_SIZE) & PUD_MASK;
-		pud++;
-	} while (address < end);
-	return 0;
-}
-
-int io_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;
-	unsigned long beg = from;
-	unsigned long end = from + size;
-	struct mm_struct *mm = vma->vm_mm;
-	int space = GET_IOSPACE(pfn);
-	unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-	unsigned long phys_base;
-
-	phys_base = offset | (((unsigned long) space) << 32UL);
-
-	/* See comment in mm/memory.c remap_pfn_range */
-	vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-	vma->vm_pgoff = phys_base >> PAGE_SHIFT;
-
-	offset -= from;
-	dir = pgd_offset(mm, from);
-	flush_cache_range(vma, beg, end);
-
-	while (from < end) {
-		pud_t *pud = pud_alloc(mm, dir, from);
-		error = -ENOMEM;
-		if (!pud)
-			break;
-		error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
-		if (error)
-			break;
-		from = (from + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	}
-
-	flush_tlb_range(vma, beg, end);
-	return error;
-}
-EXPORT_SYMBOL(io_remap_pfn_range);