drm/etnaviv: attach in fence to submit and move fence wait to fence_sync
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / etnaviv / etnaviv_gem_submit.c
index ff91154..20906c2 100644 (file)
@@ -38,17 +38,13 @@ static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
        struct etnaviv_gem_submit *submit;
        size_t sz = size_vstruct(nr, sizeof(submit->bos[0]), sizeof(*submit));
 
-       submit = kmalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
-       if (submit) {
-               submit->dev = dev;
-               submit->gpu = gpu;
+       submit = kzalloc(sz, GFP_KERNEL);
+       if (!submit)
+               return NULL;
 
-               /* initially, until copy_from_user() and bo lookup succeeds: */
-               submit->nr_bos = 0;
-               submit->fence = NULL;
+       submit->gpu = gpu;
 
-               ww_acquire_init(&submit->ticket, &reservation_ww_class);
-       }
+       ww_acquire_init(&submit->ticket, &reservation_ww_class);
 
        return submit;
 }
@@ -181,9 +177,36 @@ static int submit_fence_sync(const struct etnaviv_gem_submit *submit)
                        break;
        }
 
+       if (submit->flags & ETNA_SUBMIT_FENCE_FD_IN) {
+               /*
+                * Wait if the fence is from a foreign context, or if the fence
+                * array contains any fence from a foreign context.
+                */
+               if (!dma_fence_match_context(submit->in_fence, context))
+                       ret = dma_fence_wait(submit->in_fence, true);
+       }
+
        return ret;
 }
 
+static void submit_attach_object_fences(struct etnaviv_gem_submit *submit)
+{
+       int i;
+
+       for (i = 0; i < submit->nr_bos; i++) {
+               struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
+
+               if (submit->bos[i].flags & ETNA_SUBMIT_BO_WRITE)
+                       reservation_object_add_excl_fence(etnaviv_obj->resv,
+                                                         submit->out_fence);
+               else
+                       reservation_object_add_shared_fence(etnaviv_obj->resv,
+                                                           submit->out_fence);
+
+               submit_unlock_object(submit, i);
+       }
+}
+
 static void submit_unpin_objects(struct etnaviv_gem_submit *submit)
 {
        int i;
@@ -339,13 +362,16 @@ static void submit_cleanup(struct etnaviv_gem_submit *submit)
        for (i = 0; i < submit->nr_bos; i++) {
                struct etnaviv_gem_object *etnaviv_obj = submit->bos[i].obj;
 
+               /* if the GPU submit failed, objects might still be locked */
                submit_unlock_object(submit, i);
                drm_gem_object_put_unlocked(&etnaviv_obj->base);
        }
 
        ww_acquire_fini(&submit->ticket);
-       if (submit->fence)
-               dma_fence_put(submit->fence);
+       if (submit->in_fence)
+               dma_fence_put(submit->in_fence);
+       if (submit->out_fence)
+               dma_fence_put(submit->out_fence);
        kfree(submit);
 }
 
@@ -360,7 +386,6 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
        struct etnaviv_gem_submit *submit;
        struct etnaviv_cmdbuf *cmdbuf;
        struct etnaviv_gpu *gpu;
-       struct dma_fence *in_fence = NULL;
        struct sync_file *sync_file = NULL;
        int out_fence_fd = -1;
        void *stream;
@@ -470,21 +495,11 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
        }
 
        if (args->flags & ETNA_SUBMIT_FENCE_FD_IN) {
-               in_fence = sync_file_get_fence(args->fence_fd);
-               if (!in_fence) {
+               submit->in_fence = sync_file_get_fence(args->fence_fd);
+               if (!submit->in_fence) {
                        ret = -EINVAL;
                        goto err_submit_objects;
                }
-
-               /*
-                * Wait if the fence is from a foreign context, or if the fence
-                * array contains any fence from a foreign context.
-                */
-               if (!dma_fence_match_context(in_fence, gpu->fence_context)) {
-                       ret = dma_fence_wait(in_fence, true);
-                       if (ret)
-                               goto err_submit_objects;
-               }
        }
 
        ret = submit_fence_sync(submit);
@@ -511,6 +526,8 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
        if (ret)
                goto out;
 
+       submit_attach_object_fences(submit);
+
        cmdbuf = NULL;
 
        if (args->flags & ETNA_SUBMIT_FENCE_FD_OUT) {
@@ -520,7 +537,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
                 * fence to the sync file here, eliminating the ENOMEM
                 * possibility at this stage.
                 */
-               sync_file = sync_file_create(submit->fence);
+               sync_file = sync_file_create(submit->out_fence);
                if (!sync_file) {
                        ret = -ENOMEM;
                        goto out;
@@ -529,22 +546,12 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
        }
 
        args->fence_fd = out_fence_fd;
-       args->fence = submit->fence->seqno;
+       args->fence = submit->out_fence->seqno;
 
 out:
        submit_unpin_objects(submit);
 
-       /*
-        * If we're returning -EAGAIN, it may be due to the userptr code
-        * wanting to run its workqueue outside of any locks. Flush our
-        * workqueue to ensure that it is run in a timely manner.
-        */
-       if (ret == -EAGAIN)
-               flush_workqueue(priv->wq);
-
 err_submit_objects:
-       if (in_fence)
-               dma_fence_put(in_fence);
        submit_cleanup(submit);
 
 err_submit_cmds: