Merge drm-upstream/drm-next into drm-intel-next-queued
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / i915_gem_userptr.c
index 709efe2357eac9948ba71a76e11c02ace9f6ae4c..2d4996de733120b155a613f5f60137b3afcecbcb 100644 (file)
@@ -399,64 +399,42 @@ struct get_pages_work {
        struct task_struct *task;
 };
 
-#if IS_ENABLED(CONFIG_SWIOTLB)
-#define swiotlb_active() swiotlb_nr_tbl()
-#else
-#define swiotlb_active() 0
-#endif
-
-static int
-st_set_pages(struct sg_table **st, struct page **pvec, int num_pages)
-{
-       struct scatterlist *sg;
-       int ret, n;
-
-       *st = kmalloc(sizeof(**st), GFP_KERNEL);
-       if (*st == NULL)
-               return -ENOMEM;
-
-       if (swiotlb_active()) {
-               ret = sg_alloc_table(*st, num_pages, GFP_KERNEL);
-               if (ret)
-                       goto err;
-
-               for_each_sg((*st)->sgl, sg, num_pages, n)
-                       sg_set_page(sg, pvec[n], PAGE_SIZE, 0);
-       } else {
-               ret = sg_alloc_table_from_pages(*st, pvec, num_pages,
-                                               0, num_pages << PAGE_SHIFT,
-                                               GFP_KERNEL);
-               if (ret)
-                       goto err;
-       }
-
-       return 0;
-
-err:
-       kfree(*st);
-       *st = NULL;
-       return ret;
-}
-
 static struct sg_table *
-__i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj,
-                            struct page **pvec, int num_pages)
+__i915_gem_userptr_alloc_pages(struct drm_i915_gem_object *obj,
+                              struct page **pvec, int num_pages)
 {
-       struct sg_table *pages;
+       unsigned int max_segment = i915_sg_segment_size();
+       struct sg_table *st;
        int ret;
 
-       ret = st_set_pages(&pages, pvec, num_pages);
-       if (ret)
+       st = kmalloc(sizeof(*st), GFP_KERNEL);
+       if (!st)
+               return ERR_PTR(-ENOMEM);
+
+alloc_table:
+       ret = __sg_alloc_table_from_pages(st, pvec, num_pages,
+                                         0, num_pages << PAGE_SHIFT,
+                                         max_segment,
+                                         GFP_KERNEL);
+       if (ret) {
+               kfree(st);
                return ERR_PTR(ret);
+       }
 
-       ret = i915_gem_gtt_prepare_pages(obj, pages);
+       ret = i915_gem_gtt_prepare_pages(obj, st);
        if (ret) {
-               sg_free_table(pages);
-               kfree(pages);
+               sg_free_table(st);
+
+               if (max_segment > PAGE_SIZE) {
+                       max_segment = PAGE_SIZE;
+                       goto alloc_table;
+               }
+
+               kfree(st);
                return ERR_PTR(ret);
        }
 
-       return pages;
+       return st;
 }
 
 static int
@@ -540,7 +518,8 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
                struct sg_table *pages = ERR_PTR(ret);
 
                if (pinned == npages) {
-                       pages = __i915_gem_userptr_set_pages(obj, pvec, npages);
+                       pages = __i915_gem_userptr_alloc_pages(obj, pvec,
+                                                              npages);
                        if (!IS_ERR(pages)) {
                                __i915_gem_object_set_pages(obj, pages);
                                pinned = 0;
@@ -661,7 +640,7 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
                pages = __i915_gem_userptr_get_pages_schedule(obj);
                active = pages == ERR_PTR(-EAGAIN);
        } else {
-               pages = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
+               pages = __i915_gem_userptr_alloc_pages(obj, pvec, num_pages);
                active = !IS_ERR(pages);
        }
        if (active)
@@ -834,7 +813,9 @@ int i915_gem_init_userptr(struct drm_i915_private *dev_priv)
        hash_init(dev_priv->mm_structs);
 
        dev_priv->mm.userptr_wq =
-               alloc_workqueue("i915-userptr-acquire", WQ_HIGHPRI, 0);
+               alloc_workqueue("i915-userptr-acquire",
+                               WQ_HIGHPRI | WQ_MEM_RECLAIM,
+                               0);
        if (!dev_priv->mm.userptr_wq)
                return -ENOMEM;