fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / infiniband / hw / ipath / ipath_user_pages.c
index 2bb08af..311ec3b 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -32,6 +33,7 @@
 
 #include <linux/mm.h>
 #include <linux/device.h>
+#include <linux/vs_memory.h>
 
 #include "ipath_kernel.h"
 
@@ -57,21 +59,11 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages,
        size_t got;
        int ret;
 
-#if 0
-       /*
-        * XXX - causes MPI programs to fail, haven't had time to check
-        * yet
-        */
-       if (!capable(CAP_IPC_LOCK)) {
-               ret = -EPERM;
-               goto bail;
-       }
-#endif
-
        lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >>
                PAGE_SHIFT;
 
-       if (num_pages > lock_limit) {
+       if (num_pages > lock_limit ||
+               !vx_vmlocked_avail(current->mm, num_pages)) {
                ret = -ENOMEM;
                goto bail;
        }
@@ -88,7 +80,7 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages,
                        goto bail_release;
        }
 
-       current->mm->locked_vm += num_pages;
+       vx_vmlocked_add(current->mm, num_pages);
 
        ret = 0;
        goto bail;
@@ -99,6 +91,62 @@ bail:
        return ret;
 }
 
+/**
+ * ipath_map_page - a safety wrapper around pci_map_page()
+ *
+ * A dma_addr of all 0's is interpreted by the chip as "disabled".
+ * Unfortunately, it can also be a valid dma_addr returned on some
+ * architectures.
+ *
+ * The powerpc iommu assigns dma_addrs in ascending order, so we don't
+ * have to bother with retries or mapping a dummy page to insure we
+ * don't just get the same mapping again.
+ *
+ * I'm sure we won't be so lucky with other iommu's, so FIXME.
+ */
+dma_addr_t ipath_map_page(struct pci_dev *hwdev, struct page *page,
+       unsigned long offset, size_t size, int direction)
+{
+       dma_addr_t phys;
+
+       phys = pci_map_page(hwdev, page, offset, size, direction);
+
+       if (phys == 0) {
+               pci_unmap_page(hwdev, phys, size, direction);
+               phys = pci_map_page(hwdev, page, offset, size, direction);
+               /*
+                * FIXME: If we get 0 again, we should keep this page,
+                * map another, then free the 0 page.
+                */
+       }
+
+       return phys;
+}
+
+/**
+ * ipath_map_single - a safety wrapper around pci_map_single()
+ *
+ * Same idea as ipath_map_page().
+ */
+dma_addr_t ipath_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
+       int direction)
+{
+       dma_addr_t phys;
+
+       phys = pci_map_single(hwdev, ptr, size, direction);
+
+       if (phys == 0) {
+               pci_unmap_single(hwdev, phys, size, direction);
+               phys = pci_map_single(hwdev, ptr, size, direction);
+               /*
+                * FIXME: If we get 0 again, we should keep this page,
+                * map another, then free the 0 page.
+                */
+       }
+
+       return phys;
+}
+
 /**
  * ipath_get_user_pages - lock user pages into memory
  * @start_page: the start page
@@ -157,7 +205,7 @@ void ipath_release_user_pages(struct page **p, size_t num_pages)
 
        __ipath_release_user_pages(p, num_pages, 1);
 
-       current->mm->locked_vm -= num_pages;
+       vx_vmlocked_sub(current->mm, num_pages);
 
        up_write(&current->mm->mmap_sem);
 }
@@ -168,12 +216,13 @@ struct ipath_user_pages_work {
        unsigned long num_pages;
 };
 
-static void user_pages_account(void *ptr)
+static void user_pages_account(struct work_struct *_work)
 {
-       struct ipath_user_pages_work *work = ptr;
+       struct ipath_user_pages_work *work =
+               container_of(_work, struct ipath_user_pages_work, work);
 
        down_write(&work->mm->mmap_sem);
-       work->mm->locked_vm -= work->num_pages;
+       vx_vmlocked_sub(work->mm, work->num_pages);
        up_write(&work->mm->mmap_sem);
        mmput(work->mm);
        kfree(work);
@@ -196,7 +245,7 @@ void ipath_release_user_pages_on_close(struct page **p, size_t num_pages)
 
        goto bail;
 
-       INIT_WORK(&work->work, user_pages_account, work);
+       INIT_WORK(&work->work, user_pages_account);
        work->mm = mm;
        work->num_pages = num_pages;