]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/gpu/drm/i915/intel_overlay.c
drm/i915: Release vma when the handle is closed
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / i915 / intel_overlay.c
index 30d2f5db7d871a5c462fef6e486aaf369f84bff9..2c598d63c794c8a68dc84cfabc86fa622133e5d9 100644 (file)
@@ -183,8 +183,7 @@ struct intel_overlay {
        u32 flip_addr;
        struct drm_i915_gem_object *reg_bo;
        /* flip handling */
-       struct drm_i915_gem_request *last_flip_req;
-       void (*flip_tail)(struct intel_overlay *);
+       struct i915_gem_active last_flip;
 };
 
 static struct overlay_registers __iomem *
@@ -210,37 +209,46 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
                io_mapping_unmap(regs);
 }
 
-static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+static void intel_overlay_submit_request(struct intel_overlay *overlay,
                                         struct drm_i915_gem_request *req,
-                                        void (*tail)(struct intel_overlay *))
+                                        i915_gem_retire_fn retire)
 {
-       int ret;
-
-       WARN_ON(overlay->last_flip_req);
-       i915_gem_request_assign(&overlay->last_flip_req, req);
+       GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip,
+                                       &overlay->i915->drm.struct_mutex));
+       overlay->last_flip.retire = retire;
+       i915_gem_active_set(&overlay->last_flip, req);
        i915_add_request(req);
+}
 
-       overlay->flip_tail = tail;
-       ret = i915_wait_request(overlay->last_flip_req);
-       if (ret)
-               return ret;
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+                                        struct drm_i915_gem_request *req,
+                                        i915_gem_retire_fn retire)
+{
+       intel_overlay_submit_request(overlay, req, retire);
+       return i915_gem_active_retire(&overlay->last_flip,
+                                     &overlay->i915->drm.struct_mutex);
+}
 
-       i915_gem_request_assign(&overlay->last_flip_req, NULL);
-       return 0;
+static struct drm_i915_gem_request *alloc_request(struct intel_overlay *overlay)
+{
+       struct drm_i915_private *dev_priv = overlay->i915;
+       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
+
+       return i915_gem_request_alloc(engine, dev_priv->kernel_context);
 }
 
 /* overlay needs to be disable in OCMD reg */
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        struct drm_i915_gem_request *req;
+       struct intel_ring *ring;
        int ret;
 
        WARN_ON(overlay->active);
        WARN_ON(IS_I830(dev_priv) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE));
 
-       req = i915_gem_request_alloc(engine, NULL);
+       req = alloc_request(overlay);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -252,11 +260,12 @@ static int intel_overlay_on(struct intel_overlay *overlay)
 
        overlay->active = true;
 
-       intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
-       intel_ring_emit(engine, overlay->flip_addr | OFC_UPDATE);
-       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-       intel_ring_emit(engine, MI_NOOP);
-       intel_ring_advance(engine);
+       ring = req->ring;
+       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
+       intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
 
        return intel_overlay_do_wait_request(overlay, req, NULL);
 }
@@ -266,8 +275,8 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
                                  bool load_polyphase_filter)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        struct drm_i915_gem_request *req;
+       struct intel_ring *ring;
        u32 flip_addr = overlay->flip_addr;
        u32 tmp;
        int ret;
@@ -282,7 +291,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
        if (tmp & (1 << 17))
                DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
 
-       req = i915_gem_request_alloc(engine, NULL);
+       req = alloc_request(overlay);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -292,29 +301,37 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
                return ret;
        }
 
-       intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
-       intel_ring_emit(engine, flip_addr);
-       intel_ring_advance(engine);
+       ring = req->ring;
+       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+       intel_ring_emit(ring, flip_addr);
+       intel_ring_advance(ring);
 
-       WARN_ON(overlay->last_flip_req);
-       i915_gem_request_assign(&overlay->last_flip_req, req);
-       i915_add_request(req);
+       intel_overlay_submit_request(overlay, req, NULL);
 
        return 0;
 }
 
-static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct i915_gem_active *active,
+                                              struct drm_i915_gem_request *req)
 {
+       struct intel_overlay *overlay =
+               container_of(active, typeof(*overlay), last_flip);
        struct drm_i915_gem_object *obj = overlay->old_vid_bo;
 
+       i915_gem_track_fb(obj, NULL,
+                         INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
+
        i915_gem_object_ggtt_unpin(obj);
        i915_gem_object_put(obj);
 
        overlay->old_vid_bo = NULL;
 }
 
-static void intel_overlay_off_tail(struct intel_overlay *overlay)
+static void intel_overlay_off_tail(struct i915_gem_active *active,
+                                  struct drm_i915_gem_request *req)
 {
+       struct intel_overlay *overlay =
+               container_of(active, typeof(*overlay), last_flip);
        struct drm_i915_gem_object *obj = overlay->vid_bo;
 
        /* never have the overlay hw on without showing a frame */
@@ -334,8 +351,8 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay)
 static int intel_overlay_off(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        struct drm_i915_gem_request *req;
+       struct intel_ring *ring;
        u32 flip_addr = overlay->flip_addr;
        int ret;
 
@@ -347,7 +364,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
         * of the hw. Do it in both cases */
        flip_addr |= OFC_UPDATE;
 
-       req = i915_gem_request_alloc(engine, NULL);
+       req = alloc_request(overlay);
        if (IS_ERR(req))
                return PTR_ERR(req);
 
@@ -357,46 +374,36 @@ static int intel_overlay_off(struct intel_overlay *overlay)
                return ret;
        }
 
+       ring = req->ring;
        /* wait for overlay to go idle */
-       intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
-       intel_ring_emit(engine, flip_addr);
-       intel_ring_emit(engine, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+       intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+       intel_ring_emit(ring, flip_addr);
+       intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        /* turn overlay off */
        if (IS_I830(dev_priv)) {
                /* Workaround: Don't disable the overlay fully, since otherwise
                 * it dies on the next OVERLAY_ON cmd. */
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_emit(engine, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_emit(ring, MI_NOOP);
        } else {
-               intel_ring_emit(engine, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-               intel_ring_emit(engine, flip_addr);
-               intel_ring_emit(engine,
+               intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+               intel_ring_emit(ring, flip_addr);
+               intel_ring_emit(ring,
                                MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
        }
-       intel_ring_advance(engine);
+       intel_ring_advance(ring);
 
-       return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail);
+       return intel_overlay_do_wait_request(overlay, req,
+                                            intel_overlay_off_tail);
 }
 
 /* recover from an interruption due to a signal
  * We have to be careful not to repeat work forever an make forward progess. */
 static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 {
-       int ret;
-
-       if (overlay->last_flip_req == NULL)
-               return 0;
-
-       ret = i915_wait_request(overlay->last_flip_req);
-       if (ret)
-               return ret;
-
-       if (overlay->flip_tail)
-               overlay->flip_tail(overlay);
-
-       i915_gem_request_assign(&overlay->last_flip_req, NULL);
-       return 0;
+       return i915_gem_active_retire(&overlay->last_flip,
+                                     &overlay->i915->drm.struct_mutex);
 }
 
 /* Wait for pending overlay flip and release old frame.
@@ -406,7 +413,6 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
        struct drm_i915_private *dev_priv = overlay->i915;
-       struct intel_engine_cs *engine = &dev_priv->engine[RCS];
        int ret;
 
        lockdep_assert_held(&dev_priv->drm.struct_mutex);
@@ -420,8 +426,9 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
        if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
                /* synchronous slowpath */
                struct drm_i915_gem_request *req;
+               struct intel_ring *ring;
 
-               req = i915_gem_request_alloc(engine, NULL);
+               req = alloc_request(overlay);
                if (IS_ERR(req))
                        return PTR_ERR(req);
 
@@ -431,22 +438,19 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
                        return ret;
                }
 
-               intel_ring_emit(engine,
+               ring = req->ring;
+               intel_ring_emit(ring,
                                MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-               intel_ring_emit(engine, MI_NOOP);
-               intel_ring_advance(engine);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_advance(ring);
 
                ret = intel_overlay_do_wait_request(overlay, req,
                                                    intel_overlay_release_old_vid_tail);
                if (ret)
                        return ret;
-       }
-
-       intel_overlay_release_old_vid_tail(overlay);
+       } else
+               intel_overlay_release_old_vid_tail(&overlay->last_flip, NULL);
 
-
-       i915_gem_track_fb(overlay->old_vid_bo, NULL,
-                         INTEL_FRONTBUFFER_OVERLAY(overlay->crtc->pipe));
        return 0;
 }
 
@@ -459,7 +463,6 @@ void intel_overlay_reset(struct drm_i915_private *dev_priv)
 
        intel_overlay_release_old_vid(overlay);
 
-       overlay->last_flip_req = NULL;
        overlay->old_xscale = 0;
        overlay->old_yscale = 0;
        overlay->crtc = NULL;
@@ -870,12 +873,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
        iowrite32(0, &regs->OCMD);
        intel_overlay_unmap_regs(overlay, regs);
 
-       ret = intel_overlay_off(overlay);
-       if (ret != 0)
-               return ret;
-
-       intel_overlay_off_tail(overlay);
-       return 0;
+       return intel_overlay_off(overlay);
 }
 
 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
@@ -1219,7 +1217,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        drm_modeset_unlock_all(dev);
-       i915_gem_object_put(new_bo);
+       i915_gem_object_put_unlocked(new_bo);
 out_free:
        kfree(params);
 
@@ -1460,7 +1458,7 @@ void intel_cleanup_overlay(struct drm_i915_private *dev_priv)
         * hardware should be off already */
        WARN_ON(dev_priv->overlay->active);
 
-       drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+       i915_gem_object_put_unlocked(dev_priv->overlay->reg_bo);
        kfree(dev_priv->overlay);
 }