#include "ipath_kernel.h"
 #include "ipath_common.h"
 
-/*
- * mmap64 doesn't allow all 64 bits for 32-bit applications
- * so only use the low 43 bits.
- */
-#define MMAP64_MASK    0x7FFFFFFFFFFUL
-
 static int ipath_open(struct inode *, struct file *);
 static int ipath_close(struct inode *, struct file *);
 static ssize_t ipath_write(struct file *, const char __user *, size_t,
        .mmap = ipath_mmap
 };
 
+/*
+ * Convert kernel virtual addresses to physical addresses so they don't
+ * potentially conflict with the chip addresses used as mmap offsets.
+ * It doesn't really matter what mmap offset we use as long as we can
+ * interpret it correctly.
+ */
+static u64 cvt_kvaddr(void *p)
+{
+       struct page *page;
+       u64 paddr = 0;
+
+       page = vmalloc_to_page(p);
+       if (page)
+               paddr = page_to_pfn(page) << PAGE_SHIFT;
+
+       return paddr;
+}
+
 static int ipath_get_base_info(struct file *fp,
                               void __user *ubase, size_t ubase_size)
 {
                kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt;
                kinfo->spi_piobufbase = (u64) pd->port_piobufs +
                        dd->ipath_palign * kinfo->spi_piocnt * slave;
-               kinfo->__spi_uregbase = ((u64) pd->subport_uregbase +
-                       PAGE_SIZE * slave) & MMAP64_MASK;
+               kinfo->__spi_uregbase = cvt_kvaddr(pd->subport_uregbase +
+                       PAGE_SIZE * slave);
 
-               kinfo->spi_rcvhdr_base = ((u64) pd->subport_rcvhdr_base +
-                       pd->port_rcvhdrq_size * slave) & MMAP64_MASK;
+               kinfo->spi_rcvhdr_base = cvt_kvaddr(pd->subport_rcvhdr_base +
+                       pd->port_rcvhdrq_size * slave);
                kinfo->spi_rcvhdr_tailaddr = 0;
-               kinfo->spi_rcv_egrbufs = ((u64) pd->subport_rcvegrbuf +
-                       dd->ipath_rcvegrcnt * dd->ipath_rcvegrbufsize * slave) &
-                       MMAP64_MASK;
+               kinfo->spi_rcv_egrbufs = cvt_kvaddr(pd->subport_rcvegrbuf +
+                       dd->ipath_rcvegrcnt * dd->ipath_rcvegrbufsize * slave);
        }
 
        kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) /
        if (master) {
                kinfo->spi_runtime_flags |= IPATH_RUNTIME_MASTER;
                kinfo->spi_subport_uregbase =
-                       (u64) pd->subport_uregbase & MMAP64_MASK;
+                       cvt_kvaddr(pd->subport_uregbase);
                kinfo->spi_subport_rcvegrbuf =
-                       (u64) pd->subport_rcvegrbuf & MMAP64_MASK;
+                       cvt_kvaddr(pd->subport_rcvegrbuf);
                kinfo->spi_subport_rcvhdr_base =
-                       (u64) pd->subport_rcvhdr_base & MMAP64_MASK;
+                       cvt_kvaddr(pd->subport_rcvhdr_base);
                ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n",
                        kinfo->spi_port, kinfo->spi_runtime_flags,
                        (unsigned long long) kinfo->spi_subport_uregbase,
        struct ipath_devdata *dd;
        void *addr;
        size_t size;
-       int ret;
+       int ret = 0;
 
        /* If the port is not shared, all addresses should be physical */
-       if (!pd->port_subport_cnt) {
-               ret = -EINVAL;
+       if (!pd->port_subport_cnt)
                goto bail;
-       }
 
        dd = pd->port_dd;
        size = pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size;
        if (subport == 0) {
                unsigned num_slaves = pd->port_subport_cnt - 1;
 
-               if (pgaddr == ((u64) pd->subport_uregbase & MMAP64_MASK)) {
+               if (pgaddr == cvt_kvaddr(pd->subport_uregbase)) {
                        addr = pd->subport_uregbase;
                        size = PAGE_SIZE * num_slaves;
-               } else if (pgaddr == ((u64) pd->subport_rcvhdr_base &
-                                     MMAP64_MASK)) {
+               } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base)) {
                        addr = pd->subport_rcvhdr_base;
                        size = pd->port_rcvhdrq_size * num_slaves;
-               } else if (pgaddr == ((u64) pd->subport_rcvegrbuf &
-                                     MMAP64_MASK)) {
+               } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf)) {
                        addr = pd->subport_rcvegrbuf;
                        size *= num_slaves;
-               } else {
-                       ret = -EINVAL;
+               } else
                        goto bail;
-               }
-       } else if (pgaddr == (((u64) pd->subport_uregbase +
-                              PAGE_SIZE * (subport - 1)) & MMAP64_MASK)) {
+       } else if (pgaddr == cvt_kvaddr(pd->subport_uregbase +
+                                       PAGE_SIZE * (subport - 1))) {
                addr = pd->subport_uregbase + PAGE_SIZE * (subport - 1);
                size = PAGE_SIZE;
-       } else if (pgaddr == (((u64) pd->subport_rcvhdr_base +
-                              pd->port_rcvhdrq_size * (subport - 1)) &
-                             MMAP64_MASK)) {
+       } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base +
+                               pd->port_rcvhdrq_size * (subport - 1))) {
                addr = pd->subport_rcvhdr_base +
                        pd->port_rcvhdrq_size * (subport - 1);
                size = pd->port_rcvhdrq_size;
-       } else if (pgaddr == (((u64) pd->subport_rcvegrbuf +
-                              size * (subport - 1)) & MMAP64_MASK)) {
+       } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf +
+                              size * (subport - 1))) {
                addr = pd->subport_rcvegrbuf + size * (subport - 1);
                /* rcvegrbufs are read-only on the slave */
                if (vma->vm_flags & VM_WRITE) {
                 * with mprotect.
                 */
                vma->vm_flags &= ~VM_MAYWRITE;
-       } else {
-               ret = -EINVAL;
+       } else
                goto bail;
-       }
        len = vma->vm_end - vma->vm_start;
        if (len > size) {
                ipath_cdbg(MM, "FAIL: reqlen %lx > %zx\n", len, size);
        vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
        vma->vm_ops = &ipath_file_vm_ops;
        vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
-       ret = 0;
+       ret = 1;
 
 bail:
        return ret;
         * Check for kernel virtual addresses first, anything else must
         * match a HW or memory address.
         */
-       if (pgaddr >= (1ULL<<40)) {
-               ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
+       ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
+       if (ret) {
+               if (ret > 0)
+                       ret = 0;
                goto bail;
        }
 
         */
        if (uinfo->spu_subport_cnt <= 1)
                goto bail;
-       if (uinfo->spu_subport_cnt > 4) {
+       if (uinfo->spu_subport_cnt > INFINIPATH_MAX_SUBPORT) {
                ret = -EINVAL;
                goto bail;
        }