summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/display/intel_fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_fb.c')
-rw-r--r--drivers/gpu/drm/i915/display/intel_fb.c63
1 files changed, 59 insertions, 4 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
index 446bbf7986b6..19b35ece31f1 100644
--- a/drivers/gpu/drm/i915/display/intel_fb.c
+++ b/drivers/gpu/drm/i915/display/intel_fb.c
@@ -7,11 +7,15 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_modeset_helper.h>
+#include <linux/dma-fence.h>
+#include <linux/dma-resv.h>
+
#include "i915_drv.h"
#include "intel_display.h"
#include "intel_display_types.h"
#include "intel_dpt.h"
#include "intel_fb.h"
+#include "intel_frontbuffer.h"
#define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a))
@@ -1113,7 +1117,7 @@ static int intel_fb_offset_to_xy(int *x, int *y,
return -EINVAL;
}
- height = drm_framebuffer_plane_height(fb->height, fb, color_plane);
+ height = drm_format_info_plane_height(fb->format, fb->height, color_plane);
height = ALIGN(height, intel_tile_height(fb, color_plane));
/* Catch potential overflows early */
@@ -1896,6 +1900,21 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
return drm_gem_handle_create(file, &obj->base, handle);
}
+struct frontbuffer_fence_cb {
+ struct dma_fence_cb base;
+ struct intel_frontbuffer *front;
+};
+
+static void intel_user_framebuffer_fence_wake(struct dma_fence *dma,
+ struct dma_fence_cb *data)
+{
+ struct frontbuffer_fence_cb *cb = container_of(data, typeof(*cb), base);
+
+ intel_frontbuffer_queue_flush(cb->front);
+ kfree(cb);
+ dma_fence_put(dma);
+}
+
static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
struct drm_file *file,
unsigned int flags, unsigned int color,
@@ -1903,11 +1922,47 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb,
unsigned int num_clips)
{
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_frontbuffer *front = to_intel_frontbuffer(fb);
+ struct dma_fence *fence;
+ struct frontbuffer_fence_cb *cb;
+ int ret = 0;
- i915_gem_object_flush_if_display(obj);
- intel_frontbuffer_flush(to_intel_frontbuffer(fb), ORIGIN_DIRTYFB);
+ if (!atomic_read(&front->bits))
+ return 0;
- return 0;
+ if (dma_resv_test_signaled(obj->base.resv, dma_resv_usage_rw(false)))
+ goto flush;
+
+ ret = dma_resv_get_singleton(obj->base.resv, dma_resv_usage_rw(false),
+ &fence);
+ if (ret || !fence)
+ goto flush;
+
+ cb = kmalloc(sizeof(*cb), GFP_KERNEL);
+ if (!cb) {
+ dma_fence_put(fence);
+ ret = -ENOMEM;
+ goto flush;
+ }
+
+ cb->front = front;
+
+ intel_frontbuffer_invalidate(front, ORIGIN_DIRTYFB);
+
+ ret = dma_fence_add_callback(fence, &cb->base,
+ intel_user_framebuffer_fence_wake);
+ if (ret) {
+ intel_user_framebuffer_fence_wake(fence, &cb->base);
+ if (ret == -ENOENT)
+ ret = 0;
+ }
+
+ return ret;
+
+flush:
+ i915_gem_object_flush_if_display(obj);
+ intel_frontbuffer_flush(front, ORIGIN_DIRTYFB);
+ return ret;
}
static const struct drm_framebuffer_funcs intel_fb_funcs = {