aboutsummaryrefslogtreecommitdiffstats
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.c82
1 files changed, 75 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c
index 446bbf7986b6..646f367a13f5 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 */
@@ -1370,7 +1374,8 @@ plane_view_scanout_stride(const struct intel_framebuffer *fb, int color_plane,
struct drm_i915_private *i915 = to_i915(fb->base.dev);
unsigned int stride_tiles;
- if (IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14)
+ if ((IS_ALDERLAKE_P(i915) || DISPLAY_VER(i915) >= 14) &&
+ src_stride_tiles < dst_stride_tiles)
stride_tiles = src_stride_tiles;
else
stride_tiles = dst_stride_tiles;
@@ -1497,8 +1502,20 @@ static u32 calc_plane_remap_info(const struct intel_framebuffer *fb, int color_p
size += remap_info->size;
} else {
- unsigned int dst_stride = plane_view_dst_stride_tiles(fb, color_plane,
- remap_info->width);
+ unsigned int dst_stride;
+
+ /*
+ * The hardware automagically calculates the CCS AUX surface
+ * stride from the main surface stride so can't really remap a
+ * smaller subset (unless we'd remap in whole AUX page units).
+ */
+ if (intel_fb_needs_pot_stride_remap(fb) &&
+ intel_fb_is_ccs_modifier(fb->base.modifier))
+ dst_stride = remap_info->src_stride;
+ else
+ dst_stride = remap_info->width;
+
+ dst_stride = plane_view_dst_stride_tiles(fb, color_plane, dst_stride);
assign_chk_ovf(i915, remap_info->dst_stride, dst_stride);
color_plane_info->mapping_stride = dst_stride *
@@ -1896,6 +1913,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 +1935,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 = {