From f92e1ee52ae2e5ef4249b12a5659dc2b011857c3 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Thu, 10 Nov 2016 15:50:35 +0200 Subject: [PATCH 01/51] drm: Add missing mutex_destroy in drm_dev_init/release Add 3 missing mutex_destroy to drm_dev_init teardown and drm_dev_release. v2: - Also include drm_dev_release Signed-off-by: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478785835-4142-1-git-send-email-joonas.lahtinen@linux.intel.com Link: http://patchwork.freedesktop.org/patch/msgid/1478785835-4142-1-git-send-email-joonas.lahtinen@linux.intel.com --- drivers/gpu/drm/drm_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 6efdba4993fc8..d1cb73963169a 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -568,6 +568,9 @@ int drm_dev_init(struct drm_device *dev, drm_fs_inode_free(dev->anon_inode); err_free: mutex_destroy(&dev->master_mutex); + mutex_destroy(&dev->ctxlist_mutex); + mutex_destroy(&dev->filelist_mutex); + mutex_destroy(&dev->struct_mutex); return ret; } EXPORT_SYMBOL(drm_dev_init); @@ -630,6 +633,9 @@ static void drm_dev_release(struct kref *ref) drm_minor_free(dev, DRM_MINOR_CONTROL); mutex_destroy(&dev->master_mutex); + mutex_destroy(&dev->ctxlist_mutex); + mutex_destroy(&dev->filelist_mutex); + mutex_destroy(&dev->struct_mutex); kfree(dev->unique); kfree(dev); } From b3c11ac267d461d3d597967164ff7278a919a39f Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Sat, 12 Nov 2016 01:12:56 +0000 Subject: [PATCH 02/51] drm: move allocation out of drm_get_format_name() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function's behaviour was changed in 90844f00049e, without changing its signature, causing people to keep using it the old way without realising they were now leaking memory. Rob Clark also noticed it was also allocating GFP_KERNEL memory in atomic contexts, breaking them. Instead of having to allocate GFP_ATOMIC memory and fixing the callers to make them cleanup the memory afterwards, let's change the function's signature by having the caller take care of the memory and passing it to the function. The new parameter is a single-field struct in order to enforce the size of its buffer and help callers to correctly manage their memory. Fixes: 90844f00049e ("drm: make drm_get_format_name thread-safe") Cc: Rob Clark Cc: Christian König Acked-by: Christian König Acked-by: Rob Clark Acked-by: Sinclair Yeh (vmwgfx) Reviewed-by: Jani Nikula Suggested-by: Ville Syrjälä Signed-off-by: Eric Engestrom Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161112011309.9799-1-eric@engestrom.ch --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 7 ++-- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 7 ++-- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 3 +- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 7 ++-- drivers/gpu/drm/drm_atomic.c | 10 +++-- drivers/gpu/drm/drm_crtc.c | 7 ++-- drivers/gpu/drm/drm_fourcc.c | 14 +++---- drivers/gpu/drm/drm_framebuffer.c | 7 ++-- drivers/gpu/drm/drm_modeset_helper.c | 7 ++-- drivers/gpu/drm/drm_plane.c | 7 ++-- .../gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 7 ++-- drivers/gpu/drm/i915/i915_debugfs.c | 10 ++--- drivers/gpu/drm/i915/intel_atomic_plane.c | 8 ++-- drivers/gpu/drm/i915/intel_display.c | 41 ++++++++----------- drivers/gpu/drm/radeon/atombios_crtc.c | 14 +++---- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 +- include/drm/drm_fourcc.h | 10 ++++- 17 files changed, 82 insertions(+), 87 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 679dd73202794..65a954cb69ed8 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2032,7 +2032,7 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; - char *format_name; + struct drm_format_name_buf format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -2144,9 +2144,8 @@ static int dce_v10_0_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - format_name = drm_get_format_name(target_fb->pixel_format); - DRM_ERROR("Unsupported screen format %s\n", format_name); - kfree(format_name); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format, &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 807dfedb3610d..d807e876366b0 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2013,7 +2013,7 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; - char *format_name; + struct drm_format_name_buf format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -2125,9 +2125,8 @@ static int dce_v11_0_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - format_name = drm_get_format_name(target_fb->pixel_format); - DRM_ERROR("Unsupported screen format %s\n", format_name); - kfree(format_name); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format, &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 57423332bf75b..c1bd1beab655c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1456,6 +1456,7 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; + struct drm_format_name_buf format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1559,7 +1560,7 @@ static int dce_v6_0_crtc_do_set_base(struct drm_crtc *crtc, break; default: DRM_ERROR("Unsupported screen format %s\n", - drm_get_format_name(target_fb->pixel_format)); + drm_get_format_name(target_fb->pixel_format, &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 6f7656d525e29..4ae59914bc324 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -1910,7 +1910,7 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; - char *format_name; + struct drm_format_name_buf format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -2015,9 +2015,8 @@ static int dce_v8_0_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - format_name = drm_get_format_name(target_fb->pixel_format); - DRM_ERROR("Unsupported screen format %s\n", format_name); - kfree(format_name); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format, &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f5ea7db4a48a2..57e0a6e96f6d6 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -861,9 +861,10 @@ static int drm_atomic_plane_check(struct drm_plane *plane, /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, state->fb->pixel_format); if (ret) { - char *format_name = drm_get_format_name(state->fb->pixel_format); - DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", format_name); - kfree(format_name); + struct drm_format_name_buf format_name; + DRM_DEBUG_ATOMIC("Invalid pixel format %s\n", + drm_get_format_name(state->fb->pixel_format, + &format_name)); return ret; } @@ -917,9 +918,10 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, if (state->fb) { struct drm_framebuffer *fb = state->fb; int i, n = drm_format_num_planes(fb->pixel_format); + struct drm_format_name_buf format_name; drm_printf(p, "\t\tformat=%s\n", - drm_get_format_name(fb->pixel_format)); + drm_get_format_name(fb->pixel_format, &format_name)); drm_printf(p, "\t\tsize=%dx%d\n", fb->width, fb->height); drm_printf(p, "\t\tlayers:\n"); for (i = 0; i < n; i++) { diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index ce274edb9e525..5745464922fa6 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -827,9 +827,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, ret = drm_plane_check_pixel_format(crtc->primary, fb->pixel_format); if (ret) { - char *format_name = drm_get_format_name(fb->pixel_format); - DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); - kfree(format_name); + struct drm_format_name_buf format_name; + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(fb->pixel_format, + &format_name)); goto out; } } diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index cbb8b77c363ca..90d2cc8da8eb6 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -79,17 +79,13 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) EXPORT_SYMBOL(drm_mode_legacy_fb_format); /** - * drm_get_format_name - return a string for drm fourcc format + * drm_get_format_name - fill a string with a drm fourcc format's name * @format: format to compute name of - * - * Note that the buffer returned by this function is owned by the caller - * and will need to be freed using kfree(). + * @buf: caller-supplied buffer */ -char *drm_get_format_name(uint32_t format) +const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf) { - char *buf = kmalloc(32, GFP_KERNEL); - - snprintf(buf, 32, + snprintf(buf->str, sizeof(buf->str), "%c%c%c%c %s-endian (0x%08x)", printable_char(format & 0xff), printable_char((format >> 8) & 0xff), @@ -98,7 +94,7 @@ char *drm_get_format_name(uint32_t format) format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", format); - return buf; + return buf->str; } EXPORT_SYMBOL(drm_get_format_name); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index af786f27f72ec..06ad3d1350c49 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -133,9 +133,10 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); if (!info) { - char *format_name = drm_get_format_name(r->pixel_format); - DRM_DEBUG_KMS("bad framebuffer format %s\n", format_name); - kfree(format_name); + struct drm_format_name_buf format_name; + DRM_DEBUG_KMS("bad framebuffer format %s\n", + drm_get_format_name(r->pixel_format, + &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index 2544dfe7354ca..2f452b3dd40e1 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -75,10 +75,11 @@ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, info = drm_format_info(mode_cmd->pixel_format); if (!info || !info->depth) { - char *format_name = drm_get_format_name(mode_cmd->pixel_format); + struct drm_format_name_buf format_name; - DRM_DEBUG_KMS("non-RGB pixel format %s\n", format_name); - kfree(format_name); + DRM_DEBUG_KMS("non-RGB pixel format %s\n", + drm_get_format_name(mode_cmd->pixel_format, + &format_name)); fb->depth = 0; fb->bits_per_pixel = 0; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 249c0ae52c6d1..2ba0c221bf1bc 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -479,9 +479,10 @@ static int __setplane_internal(struct drm_plane *plane, /* Check whether this plane supports the fb pixel format. */ ret = drm_plane_check_pixel_format(plane, fb->pixel_format); if (ret) { - char *format_name = drm_get_format_name(fb->pixel_format); - DRM_DEBUG_KMS("Invalid pixel format %s\n", format_name); - kfree(format_name); + struct drm_format_name_buf format_name; + DRM_DEBUG_KMS("Invalid pixel format %s\n", + drm_get_format_name(fb->pixel_format, + &format_name)); goto out; } diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index 7e7a4d43d6b69..afc2b5d2d5f03 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -608,17 +608,16 @@ static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, u32 ch, u32 y, u32 in_h, u32 fmt) { struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0); - char *format_name; + struct drm_format_name_buf format_name; u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en; u32 stride = fb->pitches[0]; u32 addr = (u32)obj->paddr + y * stride; DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n", ch + 1, y, in_h, stride, (u32)obj->paddr); - format_name = drm_get_format_name(fb->pixel_format); DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n", - addr, fb->width, fb->height, fmt, format_name); - kfree(format_name); + addr, fb->width, fb->height, fmt, + drm_get_format_name(fb->pixel_format, &format_name)); /* get reg offset */ reg_ctrl = RD_CH_CTRL(ch); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index c9465fbff2dfd..7166a1a6265da 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3032,7 +3032,7 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { struct drm_plane_state *state; struct drm_plane *plane = &intel_plane->base; - char *format_name; + struct drm_format_name_buf format_name; if (!plane->state) { seq_puts(m, "plane->state is NULL!\n"); @@ -3042,9 +3042,9 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) state = plane->state; if (state->fb) { - format_name = drm_get_format_name(state->fb->pixel_format); + drm_get_format_name(state->fb->pixel_format, &format_name); } else { - format_name = kstrdup("N/A", GFP_KERNEL); + sprintf(format_name.str, "N/A"); } seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n", @@ -3060,10 +3060,8 @@ static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) ((state->src_w & 0xffff) * 15625) >> 10, (state->src_h >> 16), ((state->src_h & 0xffff) * 15625) >> 10, - format_name, + format_name.str, plane_rotation(state->rotation)); - - kfree(format_name); } } diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index cb5594411bb64..984a6b75c118d 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -141,7 +141,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, crtc_state->base.enable ? crtc_state->pipe_src_h : 0; if (state->fb && drm_rotation_90_or_270(state->rotation)) { - char *format_name; + struct drm_format_name_buf format_name; if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { @@ -157,9 +157,9 @@ static int intel_plane_atomic_check(struct drm_plane *plane, switch (state->fb->pixel_format) { case DRM_FORMAT_C8: case DRM_FORMAT_RGB565: - format_name = drm_get_format_name(state->fb->pixel_format); - DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", format_name); - kfree(format_name); + DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n", + drm_get_format_name(state->fb->pixel_format, + &format_name)); return -EINVAL; default: diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f4e321853fa4c..6fd6283fa1f86 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12851,7 +12851,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("planes on this crtc\n"); list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - char *format_name; + struct drm_format_name_buf format_name; intel_plane = to_intel_plane(plane); if (intel_plane->pipe != crtc->pipe) continue; @@ -12864,12 +12864,11 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, continue; } - format_name = drm_get_format_name(fb->pixel_format); - DRM_DEBUG_KMS("[PLANE:%d:%s] enabled", plane->base.id, plane->name); DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = %s", - fb->base.id, fb->width, fb->height, format_name); + fb->base.id, fb->width, fb->height, + drm_get_format_name(fb->pixel_format, &format_name)); DRM_DEBUG_KMS("\tscaler:%d src %dx%d+%d+%d dst %dx%d+%d+%d\n", state->scaler_id, state->base.src.x1 >> 16, @@ -12879,8 +12878,6 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, state->base.dst.x1, state->base.dst.y1, drm_rect_width(&state->base.dst), drm_rect_height(&state->base.dst)); - - kfree(format_name); } } @@ -15745,7 +15742,7 @@ static int intel_framebuffer_init(struct drm_device *dev, unsigned int tiling = i915_gem_object_get_tiling(obj); int ret; u32 pitch_limit, stride_alignment; - char *format_name; + struct drm_format_name_buf format_name; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -15836,18 +15833,16 @@ static int intel_framebuffer_init(struct drm_device *dev, break; case DRM_FORMAT_XRGB1555: if (INTEL_INFO(dev)->gen > 3) { - format_name = drm_get_format_name(mode_cmd->pixel_format); - DRM_DEBUG("unsupported pixel format: %s\n", format_name); - kfree(format_name); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format, &format_name)); return -EINVAL; } break; case DRM_FORMAT_ABGR8888: if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) && INTEL_INFO(dev)->gen < 9) { - format_name = drm_get_format_name(mode_cmd->pixel_format); - DRM_DEBUG("unsupported pixel format: %s\n", format_name); - kfree(format_name); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format, &format_name)); return -EINVAL; } break; @@ -15855,17 +15850,15 @@ static int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_XRGB2101010: case DRM_FORMAT_XBGR2101010: if (INTEL_INFO(dev)->gen < 4) { - format_name = drm_get_format_name(mode_cmd->pixel_format); - DRM_DEBUG("unsupported pixel format: %s\n", format_name); - kfree(format_name); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format, &format_name)); return -EINVAL; } break; case DRM_FORMAT_ABGR2101010: if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) { - format_name = drm_get_format_name(mode_cmd->pixel_format); - DRM_DEBUG("unsupported pixel format: %s\n", format_name); - kfree(format_name); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format, &format_name)); return -EINVAL; } break; @@ -15874,16 +15867,14 @@ static int intel_framebuffer_init(struct drm_device *dev, case DRM_FORMAT_YVYU: case DRM_FORMAT_VYUY: if (INTEL_INFO(dev)->gen < 5) { - format_name = drm_get_format_name(mode_cmd->pixel_format); - DRM_DEBUG("unsupported pixel format: %s\n", format_name); - kfree(format_name); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format, &format_name)); return -EINVAL; } break; default: - format_name = drm_get_format_name(mode_cmd->pixel_format); - DRM_DEBUG("unsupported pixel format: %s\n", format_name); - kfree(format_name); + DRM_DEBUG("unsupported pixel format: %s\n", + drm_get_format_name(mode_cmd->pixel_format, &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 74f99bac08b1b..05f4ebe31ce2d 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1156,7 +1156,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, u32 tmp, viewport_w, viewport_h; int r; bool bypass_lut = false; - char *format_name; + struct drm_format_name_buf format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1260,9 +1260,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - format_name = drm_get_format_name(target_fb->pixel_format); - DRM_ERROR("Unsupported screen format %s\n", format_name); - kfree(format_name); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format, &format_name)); return -EINVAL; } @@ -1473,7 +1472,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, u32 viewport_w, viewport_h; int r; bool bypass_lut = false; - char *format_name; + struct drm_format_name_buf format_name; /* no fb bound */ if (!atomic && !crtc->primary->fb) { @@ -1563,9 +1562,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, bypass_lut = true; break; default: - format_name = drm_get_format_name(target_fb->pixel_format); - DRM_ERROR("Unsupported screen format %s\n", format_name); - kfree(format_name); + DRM_ERROR("Unsupported screen format %s\n", + drm_get_format_name(target_fb->pixel_format, &format_name)); return -EINVAL; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index c965514b82be2..e3f68cc9bb4b6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -985,8 +985,9 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, info = drm_format_info(mode_cmd2->pixel_format); if (!info || !info->depth) { + struct drm_format_name_buf format_name; DRM_ERROR("Unsupported framebuffer format %s\n", - drm_get_format_name(mode_cmd2->pixel_format)); + drm_get_format_name(mode_cmd2->pixel_format, &format_name)); return ERR_PTR(-EINVAL); } diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index dc0aafab9ffd2..fcc08da850c85 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -45,6 +45,14 @@ struct drm_format_info { u8 vsub; }; +/** + * struct drm_format_name_buf - name of a DRM format + * @str: string buffer containing the format name + */ +struct drm_format_name_buf { + char str[32]; +}; + const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); @@ -54,6 +62,6 @@ int drm_format_horz_chroma_subsampling(uint32_t format); int drm_format_vert_chroma_subsampling(uint32_t format); int drm_format_plane_width(int width, uint32_t format, int plane); int drm_format_plane_height(int height, uint32_t format, int plane); -char *drm_get_format_name(uint32_t format) __malloc; +const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf); #endif /* __DRM_FOURCC_H__ */ From dfeb693d5a5dab938fc9d371e6870da1b4c4b4cb Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 12 Nov 2016 18:19:58 +0100 Subject: [PATCH 03/51] drm/sun4i: constify component_ops structures These component_ops structures are only used as the second argument to component_add and component_del, which are declared as const, so the structures can be declared as const as well. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct component_ops i@p = { ... }; @ok1@ identifier r.i; expression e1; position p; @@ component_add(e1,&i@p) @ok2@ identifier r.i; expression e1; position p; @@ component_del(e1, &i@p) @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct component_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct component_ops i = { ... }; // The result of the size command before the change is (arm): text data bss dec hex filename 5266 236 8 5510 1586 sun4i_backend.o 6393 236 8 6637 19ed sun4i_tcon.o 3700 368 8 4076 fec sun4i_tv.o 1668 108 0 1776 6f0 sun6i_drc.o and after the change: text data bss dec hex filename 5274 228 8 5510 1586 sun4i_backend.o 6401 228 8 6637 19ed sun4i_tcon.o 3708 360 8 4076 fec sun4i_tv.o 1676 100 0 1776 6f0 sun6i_drc.o Signed-off-by: Julia Lawall Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478971198-3659-1-git-send-email-Julia.Lawall@lip6.fr --- drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +- drivers/gpu/drm/sun4i/sun4i_tcon.c | 2 +- drivers/gpu/drm/sun4i/sun4i_tv.c | 2 +- drivers/gpu/drm/sun4i/sun6i_drc.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 32c0584e3c356..701fff8705f15 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -389,7 +389,7 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master, reset_control_assert(backend->reset); } -static struct component_ops sun4i_backend_ops = { +static const struct component_ops sun4i_backend_ops = { .bind = sun4i_backend_bind, .unbind = sun4i_backend_unbind, }; diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index cadacb517f958..25674bcd6dd0a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -551,7 +551,7 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master, sun4i_tcon_free_clocks(tcon); } -static struct component_ops sun4i_tcon_ops = { +static const struct component_ops sun4i_tcon_ops = { .bind = sun4i_tcon_bind, .unbind = sun4i_tcon_unbind, }; diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index 1dd3d9eabf2e5..d430b331fed5c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -667,7 +667,7 @@ static void sun4i_tv_unbind(struct device *dev, struct device *master, clk_disable_unprepare(tv->clk); } -static struct component_ops sun4i_tv_ops = { +static const struct component_ops sun4i_tv_ops = { .bind = sun4i_tv_bind, .unbind = sun4i_tv_unbind, }; diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c index bf6d846d81322..873b479670609 100644 --- a/drivers/gpu/drm/sun4i/sun6i_drc.c +++ b/drivers/gpu/drm/sun4i/sun6i_drc.c @@ -80,7 +80,7 @@ static void sun6i_drc_unbind(struct device *dev, struct device *master, reset_control_assert(drc->reset); } -static struct component_ops sun6i_drc_ops = { +static const struct component_ops sun6i_drc_ops = { .bind = sun6i_drc_bind, .unbind = sun6i_drc_unbind, }; From 554dd692afd5d449168b5007841742db4a2ed17b Mon Sep 17 00:00:00 2001 From: Andrew Donnellan Date: Mon, 14 Nov 2016 14:03:59 +1100 Subject: [PATCH 04/51] drm/ast: free correct pointer in astfb_create() error paths In the err_free_vram and err_release_fbi error paths in astfb_create(), we attempt to free afbdev->sysram. The only jumps to these error paths occur before we assign afbdev->sysram = sysram. Free sysram instead. Signed-off-by: Andrew Donnellan Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114030359.27852-1-andrew.donnellan@au1.ibm.com --- drivers/gpu/drm/ast/ast_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index 7a86e24e26875..d6f5ec64c6673 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -253,7 +253,7 @@ static int astfb_create(struct drm_fb_helper *helper, err_release_fbi: drm_fb_helper_release_fbi(helper); err_free_vram: - vfree(afbdev->sysram); + vfree(sysram); return ret; } From 1b99b72489c6a2d9fb3156b403510dc5f6c8b6a5 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:11 +0100 Subject: [PATCH 05/51] drm/fb-helper: fix segfaults in drm_fb_helper_debug_* A drm driver that is implementing fb_debug_enter and fb_debug_leave in struct fb_ops with drm fb helper functions drm_fb_helper_debug_enter and drm_fb_helper_debug_leave must also implement the callback 'mode_set_base_atomic' in struct drm_crtc_helper_funcs. See Documentation/DocBook/kgdb.tmpl. The current implementation will segfault when 'mode_set_base_atomic' is a NULL pointer. Before this patch at least the drm drivers armada, ast, qxl, udl and virtio do not have a 'mode_set_base_atomic' implementation but using drm_fb_helper_debug_(enter|leave). So these drivers may segfault when callbacks fb_debug_(enter|leave) are called. Avoid the issue by just checking for NULL pointers. So all drivers can unconditionally implement fb_debug_(enter|leave) with the drm_fb_helper functions. If callback 'mode_set_base_atomic' is not implemented, the code in drm_fb_helper_debug_(enter|leave) does effectively nothing. Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-2-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/drm_fb_helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 36797c465edce..14547817566d9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -256,6 +256,9 @@ int drm_fb_helper_debug_enter(struct fb_info *info) continue; funcs = mode_set->crtc->helper_private; + if (funcs->mode_set_base_atomic == NULL) + continue; + drm_fb_helper_save_lut_atomic(mode_set->crtc, helper); funcs->mode_set_base_atomic(mode_set->crtc, mode_set->fb, @@ -309,6 +312,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info) continue; } + if (funcs->mode_set_base_atomic == NULL) + continue; + drm_fb_helper_restore_lut_atomic(mode_set->crtc); funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, crtc->y, LEAVE_ATOMIC_MODE_SET); From 1e0089288b9b10a3cff863d835688a0c44522acb Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:12 +0100 Subject: [PATCH 06/51] drm/fb-helper: add fb_debug_* to DRM_FB_HELPER_DEFAULT_OPS Add additional members fb_debug_enter and fb_debug_leave to helper define. They are shared by all fb_ops implementations. Suggested-by: Daniel Vetter Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-3-git-send-email-contact@stefanchrist.eu --- include/drm/drm_fb_helper.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index ed8edfef75b23..975deedd593ec 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -228,7 +228,9 @@ struct drm_fb_helper { .fb_set_par = drm_fb_helper_set_par, \ .fb_setcmap = drm_fb_helper_setcmap, \ .fb_blank = drm_fb_helper_blank, \ - .fb_pan_display = drm_fb_helper_pan_display + .fb_pan_display = drm_fb_helper_pan_display, \ + .fb_debug_enter = drm_fb_helper_debug_enter, \ + .fb_debug_leave = drm_fb_helper_debug_leave #ifdef CONFIG_DRM_FBDEV_EMULATION void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, From ea4ffffea3d7596528a400f9feb94fdb1f2b42bb Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:13 +0100 Subject: [PATCH 07/51] drm/amdgpu: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Alex Deucher Cc: Christian König Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-4-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 38bdc2d300a31..f1c9e59a7c875 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -75,18 +75,12 @@ amdgpufb_release(struct fb_info *info, int user) static struct fb_ops amdgpufb_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_open = amdgpufb_open, .fb_release = amdgpufb_release, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; From 1caae277607f159b1179b1fcf746fa42b7a29ce5 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:14 +0100 Subject: [PATCH 08/51] drm/armada: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Russell King Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-5-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/armada/armada_fbdev.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index ca73ad8614fe6..c5dc06a558834 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -19,16 +19,10 @@ static /*const*/ struct fb_ops armada_fb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; static int armada_fb_create(struct drm_fb_helper *fbh, From d4d938c9bd2838a4de55ca981e4928dacec9809b Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:15 +0100 Subject: [PATCH 09/51] drm/bochs: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Gerd Hoffmann Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-6-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/bochs/bochs_fbdev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index e1ec498a6b6eb..da790a1c302a2 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -22,14 +22,10 @@ static int bochsfb_mmap(struct fb_info *info, static struct fb_ops bochsfb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, .fb_mmap = bochsfb_mmap, }; From 659119de7e0171693a81f5afbc5476d49c5b4a6b Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:16 +0100 Subject: [PATCH 10/51] drm/fb_cma_helper: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: David Airlie Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-7-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/drm_fb_cma_helper.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 4c6664407bfb3..8bac57e2e41c9 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -314,14 +314,10 @@ static int drm_fb_cma_mmap(struct fb_info *info, struct vm_area_struct *vma) static struct fb_ops drm_fbdev_cma_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_setcmap = drm_fb_helper_setcmap, .fb_mmap = drm_fb_cma_mmap, }; From 2eec838cf4dffd1f28bc351408e6ae69cdec3080 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:17 +0100 Subject: [PATCH 11/51] drm/exynos: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Inki Dae Cc: Joonyoung Shim Cc: Seung-Woo Kim Cc: Kyungmin Park Acked-by: Inki Dae Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-8-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 4cfb39d543b45..9f35deb561705 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -63,15 +63,11 @@ static int exynos_drm_fb_mmap(struct fb_info *info, static struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_mmap = exynos_drm_fb_mmap, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_setcmap = drm_fb_helper_setcmap, }; static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, From 51a11f3ba5040b04c90c8976071c155a533d8507 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:18 +0100 Subject: [PATCH 12/51] drm/nouveau: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Ben Skeggs Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-9-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index cc8c583379815..2f2a3dcd4ad77 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -199,35 +199,23 @@ nouveau_fbcon_release(struct fb_info *info, int user) static struct fb_ops nouveau_fbcon_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_open = nouveau_fbcon_open, .fb_release = nouveau_fbcon_release, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = nouveau_fbcon_fillrect, .fb_copyarea = nouveau_fbcon_copyarea, .fb_imageblit = nouveau_fbcon_imageblit, .fb_sync = nouveau_fbcon_sync, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; static struct fb_ops nouveau_fbcon_sw_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_open = nouveau_fbcon_open, .fb_release = nouveau_fbcon_release, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; void From 1102af19cd3fba5321049efc537ebf8beaded5a8 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:19 +0100 Subject: [PATCH 13/51] drm/qxl: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops This patch removes a TODO comment in the code. I do not know whether it is still relevant. Cc: Dave Airlie Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-10-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/qxl/qxl_fb.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 2cd879a4ae156..7e305d8a41461 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -81,16 +81,10 @@ static struct fb_deferred_io qxl_defio = { static struct fb_ops qxlfb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, /* TODO: copy vmwgfx */ + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj) From 72b6bcb1a2a4d61a5cff87f74c91f1ab39b1a40d Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:20 +0100 Subject: [PATCH 14/51] drm/rockchip: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Mark Yao Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-11-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index a16c69f96ed5e..8f639c8597a56 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c @@ -37,15 +37,11 @@ static int rockchip_fbdev_mmap(struct fb_info *info, static struct fb_ops rockchip_drm_fbdev_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_mmap = rockchip_fbdev_mmap, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_setcmap = drm_fb_helper_setcmap, }; static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, From 13be31f95892146529edccb98231b166802dd1d0 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:21 +0100 Subject: [PATCH 15/51] drm/radeon: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Alex Deucher Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-12-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/radeon/radeon_fb.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index f65f29911dca1..899b6a1644bde 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -74,18 +74,12 @@ radeonfb_release(struct fb_info *info, int user) static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_open = radeonfb_open, .fb_release = radeonfb_release, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; From 902c255b52de42e96f5df8f59bb99e1041261fc4 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:22 +0100 Subject: [PATCH 16/51] drm/tegra: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Thierry Reding Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-13-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/tegra/fb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index e6d71fa4028ea..e4a5ab0a9677b 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -186,14 +186,10 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, #ifdef CONFIG_DRM_FBDEV_EMULATION static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_setcmap = drm_fb_helper_setcmap, }; static int tegra_fbdev_probe(struct drm_fb_helper *helper, From 812162f04fa3af70b72065090ef455a85a84d410 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:23 +0100 Subject: [PATCH 17/51] drm/udl: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Dave Airlie Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-14-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/udl/udl_fb.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 611b6b9bb3cb0..167f42c67c7cf 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -254,16 +254,10 @@ static int udl_fb_release(struct fb_info *info, int user) static struct fb_ops udlfb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, .fb_mmap = udl_fb_mmap, .fb_open = udl_fb_open, .fb_release = udl_fb_release, From 00d44063fded0f6d3da5d6aec6fa716e930da2ad Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:24 +0100 Subject: [PATCH 18/51] drm/msm: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Rob Clark Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-15-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/msm/msm_fbdev.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index ffd4a338ca12e..d29f5e82a4108 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -39,6 +39,7 @@ struct msm_fbdev { static struct fb_ops msm_fb_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, /* Note: to properly handle manual update displays, we wrap the * basic fbdev ops which write to the framebuffer @@ -49,12 +50,6 @@ static struct fb_ops msm_fb_ops = { .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_mmap = msm_fbdev_mmap, - - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, }; static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) From e59a03f581636999236e2b4c6d4253b6721e8e0e Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:25 +0100 Subject: [PATCH 19/51] drm/virtio: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops This patch removes a TODO comment in the code. I do not know whether it is still relevant. Cc: David Airlie Cc: Gerd Hoffmann Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-16-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/virtio/virtgpu_fb.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index 2242a80866a95..dd21f950e129d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -200,16 +200,10 @@ static void virtio_gpu_3d_imageblit(struct fb_info *info, static struct fb_ops virtio_gpufb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, /* TODO: copy vmwgfx */ + DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = virtio_gpu_3d_fillrect, .fb_copyarea = virtio_gpu_3d_copyarea, .fb_imageblit = virtio_gpu_3d_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; static int virtio_gpu_vmap_fb(struct virtio_gpu_device *vgdev, From d074e55de421b03b717cdcc9cd2a7a720803100a Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:26 +0100 Subject: [PATCH 20/51] drm/omapdrm: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Tomi Valkeinen Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-17-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index adb10fbe918da..8d8ac173f55d9 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -82,6 +82,7 @@ static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, static struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, /* Note: to properly handle manual update displays, we wrap the * basic fbdev ops which write to the framebuffer @@ -92,11 +93,7 @@ static struct fb_ops omap_fb_ops = { .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, .fb_pan_display = omap_fbdev_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, }; static int omap_fbdev_create(struct drm_fb_helper *helper, From a36384dd941b486a5db8272c1aadd5498b5daa28 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:27 +0100 Subject: [PATCH 21/51] drm/i915: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops Cc: Daniel Vetter Cc: Jani Nikula Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-18-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/i915/intel_fbdev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b7098f98bb671..e87221bba475b 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -102,16 +102,13 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, + DRM_FB_HELPER_DEFAULT_OPS, .fb_set_par = intel_fbdev_set_par, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = intel_fbdev_pan_display, .fb_blank = intel_fbdev_blank, - .fb_setcmap = drm_fb_helper_setcmap, - .fb_debug_enter = drm_fb_helper_debug_enter, - .fb_debug_leave = drm_fb_helper_debug_leave, }; static int intelfb_alloc(struct drm_fb_helper *helper, From 3da6c2f3b730cea04938e612e7f26dfbf2db9641 Mon Sep 17 00:00:00 2001 From: Stefan Christ Date: Mon, 14 Nov 2016 00:03:28 +0100 Subject: [PATCH 22/51] drm/gma500: use DRM_FB_HELPER_DEFAULT_OPS for fb_ops This refactoring leads to real functional changes in the driver. Now the struct psbfb_ops implements two additional members: .fb_setcmap = drm_fb_helper_setcmap, .fb_pan_display = drm_fb_helper_pan_display, and the struct psbfb_roll_ops implements one additional member: .fb_setcmap = drm_fb_helper_setcmap, and the struct psbfb_unaccel_ops implements two additional members: .fb_setcmap = drm_fb_helper_setcmap, .fb_pan_display = drm_fb_helper_pan_display, These changes are not tested. Cc: Patrik Jakobsson Signed-off-by: Stefan Christ Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479078208-25221-19-git-send-email-contact@stefanchrist.eu --- drivers/gpu/drm/gma500/framebuffer.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 97daf23f3fef7..4071b2d1e8cfc 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -185,9 +185,7 @@ static int psbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) static struct fb_ops psbfb_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, + DRM_FB_HELPER_DEFAULT_OPS, .fb_setcolreg = psbfb_setcolreg, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = psbfb_copyarea, @@ -198,9 +196,7 @@ static struct fb_ops psbfb_ops = { static struct fb_ops psbfb_roll_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, + DRM_FB_HELPER_DEFAULT_OPS, .fb_setcolreg = psbfb_setcolreg, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, @@ -211,9 +207,7 @@ static struct fb_ops psbfb_roll_ops = { static struct fb_ops psbfb_unaccel_ops = { .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_blank = drm_fb_helper_blank, + DRM_FB_HELPER_DEFAULT_OPS, .fb_setcolreg = psbfb_setcolreg, .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = drm_fb_helper_cfb_copyarea, From 14d7f96f90fb65c2ca0e0ac7df237e06ff001c29 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 14 Nov 2016 11:07:31 +0100 Subject: [PATCH 23/51] drm/fb_cma_helper: Add drm_fb_cma_prepare_fb() helper Add new drm_fb_cma_prepare_fb() helper function extracted from the imx-drm driver. This function checks if the plane has DMABUF attached to it, extracts the exclusive fence from it and attaches it to the plane state for the atomic helper to wait on it. Signed-off-by: Marek Vasut Cc: Daniel Vetter Cc: Lucas Stach Reviewed-by: Lucas Stach Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114100732.3446-1-marex@denx.de --- drivers/gpu/drm/drm_fb_cma_helper.c | 35 +++++++++++++++++++++++++++++ include/drm/drm_fb_cma_helper.h | 3 +++ 2 files changed, 38 insertions(+) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 8bac57e2e41c9..81b3558302b5a 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -18,13 +18,16 @@ */ #include +#include #include #include #include #include #include +#include #include #include +#include #define DEFAULT_FBDEFIO_DELAY_MS 50 @@ -265,6 +268,38 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, } EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj); +/** + * drm_fb_cma_prepare_fb() - Prepare CMA framebuffer + * @plane: Which plane + * @state: Plane state attach fence to + * + * This should be put into prepare_fb hook of struct &drm_plane_helper_funcs . + * + * This function checks if the plane FB has an dma-buf attached, extracts + * the exclusive fence and attaches it to plane state for the atomic helper + * to wait on. + * + * There is no need for cleanup_fb for CMA based framebuffer drivers. + */ +int drm_fb_cma_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct dma_buf *dma_buf; + struct dma_fence *fence; + + if ((plane->state->fb == state->fb) || !state->fb) + return 0; + + dma_buf = drm_fb_cma_get_gem_obj(state->fb, 0)->base.dma_buf; + if (dma_buf) { + fence = reservation_object_get_excl_rcu(dma_buf->resv); + drm_atomic_set_fence_for_plane(state, fence); + } + + return 0; +} +EXPORT_SYMBOL_GPL(drm_fb_cma_prepare_fb); + #ifdef CONFIG_DEBUG_FS static void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m) { diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index f313211f8ed52..cc82c73b07fc9 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -41,6 +41,9 @@ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane); +int drm_fb_cma_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *state); + #ifdef CONFIG_DEBUG_FS struct seq_file; From 782ea2a493ba908008cbf2ce50d1b4047c1bba0f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 14 Nov 2016 11:07:32 +0100 Subject: [PATCH 24/51] drm/imx: Switch to drm_fb_cma_prepare_fb() helper Remove the common code from the driver and use the drm_fb_cma_prepare_fb() helper instead. Moveover, call the helper from prepare_fb() plane hook . Signed-off-by: Marek Vasut Cc: Daniel Vetter Cc: Lucas Stach Reviewed-by: Lucas Stach Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114100732.3446-2-marex@denx.de Link: http://patchwork.freedesktop.org/patch/msgid/1476451342-146510-1-git-send-email-dvyukov@google.com --- drivers/gpu/drm/imx/imx-drm-core.c | 32 +----------------------------- drivers/gpu/drm/imx/ipuv3-plane.c | 1 + 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index a16e8b7df1207..33404295b447c 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -151,40 +150,11 @@ static int imx_drm_atomic_check(struct drm_device *dev, return ret; } -static int imx_drm_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock) -{ - struct drm_plane_state *plane_state; - struct drm_plane *plane; - struct dma_buf *dma_buf; - struct dma_fence *fence; - int i; - - /* - * If the plane fb has an dma-buf attached, fish out the exclusive - * fence for the atomic helper to wait on. - */ - for_each_plane_in_state(state, plane, plane_state, i) { - if ((plane->state->fb != plane_state->fb) && plane_state->fb) { - dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb, - 0)->base.dma_buf; - if (!dma_buf) - continue; - fence = reservation_object_get_excl_rcu(dma_buf->resv); - - drm_atomic_set_fence_for_plane(plane_state, fence); - } - } - - return drm_atomic_helper_commit(dev, state, nonblock); -} - static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = { .fb_create = drm_fb_cma_create, .output_poll_changed = imx_drm_output_poll_changed, .atomic_check = imx_drm_atomic_check, - .atomic_commit = imx_drm_atomic_commit, + .atomic_commit = drm_atomic_helper_commit, }; static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state) diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 6a97e396fce3e..e74a0ad52950c 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -468,6 +468,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, } static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = { + .prepare_fb = drm_fb_cma_prepare_fb, .atomic_check = ipu_plane_atomic_check, .atomic_disable = ipu_plane_atomic_disable, .atomic_update = ipu_plane_atomic_update, From 6bfec6d94556683c91c937a20576118183af9e1d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 14 Nov 2016 11:55:40 +0000 Subject: [PATCH 25/51] dma-buf: Use fence_get_rcu_safe() for retrieving the exclusive fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code is subject to a race where we may try to acquire a reference on a stale fence: [13703.335118] WARNING: CPU: 1 PID: 14975 at ./include/linux/kref.h:46 i915_gem_object_wait+0x1a3/0x1c0 [13703.335184] Modules linked in: [13703.335202] CPU: 1 PID: 14975 Comm: gem_concurrent_ Not tainted 4.9.0-rc4+ #26 [13703.335216] Hardware name: / , BIOS PYBSWCEL.86A.0027.2015.0507.1758 05/07/2015 [13703.335233] ffffc90002f5bcc8 ffffffff812807de 0000000000000000 0000000000000000 [13703.335257] ffffc90002f5bd08 ffffffff81073811 0000002e80000000 ffff88026bf7c780 [13703.335279] 7fffffffffffffff 0000000000000001 ffff88027045a550 ffff88026bf7c780 [13703.335301] Call Trace: [13703.335316] [] dump_stack+0x4d/0x6f [13703.335331] [] __warn+0xc1/0xe0 [13703.335343] [] warn_slowpath_null+0x18/0x20 [13703.335355] [] i915_gem_object_wait+0x1a3/0x1c0 [13703.335367] [] i915_gem_set_domain_ioctl+0xcc/0x330 [13703.335386] [] drm_ioctl+0x1cb/0x410 [13703.335400] [] ? i915_gem_obj_prepare_shmem_write+0x1d0/0x1d0 [13703.335416] [] ? drm_ioctl+0x2bb/0x410 [13703.335429] [] do_vfs_ioctl+0x8f/0x5c0 [13703.335442] [] SyS_ioctl+0x3c/0x70 [13703.335456] [] entry_SYSCALL_64_fastpath+0x17/0x98 [13703.335558] ---[ end trace fd24176416ba6981 ]--- [13703.382778] general protection fault: 0000 [#1] SMP [13703.382802] Modules linked in: [13703.382816] CPU: 1 PID: 14967 Comm: gem_concurrent_ Tainted: G W 4.9.0-rc4+ #26 [13703.382828] Hardware name: / , BIOS PYBSWCEL.86A.0027.2015.0507.1758 05/07/2015 [13703.382841] task: ffff880275458000 task.stack: ffffc90002f18000 [13703.382849] RIP: 0010:[] [] i915_gem_request_retire+0x2b4/0x320 [13703.382870] RSP: 0018:ffffc90002f1bbc8 EFLAGS: 00010293 [13703.382878] RAX: dead000000000200 RBX: ffff88026bf7dce8 RCX: dead000000000100 [13703.382887] RDX: dead000000000100 RSI: ffff88026bf7c930 RDI: ffff88026bf7dd00 [13703.382897] RBP: ffffc90002f1bbf8 R08: 00000000ffffffff R09: ffff88026b89a000 [13703.382905] R10: 0000000000000001 R11: ffff88026bbe8fe0 R12: ffff88026bf7c000 [13703.382913] R13: ffff880275af8000 R14: ffff88026bf7c180 R15: dead000000000200 [13703.382922] FS: 00007f89e787d740(0000) GS:ffff88027fd00000(0000) knlGS:0000000000000000 [13703.382934] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [13703.382942] CR2: 00007f9053d2e000 CR3: 000000026d414000 CR4: 00000000001006e0 [13703.382951] Stack: [13703.382958] ffff880275413000 ffffc90002f1bde8 ffff880275af8000 ffff880274e8a600 [13703.382976] ffff880276a06000 ffffc90002f1bde8 ffffc90002f1bc38 ffffffff813b48c5 [13703.382995] ffffc90002f1bc00 ffffc90002f1bde8 ffff88026972a440 0000000000000000 [13703.383021] Call Trace: [13703.383032] [] i915_gem_request_alloc+0xa5/0x350 [13703.383043] [] i915_gem_do_execbuffer.isra.41+0x7b3/0x18b0 [13703.383055] [] ? i915_gem_object_get_sg+0x25c/0x2b0 [13703.383065] [] ? i915_gem_object_get_page+0x1d/0x50 [13703.383076] [] ? i915_gem_pwrite_ioctl+0x66c/0x6d0 [13703.383086] [] i915_gem_execbuffer2+0x95/0x1e0 [13703.383096] [] drm_ioctl+0x1cb/0x410 [13703.383105] [] ? i915_gem_execbuffer+0x2d0/0x2d0 [13703.383117] [] ? hrtimer_start_range_ns+0x1a0/0x310 [13703.383128] [] do_vfs_ioctl+0x8f/0x5c0 [13703.383140] [] ? SyS_timer_settime+0x118/0x1a0 [13703.383150] [] SyS_ioctl+0x3c/0x70 [13703.383162] [] entry_SYSCALL_64_fastpath+0x17/0x98 [13703.383172] Code: 49 39 c6 48 8d 70 e8 48 8d 5f e8 75 16 eb 47 48 8d 43 18 48 8b 53 18 48 89 de 49 39 c6 48 8d 5a e8 74 33 48 8b 56 08 48 8b 46 10 <48> 89 42 08 48 89 10 f6 46 38 01 48 89 4e 08 4c 89 7e 10 74 cf [13703.383557] RIP [] i915_gem_request_retire+0x2b4/0x320 [13703.383570] RSP [13703.383586] ---[ end trace fd24176416ba6982 ]--- This is fixed by using the kref_get_unless_zero() as a full memory barrier to validate the fence is still the current exclusive fence before returning it back to the caller. (Note the fix only requires using dma_fence_get_rcu() and correct handling, but we may as well use the helper rather than inline equivalent code.) Note: Issue can only be hit with the i915 driver. Signed-off-by: Chris Wilson Cc: Sumit Semwal . Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115540.31155-1-chris@chris-wilson.co.uk --- include/linux/reservation.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/include/linux/reservation.h b/include/linux/reservation.h index 2e313cca08f03..d9706a6f5ae25 100644 --- a/include/linux/reservation.h +++ b/include/linux/reservation.h @@ -177,17 +177,14 @@ static inline struct dma_fence * reservation_object_get_excl_rcu(struct reservation_object *obj) { struct dma_fence *fence; - unsigned seq; -retry: - seq = read_seqcount_begin(&obj->seq); + + if (!rcu_access_pointer(obj->fence_excl)) + return NULL; + rcu_read_lock(); - fence = rcu_dereference(obj->fence_excl); - if (read_seqcount_retry(&obj->seq, seq)) { - rcu_read_unlock(); - goto retry; - } - fence = dma_fence_get(fence); + fence = dma_fence_get_rcu_safe(&obj->fence_excl); rcu_read_unlock(); + return fence; } From 35cf03508d8466ecc5199c9d609e74e85bec785b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 14 Nov 2016 17:40:57 -0500 Subject: [PATCH 26/51] drm: don't let crtc_ww_class leak out kbuild spotted this error, with drm/msm patches that add a new modeset-lock in the driver and driver built as a module: ERROR: "crtc_ww_class" [drivers/gpu/drm/msm/msm.ko] undefined! Really the only reason for crtc_ww_class not being internal to drm_modeset_lock.c is that drm_modeset_lock_init() was static-inline (for no particularly good reason). Fix that, and move crtc_ww_class into drm_modeset_lock.c. Signed-off-by: Rob Clark Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479163257-18703-1-git-send-email-robdclark@gmail.com --- drivers/gpu/drm/drm_crtc.c | 2 -- drivers/gpu/drm/drm_modeset_lock.c | 13 +++++++++++++ include/drm/drm_modeset_lock.h | 12 +----------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 5745464922fa6..7612f85e99fb2 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -102,8 +102,6 @@ int drm_crtc_force_disable_all(struct drm_device *dev) } EXPORT_SYMBOL(drm_crtc_force_disable_all); -DEFINE_WW_CLASS(crtc_ww_class); - static unsigned int drm_num_crtcs(struct drm_device *dev) { unsigned int num = 0; diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 61146f5b4f56a..9059fe3145a1a 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -60,6 +60,8 @@ * lists and lookup data structures. */ +static DEFINE_WW_CLASS(crtc_ww_class); + /** * drm_modeset_lock_all - take all modeset locks * @dev: DRM device @@ -397,6 +399,17 @@ int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx) } EXPORT_SYMBOL(drm_modeset_backoff_interruptible); +/** + * drm_modeset_lock_init - initialize lock + * @lock: lock to init + */ +void drm_modeset_lock_init(struct drm_modeset_lock *lock) +{ + ww_mutex_init(&lock->mutex, &crtc_ww_class); + INIT_LIST_HEAD(&lock->head); +} +EXPORT_SYMBOL(drm_modeset_lock_init); + /** * drm_modeset_lock - take modeset lock * @lock: lock to take diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index c5576fbcb909f..d918ce45ec2c0 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -82,8 +82,6 @@ struct drm_modeset_lock { struct list_head head; }; -extern struct ww_class crtc_ww_class; - void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx, uint32_t flags); void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx); @@ -91,15 +89,7 @@ void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx); void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx); int drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx); -/** - * drm_modeset_lock_init - initialize lock - * @lock: lock to init - */ -static inline void drm_modeset_lock_init(struct drm_modeset_lock *lock) -{ - ww_mutex_init(&lock->mutex, &crtc_ww_class); - INIT_LIST_HEAD(&lock->head); -} +void drm_modeset_lock_init(struct drm_modeset_lock *lock); /** * drm_modeset_lock_fini - cleanup lock From 72282a88d4ea2c0f3e520fab34db56af7119f6e7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Nov 2016 12:53:01 +0300 Subject: [PATCH 27/51] drm: zte: checking for NULL instead of IS_ERR() drm_dev_alloc() never returns NULL, it only returns error pointers on error. Fixes: 0a886f59528a ("drm: zte: add initial vou drm driver") Signed-off-by: Dan Carpenter Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161115095301.GC15424@mwanda --- drivers/gpu/drm/zte/zx_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c index abc8099e6f53b..3e76f72c92fff 100644 --- a/drivers/gpu/drm/zte/zx_drm_drv.c +++ b/drivers/gpu/drm/zte/zx_drm_drv.c @@ -107,8 +107,8 @@ static int zx_drm_bind(struct device *dev) return -ENOMEM; drm = drm_dev_alloc(&zx_drm_driver, dev); - if (!drm) - return -ENOMEM; + if (IS_ERR(drm)) + return PTR_ERR(drm); drm->dev_private = priv; dev_set_drvdata(dev, drm); From 196594efc2b992217264964cbfc9d9d1bfa8f41f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 15 Nov 2016 11:55:29 +0100 Subject: [PATCH 28/51] drm/fb_cma_helper: Add missing forward declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing forward declaration for struct drm_plane and drm_plane_state, which causes the following warning in the VC4 driver (can be replicated by building using bcm2835_defconfig): In file included from drivers/gpu/drm/vc4/vc4_drv.c:18:0: include/drm/drm_fb_cma_helper.h:45:13: warning: ‘struct drm_plane_state’ declared inside parameter list will not be visible outside of this definition or declaration struct drm_plane_state *state); ^~~~~~~~~~~~~~~ include/drm/drm_fb_cma_helper.h:44:34: warning: ‘struct drm_plane’ declared inside parameter list will not be visible outside of this definition or declaration int drm_fb_cma_prepare_fb(struct drm_plane *plane, Signed-off-by: Marek Vasut Cc: Daniel Vetter Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161115105529.3227-1-marex@denx.de --- include/drm/drm_fb_cma_helper.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index cc82c73b07fc9..3b00f6480b838 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -12,6 +12,8 @@ struct drm_fb_helper; struct drm_device; struct drm_file; struct drm_mode_fb_cmd2; +struct drm_plane; +struct drm_plane_state; struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev, unsigned int preferred_bpp, unsigned int num_crtc, From 1a02ea434ec3da3195c2bcba367c9ffb7eb1256e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:16 +0100 Subject: [PATCH 29/51] drm: Extract drm_dumb_buffers.c Just code movement, doc cleanup will follow up later. v2: Keep all the copyright notices. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-2-daniel.vetter@ffwll.ch --- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_crtc.c | 109 ---------------------- drivers/gpu/drm/drm_crtc_internal.h | 18 ++-- drivers/gpu/drm/drm_dumb_buffers.c | 138 ++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 118 deletions(-) create mode 100644 drivers/gpu/drm/drm_dumb_buffers.c diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index f217274754d4a..adcfc8f922e36 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -15,7 +15,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_modeset_lock.o drm_atomic.o drm_bridge.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ drm_encoder.o drm_mode_object.o drm_property.o \ - drm_plane.o drm_color_mgmt.o drm_print.o + drm_plane.o drm_color_mgmt.o drm_print.o \ + drm_dumb_buffers.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7612f85e99fb2..b0827634af18b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -968,115 +968,6 @@ void drm_mode_config_reset(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_reset); -/** - * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This creates a new dumb buffer in the driver's backing storage manager (GEM, - * TTM or something else entirely) and returns the resulting buffer handle. This - * handle can then be wrapped up into a framebuffer modeset object. - * - * Note that userspace is not allowed to use such objects for render - * acceleration - drivers must create their own private ioctls for such a use - * case. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_create_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_create_dumb *args = data; - u32 cpp, stride, size; - - if (!dev->driver->dumb_create) - return -ENOSYS; - if (!args->width || !args->height || !args->bpp) - return -EINVAL; - - /* overflow checks for 32bit size calculations */ - /* NOTE: DIV_ROUND_UP() can overflow */ - cpp = DIV_ROUND_UP(args->bpp, 8); - if (!cpp || cpp > 0xffffffffU / args->width) - return -EINVAL; - stride = cpp * args->width; - if (args->height > 0xffffffffU / stride) - return -EINVAL; - - /* test for wrap-around */ - size = args->height * stride; - if (PAGE_ALIGN(size) == 0) - return -EINVAL; - - /* - * handle, pitch and size are output parameters. Zero them out to - * prevent drivers from accidentally using uninitialized data. Since - * not all existing userspace is clearing these fields properly we - * cannot reject IOCTL with garbage in them. - */ - args->handle = 0; - args->pitch = 0; - args->size = 0; - - return dev->driver->dumb_create(file_priv, dev, args); -} - -/** - * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * Allocate an offset in the drm device node's address space to be able to - * memory map a dumb buffer. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_map_dumb *args = data; - - /* call driver ioctl to get mmap offset */ - if (!dev->driver->dumb_map_offset) - return -ENOSYS; - - return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); -} - -/** - * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This destroys the userspace handle for the given dumb backing storage buffer. - * Since buffer objects must be reference counted in the kernel a buffer object - * won't be immediately freed if a framebuffer modeset object still uses it. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_destroy_dumb *args = data; - - if (!dev->driver->dumb_destroy) - return -ENOSYS; - - return dev->driver->dumb_destroy(file_priv, dev, args->handle); -} - /** * drm_mode_config_init - initialize DRM mode_configuration structure * @dev: DRM device diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index c48ba02c5365d..64bb3eb7f8069 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -43,14 +43,6 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, void drm_fb_release(struct drm_file *file_priv); -/* dumb buffer support IOCTLs */ -int drm_mode_create_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); - /* IOCTLs */ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -59,6 +51,16 @@ int drm_mode_getcrtc(struct drm_device *dev, int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); +/* drm_dumb_buffers.c */ + +/* IOCTLs */ +int drm_mode_create_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); +int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); + /* drm_color_mgmt.c */ /* IOCTLs */ diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c new file mode 100644 index 0000000000000..cd291b538f5aa --- /dev/null +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006-2008 Intel Corporation + * Copyright (c) 2007 Dave Airlie + * Copyright (c) 2008 Red Hat Inc. + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include + +#include "drm_crtc_internal.h" + +/** + * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This creates a new dumb buffer in the driver's backing storage manager (GEM, + * TTM or something else entirely) and returns the resulting buffer handle. This + * handle can then be wrapped up into a framebuffer modeset object. + * + * Note that userspace is not allowed to use such objects for render + * acceleration - drivers must create their own private ioctls for such a use + * case. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_create_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_create_dumb *args = data; + u32 cpp, stride, size; + + if (!dev->driver->dumb_create) + return -ENOSYS; + if (!args->width || !args->height || !args->bpp) + return -EINVAL; + + /* overflow checks for 32bit size calculations */ + /* NOTE: DIV_ROUND_UP() can overflow */ + cpp = DIV_ROUND_UP(args->bpp, 8); + if (!cpp || cpp > 0xffffffffU / args->width) + return -EINVAL; + stride = cpp * args->width; + if (args->height > 0xffffffffU / stride) + return -EINVAL; + + /* test for wrap-around */ + size = args->height * stride; + if (PAGE_ALIGN(size) == 0) + return -EINVAL; + + /* + * handle, pitch and size are output parameters. Zero them out to + * prevent drivers from accidentally using uninitialized data. Since + * not all existing userspace is clearing these fields properly we + * cannot reject IOCTL with garbage in them. + */ + args->handle = 0; + args->pitch = 0; + args->size = 0; + + return dev->driver->dumb_create(file_priv, dev, args); +} + +/** + * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * Allocate an offset in the drm device node's address space to be able to + * memory map a dumb buffer. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_map_dumb *args = data; + + /* call driver ioctl to get mmap offset */ + if (!dev->driver->dumb_map_offset) + return -ENOSYS; + + return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); +} + +/** + * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer + * @dev: DRM device + * @data: ioctl data + * @file_priv: DRM file info + * + * This destroys the userspace handle for the given dumb backing storage buffer. + * Since buffer objects must be reference counted in the kernel a buffer object + * won't be immediately freed if a framebuffer modeset object still uses it. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_destroy_dumb *args = data; + + if (!dev->driver->dumb_destroy) + return -ENOSYS; + + return dev->driver->dumb_destroy(file_priv, dev, args->handle); +} + From ebc896db673071f4f85e6c484ff8e9b684e46204 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:17 +0100 Subject: [PATCH 30/51] drm/i915: Fixup kerneldoc includes Would be great if everony could add $ make DOCBOOKS="" htmldocs to their build scripts to catch these. 0day should also report them, not sure why it failed to spot this. Fixes: b42fe9ca0a1e ("drm/i915: Split out i915_vma.c") Cc: Tvrtko Ursulin Cc: Chris Wilson Cc: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-3-daniel.vetter@ffwll.ch --- Documentation/gpu/i915.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index ba83b7d88f1f4..117d2ab7a5f73 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -258,19 +258,19 @@ Global GTT views GTT Fences and Swizzling ------------------------ -.. kernel-doc:: drivers/gpu/drm/i915/i915_gem_fence.c +.. kernel-doc:: drivers/gpu/drm/i915/i915_gem_fence_reg.c :internal: Global GTT Fence Handling ~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/i915/i915_gem_fence.c +.. kernel-doc:: drivers/gpu/drm/i915/i915_gem_fence_reg.c :doc: fence register handling Hardware Tiling and Swizzling Details ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/i915/i915_gem_fence.c +.. kernel-doc:: drivers/gpu/drm/i915/i915_gem_fence_reg.c :doc: tiling swizzling details Object Tiling IOCTLs From 8a5846bf5d4756db1d4e03305217189c1c0e7160 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:18 +0100 Subject: [PATCH 31/51] doc/dma-buf: Fix up include directives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Would be great if everony could add $ make DOCBOOKS="" htmldocs to their build scripts to catch these. 0day should also report them, not sure why it failed to spot this. Fixes: f54d1867005c ("dma-buf: Rename struct fence to dma_fence") Cc: Chris Wilson Cc: Gustavo Padovan Cc: Sumit Semwal Cc: Christian König Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-4-daniel.vetter@ffwll.ch --- Documentation/driver-api/infrastructure.rst | 8 ++++---- include/linux/dma-fence.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/driver-api/infrastructure.rst b/Documentation/driver-api/infrastructure.rst index 5d50d6733db3b..a0d65eb490550 100644 --- a/Documentation/driver-api/infrastructure.rst +++ b/Documentation/driver-api/infrastructure.rst @@ -86,10 +86,10 @@ reservation fence ~~~~~ -.. kernel-doc:: drivers/dma-buf/fence.c +.. kernel-doc:: drivers/dma-buf/dma-fence.c :export: -.. kernel-doc:: include/linux/fence.h +.. kernel-doc:: include/linux/dma-fence.h :internal: .. kernel-doc:: drivers/dma-buf/seqno-fence.c @@ -98,10 +98,10 @@ fence .. kernel-doc:: include/linux/seqno-fence.h :internal: -.. kernel-doc:: drivers/dma-buf/fence-array.c +.. kernel-doc:: drivers/dma-buf/dma-fence-array.c :export: -.. kernel-doc:: include/linux/fence-array.h +.. kernel-doc:: include/linux/dma-fence-array.h :internal: .. kernel-doc:: drivers/dma-buf/reservation.c diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index fcf4b1971eba1..d51a7d23c358c 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -225,7 +225,7 @@ static inline struct dma_fence *dma_fence_get_rcu(struct dma_fence *fence) /** * dma_fence_get_rcu_safe - acquire a reference to an RCU tracked fence - * @fence: [in] pointer to fence to increase refcount of + * @fencep: [in] pointer to fence to increase refcount of * * Function returns NULL if no refcount could be obtained, or the fence. * This function handles acquiring a reference to a fence that may be From 85e634bce01af582a0fa549c904154b0e3c56db5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:19 +0100 Subject: [PATCH 32/51] drm: Extract drm_drv.h I want to move dumb buffer documentation into the right vfuncs, and for that I first need to be able to pull that into kerneldoc without having to clean up all of drmP.h. Also, header-splitting is nice. While at it shuffle all the function declarations for drm_drv.c into the right spots, and drop the kerneldoc for drm_minor_acquire/release since it's only used internally. v2: Keep all existing copyright notices (Chris). Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_drv.c | 18 +- drivers/gpu/drm/drm_internal.h | 4 + include/drm/drmP.h | 299 +---------------------------- include/drm/drm_drv.h | 340 +++++++++++++++++++++++++++++++++ 4 files changed, 349 insertions(+), 312 deletions(-) create mode 100644 include/drm/drm_drv.h diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index d1cb73963169a..6dbb986497955 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -32,7 +32,10 @@ #include #include #include + +#include #include + #include "drm_crtc_internal.h" #include "drm_legacy.h" #include "drm_internal.h" @@ -257,10 +260,7 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type) drm_debugfs_cleanup(minor); } -/** - * drm_minor_acquire - Acquire a DRM minor - * @minor_id: Minor ID of the DRM-minor - * +/* * Looks up the given minor-ID and returns the respective DRM-minor object. The * refence-count of the underlying device is increased so you must release this * object with drm_minor_release(). @@ -268,10 +268,6 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type) * As long as you hold this minor, it is guaranteed that the object and the * minor->dev pointer will stay valid! However, the device may get unplugged and * unregistered while you hold the minor. - * - * Returns: - * Pointer to minor-object with increased device-refcount, or PTR_ERR on - * failure. */ struct drm_minor *drm_minor_acquire(unsigned int minor_id) { @@ -294,12 +290,6 @@ struct drm_minor *drm_minor_acquire(unsigned int minor_id) return minor; } -/** - * drm_minor_release - Release DRM minor - * @minor: Pointer to DRM minor object - * - * Release a minor that was previously acquired via drm_minor_acquire(). - */ void drm_minor_release(struct drm_minor *minor) { drm_dev_unref(minor->dev); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index abd209863ef4a..b8cc0fc6d44cd 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -46,6 +46,10 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); +/* drm_drv.c */ +struct drm_minor *drm_minor_acquire(unsigned int minor_id); +void drm_minor_release(struct drm_minor *minor); + /* drm_info.c */ int drm_name_info(struct seq_file *m, void *data); int drm_clients_info(struct seq_file *m, void* data); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 4e58137c1882b..96a620ffd2989 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -76,6 +76,7 @@ #include #include #include +#include struct module; @@ -137,34 +138,10 @@ struct dma_buf_attachment; #define DRM_UT_VBL 0x20 #define DRM_UT_STATE 0x40 -extern __printf(6, 7) -void drm_dev_printk(const struct device *dev, const char *level, - unsigned int category, const char *function_name, - const char *prefix, const char *format, ...); - -extern __printf(3, 4) -void drm_printk(const char *level, unsigned int category, - const char *format, ...); - /***********************************************************************/ /** \name DRM template customization defaults */ /*@{*/ -/* driver capabilities and requirements mask */ -#define DRIVER_USE_AGP 0x1 -#define DRIVER_LEGACY 0x2 -#define DRIVER_PCI_DMA 0x8 -#define DRIVER_SG 0x10 -#define DRIVER_HAVE_DMA 0x20 -#define DRIVER_HAVE_IRQ 0x40 -#define DRIVER_IRQ_SHARED 0x80 -#define DRIVER_GEM 0x1000 -#define DRIVER_MODESET 0x2000 -#define DRIVER_PRIME 0x4000 -#define DRIVER_RENDER 0x8000 -#define DRIVER_ATOMIC 0x10000 -#define DRIVER_KMS_LEGACY_CONTEXT 0x20000 - /***********************************************************************/ /** \name Macros to make printk easier */ /*@{*/ @@ -480,263 +457,6 @@ struct drm_lock_data { #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) #define DRM_SCANOUTPOS_ACCURATE (1 << 2) -/** - * DRM driver structure. This structure represent the common code for - * a family of cards. There will one drm_device for each card present - * in this family - */ -struct drm_driver { - int (*load) (struct drm_device *, unsigned long flags); - int (*firstopen) (struct drm_device *); - int (*open) (struct drm_device *, struct drm_file *); - void (*preclose) (struct drm_device *, struct drm_file *file_priv); - void (*postclose) (struct drm_device *, struct drm_file *); - void (*lastclose) (struct drm_device *); - int (*unload) (struct drm_device *); - int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); - int (*dma_quiescent) (struct drm_device *); - int (*context_dtor) (struct drm_device *dev, int context); - int (*set_busid)(struct drm_device *dev, struct drm_master *master); - - /** - * get_vblank_counter - get raw hardware vblank counter - * @dev: DRM device - * @pipe: counter to fetch - * - * Driver callback for fetching a raw hardware vblank counter for @crtc. - * If a device doesn't have a hardware counter, the driver can simply - * use drm_vblank_no_hw_counter() function. The DRM core will account for - * missed vblank events while interrupts where disabled based on system - * timestamps. - * - * Wraparound handling and loss of events due to modesetting is dealt - * with in the DRM core code. - * - * RETURNS - * Raw vblank counter value. - */ - u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe); - - /** - * enable_vblank - enable vblank interrupt events - * @dev: DRM device - * @pipe: which irq to enable - * - * Enable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, the driver should use the - * drm_vblank_no_hw_counter() function that keeps a virtual counter. - * - * RETURNS - * Zero on success, appropriate errno if the given @crtc's vblank - * interrupt cannot be enabled. - */ - int (*enable_vblank) (struct drm_device *dev, unsigned int pipe); - - /** - * disable_vblank - disable vblank interrupt events - * @dev: DRM device - * @pipe: which irq to enable - * - * Disable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, the driver should use the - * drm_vblank_no_hw_counter() function that keeps a virtual counter. - */ - void (*disable_vblank) (struct drm_device *dev, unsigned int pipe); - - /** - * Called by \c drm_device_is_agp. Typically used to determine if a - * card is really attached to AGP or not. - * - * \param dev DRM device handle - * - * \returns - * One of three values is returned depending on whether or not the - * card is absolutely \b not AGP (return of 0), absolutely \b is AGP - * (return of 1), or may or may not be AGP (return of 2). - */ - int (*device_is_agp) (struct drm_device *dev); - - /** - * Called by vblank timestamping code. - * - * Return the current display scanout position from a crtc, and an - * optional accurate ktime_get timestamp of when position was measured. - * - * \param dev DRM device. - * \param pipe Id of the crtc to query. - * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). - * \param *vpos Target location for current vertical scanout position. - * \param *hpos Target location for current horizontal scanout position. - * \param *stime Target location for timestamp taken immediately before - * scanout position query. Can be NULL to skip timestamp. - * \param *etime Target location for timestamp taken immediately after - * scanout position query. Can be NULL to skip timestamp. - * \param mode Current display timings. - * - * Returns vpos as a positive number while in active scanout area. - * Returns vpos as a negative number inside vblank, counting the number - * of scanlines to go until end of vblank, e.g., -1 means "one scanline - * until start of active scanout / end of vblank." - * - * \return Flags, or'ed together as follows: - * - * DRM_SCANOUTPOS_VALID = Query successful. - * DRM_SCANOUTPOS_INVBL = Inside vblank. - * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of - * this flag means that returned position may be offset by a constant - * but unknown small number of scanlines wrt. real scanout position. - * - */ - int (*get_scanout_position) (struct drm_device *dev, unsigned int pipe, - unsigned int flags, int *vpos, int *hpos, - ktime_t *stime, ktime_t *etime, - const struct drm_display_mode *mode); - - /** - * Called by \c drm_get_last_vbltimestamp. Should return a precise - * timestamp when the most recent VBLANK interval ended or will end. - * - * Specifically, the timestamp in @vblank_time should correspond as - * closely as possible to the time when the first video scanline of - * the video frame after the end of VBLANK will start scanning out, - * the time immediately after end of the VBLANK interval. If the - * @crtc is currently inside VBLANK, this will be a time in the future. - * If the @crtc is currently scanning out a frame, this will be the - * past start time of the current scanout. This is meant to adhere - * to the OpenML OML_sync_control extension specification. - * - * \param dev dev DRM device handle. - * \param pipe crtc for which timestamp should be returned. - * \param *max_error Maximum allowable timestamp error in nanoseconds. - * Implementation should strive to provide timestamp - * with an error of at most *max_error nanoseconds. - * Returns true upper bound on error for timestamp. - * \param *vblank_time Target location for returned vblank timestamp. - * \param flags 0 = Defaults, no special treatment needed. - * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank - * irq handler. Some drivers need to apply some workarounds - * for gpu-specific vblank irq quirks if flag is set. - * - * \returns - * Zero if timestamping isn't supported in current display mode or a - * negative number on failure. A positive status code on success, - * which describes how the vblank_time timestamp was computed. - */ - int (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe, - int *max_error, - struct timeval *vblank_time, - unsigned flags); - - /* these have to be filled in */ - - irqreturn_t(*irq_handler) (int irq, void *arg); - void (*irq_preinstall) (struct drm_device *dev); - int (*irq_postinstall) (struct drm_device *dev); - void (*irq_uninstall) (struct drm_device *dev); - - /* Master routines */ - int (*master_create)(struct drm_device *dev, struct drm_master *master); - void (*master_destroy)(struct drm_device *dev, struct drm_master *master); - /** - * master_set is called whenever the minor master is set. - * master_drop is called whenever the minor master is dropped. - */ - - int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, - bool from_open); - void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv); - - int (*debugfs_init)(struct drm_minor *minor); - void (*debugfs_cleanup)(struct drm_minor *minor); - - /** - * @gem_free_object: deconstructor for drm_gem_objects - * - * This is deprecated and should not be used by new drivers. Use - * @gem_free_object_unlocked instead. - */ - void (*gem_free_object) (struct drm_gem_object *obj); - - /** - * @gem_free_object_unlocked: deconstructor for drm_gem_objects - * - * This is for drivers which are not encumbered with dev->struct_mutex - * legacy locking schemes. Use this hook instead of @gem_free_object. - */ - void (*gem_free_object_unlocked) (struct drm_gem_object *obj); - - int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); - void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); - - /** - * Hook for allocating the GEM object struct, for use by core - * helpers. - */ - struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, - size_t size); - - /* prime: */ - /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ - int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, - uint32_t handle, uint32_t flags, int *prime_fd); - /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */ - int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, - int prime_fd, uint32_t *handle); - /* export GEM -> dmabuf */ - struct dma_buf * (*gem_prime_export)(struct drm_device *dev, - struct drm_gem_object *obj, int flags); - /* import dmabuf -> GEM */ - struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, - struct dma_buf *dma_buf); - /* low-level interface used by drm_gem_prime_{import,export} */ - int (*gem_prime_pin)(struct drm_gem_object *obj); - void (*gem_prime_unpin)(struct drm_gem_object *obj); - struct reservation_object * (*gem_prime_res_obj)( - struct drm_gem_object *obj); - struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj); - struct drm_gem_object *(*gem_prime_import_sg_table)( - struct drm_device *dev, - struct dma_buf_attachment *attach, - struct sg_table *sgt); - void *(*gem_prime_vmap)(struct drm_gem_object *obj); - void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr); - int (*gem_prime_mmap)(struct drm_gem_object *obj, - struct vm_area_struct *vma); - - /* vga arb irq handler */ - void (*vgaarb_irq)(struct drm_device *dev, bool state); - - /* dumb alloc support */ - int (*dumb_create)(struct drm_file *file_priv, - struct drm_device *dev, - struct drm_mode_create_dumb *args); - int (*dumb_map_offset)(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, - uint64_t *offset); - int (*dumb_destroy)(struct drm_file *file_priv, - struct drm_device *dev, - uint32_t handle); - - /* Driver private ops for this object */ - const struct vm_operations_struct *gem_vm_ops; - - int major; - int minor; - int patchlevel; - char *name; - char *desc; - char *date; - - u32 driver_features; - int dev_priv_size; - const struct drm_ioctl_desc *ioctls; - int num_ioctls; - const struct file_operations *fops; - - /* List of devices hanging off this driver with stealth attach. */ - struct list_head legacy_dev_list; -}; - enum drm_minor_type { DRM_MINOR_PRIMARY, DRM_MINOR_CONTROL, @@ -1011,11 +731,6 @@ void drm_clflush_virt_range(void *addr, unsigned long length); extern void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe); extern void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe); -/* drm_drv.c */ -void drm_put_dev(struct drm_device *dev); -void drm_unplug_dev(struct drm_device *dev); -extern unsigned int drm_debug; - /* Debugfs support */ #if defined(CONFIG_DEBUG_FS) extern int drm_debugfs_create_files(const struct drm_info_list *files, @@ -1068,18 +783,6 @@ extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); extern void drm_sysfs_hotplug_event(struct drm_device *dev); -struct drm_device *drm_dev_alloc(struct drm_driver *driver, - struct device *parent); -int drm_dev_init(struct drm_device *dev, - struct drm_driver *driver, - struct device *parent); -void drm_dev_ref(struct drm_device *dev); -void drm_dev_unref(struct drm_device *dev); -int drm_dev_register(struct drm_device *dev, unsigned long flags); -void drm_dev_unregister(struct drm_device *dev); - -struct drm_minor *drm_minor_acquire(unsigned int minor_id); -void drm_minor_release(struct drm_minor *minor); /*@}*/ diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h new file mode 100644 index 0000000000000..0faf5ec72d196 --- /dev/null +++ b/include/drm/drm_drv.h @@ -0,0 +1,340 @@ +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * Copyright 2016 Intel Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _DRM_DRV_H_ +#define _DRM_DRV_H_ + +#include +#include + +struct drm_device; +struct drm_file; +struct drm_gem_object; +struct drm_master; +struct drm_minor; +struct dma_buf_attachment; +struct drm_display_mode; +struct drm_mode_create_dumb; + +/* driver capabilities and requirements mask */ +#define DRIVER_USE_AGP 0x1 +#define DRIVER_LEGACY 0x2 +#define DRIVER_PCI_DMA 0x8 +#define DRIVER_SG 0x10 +#define DRIVER_HAVE_DMA 0x20 +#define DRIVER_HAVE_IRQ 0x40 +#define DRIVER_IRQ_SHARED 0x80 +#define DRIVER_GEM 0x1000 +#define DRIVER_MODESET 0x2000 +#define DRIVER_PRIME 0x4000 +#define DRIVER_RENDER 0x8000 +#define DRIVER_ATOMIC 0x10000 +#define DRIVER_KMS_LEGACY_CONTEXT 0x20000 + +/** + * struct drm_driver - DRM driver structure + * + * This structure represent the common code for a family of cards. There will + * one drm_device for each card present in this family. It contains lots of + * vfunc entries, and a pile of those probably should be moved to more + * appropriate places like &drm_mode_config_funcs or into a new operations + * structure for GEM drivers. + */ +struct drm_driver { + int (*load) (struct drm_device *, unsigned long flags); + int (*firstopen) (struct drm_device *); + int (*open) (struct drm_device *, struct drm_file *); + void (*preclose) (struct drm_device *, struct drm_file *file_priv); + void (*postclose) (struct drm_device *, struct drm_file *); + void (*lastclose) (struct drm_device *); + int (*unload) (struct drm_device *); + int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); + int (*dma_quiescent) (struct drm_device *); + int (*context_dtor) (struct drm_device *dev, int context); + int (*set_busid)(struct drm_device *dev, struct drm_master *master); + + /** + * get_vblank_counter - get raw hardware vblank counter + * @dev: DRM device + * @pipe: counter to fetch + * + * Driver callback for fetching a raw hardware vblank counter for @crtc. + * If a device doesn't have a hardware counter, the driver can simply + * use drm_vblank_no_hw_counter() function. The DRM core will account for + * missed vblank events while interrupts where disabled based on system + * timestamps. + * + * Wraparound handling and loss of events due to modesetting is dealt + * with in the DRM core code. + * + * RETURNS + * Raw vblank counter value. + */ + u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe); + + /** + * enable_vblank - enable vblank interrupt events + * @dev: DRM device + * @pipe: which irq to enable + * + * Enable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, the driver should use the + * drm_vblank_no_hw_counter() function that keeps a virtual counter. + * + * RETURNS + * Zero on success, appropriate errno if the given @crtc's vblank + * interrupt cannot be enabled. + */ + int (*enable_vblank) (struct drm_device *dev, unsigned int pipe); + + /** + * disable_vblank - disable vblank interrupt events + * @dev: DRM device + * @pipe: which irq to enable + * + * Disable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, the driver should use the + * drm_vblank_no_hw_counter() function that keeps a virtual counter. + */ + void (*disable_vblank) (struct drm_device *dev, unsigned int pipe); + + /** + * Called by \c drm_device_is_agp. Typically used to determine if a + * card is really attached to AGP or not. + * + * \param dev DRM device handle + * + * \returns + * One of three values is returned depending on whether or not the + * card is absolutely \b not AGP (return of 0), absolutely \b is AGP + * (return of 1), or may or may not be AGP (return of 2). + */ + int (*device_is_agp) (struct drm_device *dev); + + /** + * Called by vblank timestamping code. + * + * Return the current display scanout position from a crtc, and an + * optional accurate ktime_get timestamp of when position was measured. + * + * \param dev DRM device. + * \param pipe Id of the crtc to query. + * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). + * \param *vpos Target location for current vertical scanout position. + * \param *hpos Target location for current horizontal scanout position. + * \param *stime Target location for timestamp taken immediately before + * scanout position query. Can be NULL to skip timestamp. + * \param *etime Target location for timestamp taken immediately after + * scanout position query. Can be NULL to skip timestamp. + * \param mode Current display timings. + * + * Returns vpos as a positive number while in active scanout area. + * Returns vpos as a negative number inside vblank, counting the number + * of scanlines to go until end of vblank, e.g., -1 means "one scanline + * until start of active scanout / end of vblank." + * + * \return Flags, or'ed together as follows: + * + * DRM_SCANOUTPOS_VALID = Query successful. + * DRM_SCANOUTPOS_INVBL = Inside vblank. + * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of + * this flag means that returned position may be offset by a constant + * but unknown small number of scanlines wrt. real scanout position. + * + */ + int (*get_scanout_position) (struct drm_device *dev, unsigned int pipe, + unsigned int flags, int *vpos, int *hpos, + ktime_t *stime, ktime_t *etime, + const struct drm_display_mode *mode); + + /** + * Called by \c drm_get_last_vbltimestamp. Should return a precise + * timestamp when the most recent VBLANK interval ended or will end. + * + * Specifically, the timestamp in @vblank_time should correspond as + * closely as possible to the time when the first video scanline of + * the video frame after the end of VBLANK will start scanning out, + * the time immediately after end of the VBLANK interval. If the + * @crtc is currently inside VBLANK, this will be a time in the future. + * If the @crtc is currently scanning out a frame, this will be the + * past start time of the current scanout. This is meant to adhere + * to the OpenML OML_sync_control extension specification. + * + * \param dev dev DRM device handle. + * \param pipe crtc for which timestamp should be returned. + * \param *max_error Maximum allowable timestamp error in nanoseconds. + * Implementation should strive to provide timestamp + * with an error of at most *max_error nanoseconds. + * Returns true upper bound on error for timestamp. + * \param *vblank_time Target location for returned vblank timestamp. + * \param flags 0 = Defaults, no special treatment needed. + * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank + * irq handler. Some drivers need to apply some workarounds + * for gpu-specific vblank irq quirks if flag is set. + * + * \returns + * Zero if timestamping isn't supported in current display mode or a + * negative number on failure. A positive status code on success, + * which describes how the vblank_time timestamp was computed. + */ + int (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe, + int *max_error, + struct timeval *vblank_time, + unsigned flags); + + /* these have to be filled in */ + + irqreturn_t(*irq_handler) (int irq, void *arg); + void (*irq_preinstall) (struct drm_device *dev); + int (*irq_postinstall) (struct drm_device *dev); + void (*irq_uninstall) (struct drm_device *dev); + + /* Master routines */ + int (*master_create)(struct drm_device *dev, struct drm_master *master); + void (*master_destroy)(struct drm_device *dev, struct drm_master *master); + /** + * master_set is called whenever the minor master is set. + * master_drop is called whenever the minor master is dropped. + */ + + int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, + bool from_open); + void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv); + + int (*debugfs_init)(struct drm_minor *minor); + void (*debugfs_cleanup)(struct drm_minor *minor); + + /** + * @gem_free_object: deconstructor for drm_gem_objects + * + * This is deprecated and should not be used by new drivers. Use + * @gem_free_object_unlocked instead. + */ + void (*gem_free_object) (struct drm_gem_object *obj); + + /** + * @gem_free_object_unlocked: deconstructor for drm_gem_objects + * + * This is for drivers which are not encumbered with dev->struct_mutex + * legacy locking schemes. Use this hook instead of @gem_free_object. + */ + void (*gem_free_object_unlocked) (struct drm_gem_object *obj); + + int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); + void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); + + /** + * Hook for allocating the GEM object struct, for use by core + * helpers. + */ + struct drm_gem_object *(*gem_create_object)(struct drm_device *dev, + size_t size); + + /* prime: */ + /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ + int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, + uint32_t handle, uint32_t flags, int *prime_fd); + /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */ + int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, + int prime_fd, uint32_t *handle); + /* export GEM -> dmabuf */ + struct dma_buf * (*gem_prime_export)(struct drm_device *dev, + struct drm_gem_object *obj, int flags); + /* import dmabuf -> GEM */ + struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, + struct dma_buf *dma_buf); + /* low-level interface used by drm_gem_prime_{import,export} */ + int (*gem_prime_pin)(struct drm_gem_object *obj); + void (*gem_prime_unpin)(struct drm_gem_object *obj); + struct reservation_object * (*gem_prime_res_obj)( + struct drm_gem_object *obj); + struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj); + struct drm_gem_object *(*gem_prime_import_sg_table)( + struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt); + void *(*gem_prime_vmap)(struct drm_gem_object *obj); + void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr); + int (*gem_prime_mmap)(struct drm_gem_object *obj, + struct vm_area_struct *vma); + + /* vga arb irq handler */ + void (*vgaarb_irq)(struct drm_device *dev, bool state); + + /* dumb alloc support */ + int (*dumb_create)(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); + int (*dumb_map_offset)(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset); + int (*dumb_destroy)(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle); + + /* Driver private ops for this object */ + const struct vm_operations_struct *gem_vm_ops; + + int major; + int minor; + int patchlevel; + char *name; + char *desc; + char *date; + + u32 driver_features; + int dev_priv_size; + const struct drm_ioctl_desc *ioctls; + int num_ioctls; + const struct file_operations *fops; + + /* List of devices hanging off this driver with stealth attach. */ + struct list_head legacy_dev_list; +}; + +extern __printf(6, 7) +void drm_dev_printk(const struct device *dev, const char *level, + unsigned int category, const char *function_name, + const char *prefix, const char *format, ...); +extern __printf(3, 4) +void drm_printk(const char *level, unsigned int category, + const char *format, ...); +extern unsigned int drm_debug; + +int drm_dev_init(struct drm_device *dev, + struct drm_driver *driver, + struct device *parent); +struct drm_device *drm_dev_alloc(struct drm_driver *driver, + struct device *parent); +int drm_dev_register(struct drm_device *dev, unsigned long flags); +void drm_dev_unregister(struct drm_device *dev); + +void drm_dev_ref(struct drm_device *dev); +void drm_dev_unref(struct drm_device *dev); +void drm_put_dev(struct drm_device *dev); +void drm_unplug_dev(struct drm_device *dev); + +#endif From 6c4789edc55d5a0acefc85380d7a3f7c4f21c7cd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:20 +0100 Subject: [PATCH 33/51] drm: Clean up kerneldoc for struct drm_driver Just cleans up what's there, still plenty missing. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-6-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-internals.rst | 3 + include/drm/drm_drv.h | 168 ++++++++++++++++++---------- 2 files changed, 109 insertions(+), 62 deletions(-) diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 25ee92c5df65c..a54ac97510b35 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -143,6 +143,9 @@ Device Instance and Driver Handling .. kernel-doc:: drivers/gpu/drm/drm_drv.c :export: +.. kernel-doc:: include/drm/drm_drv.h + :internal: + Driver Load ----------- diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 0faf5ec72d196..048086e38ef68 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -77,92 +77,110 @@ struct drm_driver { int (*set_busid)(struct drm_device *dev, struct drm_master *master); /** - * get_vblank_counter - get raw hardware vblank counter - * @dev: DRM device - * @pipe: counter to fetch + * @get_vblank_counter: * - * Driver callback for fetching a raw hardware vblank counter for @crtc. - * If a device doesn't have a hardware counter, the driver can simply - * use drm_vblank_no_hw_counter() function. The DRM core will account for + * Driver callback for fetching a raw hardware vblank counter for the + * CRTC specified with the pipe argument. If a device doesn't have a + * hardware counter, the driver can simply use + * drm_vblank_no_hw_counter() function. The DRM core will account for * missed vblank events while interrupts where disabled based on system * timestamps. * * Wraparound handling and loss of events due to modesetting is dealt - * with in the DRM core code. + * with in the DRM core code, as long as drivers call + * drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or + * enabling a CRTC. + * + * Returns: * - * RETURNS * Raw vblank counter value. */ u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe); /** - * enable_vblank - enable vblank interrupt events - * @dev: DRM device - * @pipe: which irq to enable + * @enable_vblank: + * + * Enable vblank interrupts for the CRTC specified with the pipe + * argument. * - * Enable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, the driver should use the - * drm_vblank_no_hw_counter() function that keeps a virtual counter. + * Returns: * - * RETURNS * Zero on success, appropriate errno if the given @crtc's vblank * interrupt cannot be enabled. */ int (*enable_vblank) (struct drm_device *dev, unsigned int pipe); /** - * disable_vblank - disable vblank interrupt events - * @dev: DRM device - * @pipe: which irq to enable + * @disable_vblank: * - * Disable vblank interrupts for @crtc. If the device doesn't have - * a hardware vblank counter, the driver should use the - * drm_vblank_no_hw_counter() function that keeps a virtual counter. + * Disable vblank interrupts for the CRTC specified with the pipe + * argument. */ void (*disable_vblank) (struct drm_device *dev, unsigned int pipe); /** - * Called by \c drm_device_is_agp. Typically used to determine if a - * card is really attached to AGP or not. + * @device_is_agp: + * + * Called by drm_device_is_agp(). Typically used to determine if a card + * is really attached to AGP or not. * - * \param dev DRM device handle + * Returns: * - * \returns * One of three values is returned depending on whether or not the - * card is absolutely \b not AGP (return of 0), absolutely \b is AGP + * card is absolutely not AGP (return of 0), absolutely is AGP * (return of 1), or may or may not be AGP (return of 2). */ int (*device_is_agp) (struct drm_device *dev); /** + * @get_scanout_position: + * * Called by vblank timestamping code. * - * Return the current display scanout position from a crtc, and an - * optional accurate ktime_get timestamp of when position was measured. + * Returns the current display scanout position from a crtc, and an + * optional accurate ktime_get() timestamp of when position was + * measured. Note that this is a helper callback which is only used if a + * driver uses drm_calc_vbltimestamp_from_scanoutpos() for the + * @get_vblank_timestamp callback. + * + * Parameters: * - * \param dev DRM device. - * \param pipe Id of the crtc to query. - * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). - * \param *vpos Target location for current vertical scanout position. - * \param *hpos Target location for current horizontal scanout position. - * \param *stime Target location for timestamp taken immediately before - * scanout position query. Can be NULL to skip timestamp. - * \param *etime Target location for timestamp taken immediately after - * scanout position query. Can be NULL to skip timestamp. - * \param mode Current display timings. + * dev: + * DRM device. + * pipe: + * Id of the crtc to query. + * flags: + * Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0). + * vpos: + * Target location for current vertical scanout position. + * hpos: + * Target location for current horizontal scanout position. + * stime: + * Target location for timestamp taken immediately before + * scanout position query. Can be NULL to skip timestamp. + * etime: + * Target location for timestamp taken immediately after + * scanout position query. Can be NULL to skip timestamp. + * mode: + * Current display timings. * * Returns vpos as a positive number while in active scanout area. * Returns vpos as a negative number inside vblank, counting the number * of scanlines to go until end of vblank, e.g., -1 means "one scanline * until start of active scanout / end of vblank." * - * \return Flags, or'ed together as follows: + * Returns: + * + * Flags, or'ed together as follows: * - * DRM_SCANOUTPOS_VALID = Query successful. - * DRM_SCANOUTPOS_INVBL = Inside vblank. - * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of - * this flag means that returned position may be offset by a constant - * but unknown small number of scanlines wrt. real scanout position. + * DRM_SCANOUTPOS_VALID: + * Query successful. + * DRM_SCANOUTPOS_INVBL: + * Inside vblank. + * DRM_SCANOUTPOS_ACCURATE: Returned position is accurate. A lack of + * this flag means that returned position may be offset by a + * constant but unknown small number of scanlines wrt. real scanout + * position. * */ int (*get_scanout_position) (struct drm_device *dev, unsigned int pipe, @@ -171,7 +189,9 @@ struct drm_driver { const struct drm_display_mode *mode); /** - * Called by \c drm_get_last_vbltimestamp. Should return a precise + * @get_vblank_timestamp: + * + * Called by drm_get_last_vbltimestamp(). Should return a precise * timestamp when the most recent VBLANK interval ended or will end. * * Specifically, the timestamp in @vblank_time should correspond as @@ -183,19 +203,27 @@ struct drm_driver { * past start time of the current scanout. This is meant to adhere * to the OpenML OML_sync_control extension specification. * - * \param dev dev DRM device handle. - * \param pipe crtc for which timestamp should be returned. - * \param *max_error Maximum allowable timestamp error in nanoseconds. - * Implementation should strive to provide timestamp - * with an error of at most *max_error nanoseconds. - * Returns true upper bound on error for timestamp. - * \param *vblank_time Target location for returned vblank timestamp. - * \param flags 0 = Defaults, no special treatment needed. - * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank - * irq handler. Some drivers need to apply some workarounds - * for gpu-specific vblank irq quirks if flag is set. - * - * \returns + * Paramters: + * + * dev: + * dev DRM device handle. + * pipe: + * crtc for which timestamp should be returned. + * max_error: + * Maximum allowable timestamp error in nanoseconds. + * Implementation should strive to provide timestamp + * with an error of at most max_error nanoseconds. + * Returns true upper bound on error for timestamp. + * vblank_time: + * Target location for returned vblank timestamp. + * flags: + * 0 = Defaults, no special treatment needed. + * DRM_CALLED_FROM_VBLIRQ = Function is called from vblank + * irq handler. Some drivers need to apply some workarounds + * for gpu-specific vblank irq quirks if flag is set. + * + * Returns: + * * Zero if timestamping isn't supported in current display mode or a * negative number on failure. A positive status code on success, * which describes how the vblank_time timestamp was computed. @@ -212,16 +240,32 @@ struct drm_driver { int (*irq_postinstall) (struct drm_device *dev); void (*irq_uninstall) (struct drm_device *dev); - /* Master routines */ + /** + * @master_create: + * + * Called whenever a new master is created. Only used by vmwgfx. + */ int (*master_create)(struct drm_device *dev, struct drm_master *master); - void (*master_destroy)(struct drm_device *dev, struct drm_master *master); + /** - * master_set is called whenever the minor master is set. - * master_drop is called whenever the minor master is dropped. + * @master_destroy: + * + * Called whenever a master is destroyed. Only used by vmwgfx. */ + void (*master_destroy)(struct drm_device *dev, struct drm_master *master); + /** + * @master_set: + * + * Called whenever the minor master is set. Only used by vmwgfx. + */ int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, bool from_open); + /** + * @master_drop: + * + * Called whenever the minor master is dropped. Only used by vmwgfx. + */ void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv); int (*debugfs_init)(struct drm_minor *minor); From 4f93624ee7c05d5a8da77934a8a9e0e64e121ae6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:21 +0100 Subject: [PATCH 34/51] drm: Consolidate dumb buffer docs Put the callback docs into struct drm_driver, and the small overview into a DOC comment. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-7-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 42 ++------------------------ drivers/gpu/drm/drm_dumb_buffers.c | 46 +++++++++++----------------- include/drm/drm_drv.h | 48 +++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 69 deletions(-) diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index cb0d3537b7059..4edfb6d912501 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -72,46 +72,8 @@ DRM Format Handling Dumb Buffer Objects =================== -The KMS API doesn't standardize backing storage object creation and -leaves it to driver-specific ioctls. Furthermore actually creating a -buffer object even for GEM-based drivers is done through a -driver-specific ioctl - GEM only has a common userspace interface for -sharing and destroying objects. While not an issue for full-fledged -graphics stacks that include device-specific userspace components (in -libdrm for instance), this limit makes DRM-based early boot graphics -unnecessarily complex. - -Dumb objects partly alleviate the problem by providing a standard API to -create dumb buffers suitable for scanout, which can then be used to -create KMS frame buffers. - -To support dumb objects drivers must implement the dumb_create, -dumb_destroy and dumb_map_offset operations. - -- int (\*dumb_create)(struct drm_file \*file_priv, struct - drm_device \*dev, struct drm_mode_create_dumb \*args); - The dumb_create operation creates a driver object (GEM or TTM - handle) suitable for scanout based on the width, height and depth - from the struct :c:type:`struct drm_mode_create_dumb - ` argument. It fills the argument's - handle, pitch and size fields with a handle for the newly created - object and its line pitch and size in bytes. - -- int (\*dumb_destroy)(struct drm_file \*file_priv, struct - drm_device \*dev, uint32_t handle); - The dumb_destroy operation destroys a dumb object created by - dumb_create. - -- int (\*dumb_map_offset)(struct drm_file \*file_priv, struct - drm_device \*dev, uint32_t handle, uint64_t \*offset); - The dumb_map_offset operation associates an mmap fake offset with - the object given by the handle and returns it. Drivers must use the - :c:func:`drm_gem_create_mmap_offset()` function to associate - the fake offset as described in ?. - -Note that dumb objects may not be used for gpu acceleration, as has been -attempted on some ARM embedded platforms. Such drivers really must have -a hardware-specific ioctl to allocate suitable buffer objects. +.. kernel-doc:: drivers/gpu/drm/drm_dumb_buffers.c + :doc: overview Plane Abstraction ================= diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c index cd291b538f5aa..8ac5a1c1d8111 100644 --- a/drivers/gpu/drm/drm_dumb_buffers.c +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -28,24 +28,29 @@ #include "drm_crtc_internal.h" /** - * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info + * DOC: overview * - * This creates a new dumb buffer in the driver's backing storage manager (GEM, - * TTM or something else entirely) and returns the resulting buffer handle. This - * handle can then be wrapped up into a framebuffer modeset object. + * The KMS API doesn't standardize backing storage object creation and leaves it + * to driver-specific ioctls. Furthermore actually creating a buffer object even + * for GEM-based drivers is done through a driver-specific ioctl - GEM only has + * a common userspace interface for sharing and destroying objects. While not an + * issue for full-fledged graphics stacks that include device-specific userspace + * components (in libdrm for instance), this limit makes DRM-based early boot + * graphics unnecessarily complex. * - * Note that userspace is not allowed to use such objects for render - * acceleration - drivers must create their own private ioctls for such a use - * case. + * Dumb objects partly alleviate the problem by providing a standard API to + * create dumb buffers suitable for scanout, which can then be used to create + * KMS frame buffers. * - * Called by the user via ioctl. + * To support dumb objects drivers must implement the dumb_create, + * dumb_destroy and dumb_map_offset operations from struct &drm_driver. See + * there for further details. * - * Returns: - * Zero on success, negative errno on failure. + * Note that dumb objects may not be used for gpu acceleration, as has been + * attempted on some ARM embedded platforms. Such drivers really must have + * a hardware-specific ioctl to allocate suitable buffer objects. */ + int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -110,21 +115,6 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); } -/** - * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer - * @dev: DRM device - * @data: ioctl data - * @file_priv: DRM file info - * - * This destroys the userspace handle for the given dumb backing storage buffer. - * Since buffer objects must be reference counted in the kernel a buffer object - * won't be immediately freed if a framebuffer modeset object still uses it. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 048086e38ef68..aad8bbacd1f0f 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -328,13 +328,59 @@ struct drm_driver { /* vga arb irq handler */ void (*vgaarb_irq)(struct drm_device *dev, bool state); - /* dumb alloc support */ + /** + * @dumb_create: + * + * This creates a new dumb buffer in the driver's backing storage manager (GEM, + * TTM or something else entirely) and returns the resulting buffer handle. This + * handle can then be wrapped up into a framebuffer modeset object. + * + * Note that userspace is not allowed to use such objects for render + * acceleration - drivers must create their own private ioctls for such a use + * case. + * + * Width, height and depth are specified in the &drm_mode_create_dumb + * argument. The callback needs to fill the handle, pitch and size for + * the created buffer. + * + * Called by the user via ioctl. + * + * Returns: + * + * Zero on success, negative errno on failure. + */ int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); + /** + * @dumb_map_offset: + * + * Allocate an offset in the drm device node's address space to be able to + * memory map a dumb buffer. GEM-based drivers must use + * drm_gem_create_mmap_offset() to implement this. + * + * Called by the user via ioctl. + * + * Returns: + * + * Zero on success, negative errno on failure. + */ int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *offset); + /** + * @dumb_destroy: + * + * This destroys the userspace handle for the given dumb backing storage buffer. + * Since buffer objects must be reference counted in the kernel a buffer object + * won't be immediately freed if a framebuffer modeset object still uses it. + * + * Called by the user via ioctl. + * + * Returns: + * + * Zero on success, negative errno on failure. + */ int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle); From 2d5e836de7b24fa79c67085689ee8160302c76a9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:22 +0100 Subject: [PATCH 35/51] drm/print: Move kerneldoc next to definition kerneldoc expects the comment next to definitions, otherwise it can't pick up exported vs. internal stuff. This fixes a warning from the doc build done with: $ make DOCBOOKS="" htmldocs Fixes: d8187177b0b1 ("drm: add helper for printing to log or seq_file") Cc: Rob Clark Cc: Sean Paul Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-8-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-internals.rst | 2 +- drivers/gpu/drm/drm_print.c | 5 +++++ include/drm/drm_print.h | 5 ----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index a54ac97510b35..e35920db1f4cd 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -366,7 +366,7 @@ Printer .. kernel-doc:: include/drm/drm_print.h :internal: -.. kernel-doc:: include/drm/drm_print.h +.. kernel-doc:: drivers/gpu/drm/drm_print.c :export: diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 34eb85618b76a..ad3caaa1f48b6 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -40,6 +40,11 @@ void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf) } EXPORT_SYMBOL(__drm_printfn_info); +/** + * drm_printf - print to a &drm_printer stream + * @p: the &drm_printer + * @f: format string + */ void drm_printf(struct drm_printer *p, const char *f, ...) { struct va_format vaf; diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 475ffe3730e97..1adf84aea622b 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -74,11 +74,6 @@ struct drm_printer { void __drm_printfn_seq_file(struct drm_printer *p, struct va_format *vaf); void __drm_printfn_info(struct drm_printer *p, struct va_format *vaf); -/** - * drm_printf - print to a &drm_printer stream - * @p: the &drm_printer - * @f: format string - */ void drm_printf(struct drm_printer *p, const char *f, ...); From 7920232d54d97a35dbafc65cc6f6ffeefe9ecbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 3 Nov 2016 14:31:43 +0200 Subject: [PATCH 36/51] Revert "drm: Add and handle new aspect ratios in DRM layer" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a68362fe3e84fcbedd49939aa200519aa5410135. Adding new mode flags willy nilly breaks existing userspace. We need to coordinate this better, potentially with a new client cap that only exposes the aspect ratio flags when userspace is prepared for them (similar to what we do with stereo 3D modes). Cc: Shashank Sharma Cc: Lin, Jia Cc: Akashdeep Sharma Cc: Jim Bride Cc: Jose Abreu Cc: Daniel Vetter Cc: Emil Velikov Cc: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478176304-6743-1-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_modes.c | 12 ------------ include/uapi/drm/drm_mode.h | 6 ------ 2 files changed, 18 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ce6eeda02acfa..e82298e4c25b0 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1507,12 +1507,6 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, case HDMI_PICTURE_ASPECT_16_9: out->flags |= DRM_MODE_FLAG_PIC_AR_16_9; break; - case HDMI_PICTURE_ASPECT_64_27: - out->flags |= DRM_MODE_FLAG_PIC_AR_64_27; - break; - case DRM_MODE_PICTURE_ASPECT_256_135: - out->flags |= DRM_MODE_FLAG_PIC_AR_256_135; - break; case HDMI_PICTURE_ASPECT_RESERVED: default: out->flags |= DRM_MODE_FLAG_PIC_AR_NONE; @@ -1574,12 +1568,6 @@ int drm_mode_convert_umode(struct drm_display_mode *out, case DRM_MODE_FLAG_PIC_AR_16_9: out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_16_9; break; - case DRM_MODE_FLAG_PIC_AR_64_27: - out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_64_27; - break; - case DRM_MODE_FLAG_PIC_AR_256_135: - out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_256_135; - break; default: out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; break; diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 01000c9f7c2cf..ebf622f5b2380 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -89,8 +89,6 @@ extern "C" { #define DRM_MODE_PICTURE_ASPECT_NONE 0 #define DRM_MODE_PICTURE_ASPECT_4_3 1 #define DRM_MODE_PICTURE_ASPECT_16_9 2 -#define DRM_MODE_PICTURE_ASPECT_64_27 3 -#define DRM_MODE_PICTURE_ASPECT_256_135 4 /* Aspect ratio flag bitmask (4 bits 22:19) */ #define DRM_MODE_FLAG_PIC_AR_MASK (0x0F<<19) @@ -100,10 +98,6 @@ extern "C" { (DRM_MODE_PICTURE_ASPECT_4_3<<19) #define DRM_MODE_FLAG_PIC_AR_16_9 \ (DRM_MODE_PICTURE_ASPECT_16_9<<19) -#define DRM_MODE_FLAG_PIC_AR_64_27 \ - (DRM_MODE_PICTURE_ASPECT_64_27<<19) -#define DRM_MODE_FLAG_PIC_AR_256_135 \ - (DRM_MODE_PICTURE_ASPECT_256_135<<19) /* DPMS flags */ /* bit compatible with the xorg definitions. */ From 83113df5a74df8718e43e0b2388d0c3a9a7fda52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 3 Nov 2016 14:31:44 +0200 Subject: [PATCH 37/51] Revert "drm: Add aspect ratio parsing in DRM layer" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6dffd431e2296cda08e7e4f0242e02df1d1698cd. Adding new mode flags willy nilly breaks existing userspace. We need to coordinate this better, potentially with a new client cap that only exposes the aspect ratio flags when userspace is prepared for them (similar to what we do with stereo 3D modes). This also broke things so that we would always send out VIC==0 in the AVI infoframe unless the user specified an aspect ratio via the mode flags. And the automagic RGB full vs. limited range handling was similartly broken as the user mode would never match any CEA mode. Cc: Shashank Sharma Cc: Lin, Jia Cc: Akashdeep Sharma Cc: Jim Bride Cc: Jose Abreu Cc: Daniel Vetter Cc: Emil Velikov Cc: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1478176304-6743-2-git-send-email-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_modes.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index e82298e4c25b0..ac6a35212501e 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -995,7 +995,6 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, mode1->vsync_end == mode2->vsync_end && mode1->vtotal == mode2->vtotal && mode1->vscan == mode2->vscan && - mode1->picture_aspect_ratio == mode2->picture_aspect_ratio && (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) == (mode2->flags & ~DRM_MODE_FLAG_3D_MASK)) return true; @@ -1498,21 +1497,6 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, out->vrefresh = in->vrefresh; out->flags = in->flags; out->type = in->type; - out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; - - switch (in->picture_aspect_ratio) { - case HDMI_PICTURE_ASPECT_4_3: - out->flags |= DRM_MODE_FLAG_PIC_AR_4_3; - break; - case HDMI_PICTURE_ASPECT_16_9: - out->flags |= DRM_MODE_FLAG_PIC_AR_16_9; - break; - case HDMI_PICTURE_ASPECT_RESERVED: - default: - out->flags |= DRM_MODE_FLAG_PIC_AR_NONE; - break; - } - strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } @@ -1558,21 +1542,6 @@ int drm_mode_convert_umode(struct drm_display_mode *out, strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; - /* Clearing picture aspect ratio bits from out flags */ - out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK; - - switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) { - case DRM_MODE_FLAG_PIC_AR_4_3: - out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_4_3; - break; - case DRM_MODE_FLAG_PIC_AR_16_9: - out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_16_9; - break; - default: - out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; - break; - } - out->status = drm_mode_validate_basic(out); if (out->status != MODE_OK) goto out; From 28575f165d36051310d7ea2350e2011f8095b6fb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:23 +0100 Subject: [PATCH 38/51] drm: Extract drm_mode_config.[hc] And shuffle the kernel-doc structure a bit since drm_crtc.[hc] now only contains CRTC-related functions and structures. v2: - rebase onto drm-misc - don't forget to move drm_mode_config_cleanup. - move 2 internal decls under the right heading (Chris) Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- Documentation/gpu/drm-kms.rst | 32 +- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_crtc.c | 462 +------------------- drivers/gpu/drm/drm_crtc_internal.h | 22 +- drivers/gpu/drm/drm_mode_config.c | 482 ++++++++++++++++++++ include/drm/drm_crtc.h | 616 +------------------------- include/drm/drm_mode_config.h | 652 ++++++++++++++++++++++++++++ 7 files changed, 1172 insertions(+), 1096 deletions(-) create mode 100644 drivers/gpu/drm/drm_mode_config.c create mode 100644 include/drm/drm_mode_config.h diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 4edfb6d912501..a8ff2c87c0e9b 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -15,25 +15,24 @@ be setup by initializing the following fields. - struct drm_mode_config_funcs \*funcs; Mode setting functions. -Modeset Base Object Abstraction -=============================== +Mode Configuration -.. kernel-doc:: include/drm/drm_mode_object.h - :internal: +KMS Core Structures and Functions +================================= -.. kernel-doc:: drivers/gpu/drm/drm_mode_object.c +.. kernel-doc:: drivers/gpu/drm/drm_mode_config.c :export: -KMS Data Structures -=================== - -.. kernel-doc:: include/drm/drm_crtc.h +.. kernel-doc:: include/drm/drm_mode_config.h :internal: -KMS API Functions -================= +Modeset Base Object Abstraction +=============================== -.. kernel-doc:: drivers/gpu/drm/drm_crtc.c +.. kernel-doc:: include/drm/drm_mode_object.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_mode_object.c :export: Atomic Mode Setting Function Reference @@ -45,6 +44,15 @@ Atomic Mode Setting Function Reference .. kernel-doc:: include/drm/drm_atomic.h :internal: +CRTC Abstraction +================ + +.. kernel-doc:: drivers/gpu/drm/drm_crtc.c + :export: + +.. kernel-doc:: include/drm/drm_crtc.h + :internal: + Frame Buffer Abstraction ======================== diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index adcfc8f922e36..883f3e75cfbc4 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -16,7 +16,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ drm_framebuffer.o drm_connector.o drm_blend.o \ drm_encoder.o drm_mode_object.o drm_property.o \ drm_plane.o drm_color_mgmt.o drm_print.o \ - drm_dumb_buffers.o + drm_dumb_buffers.o drm_mode_config.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b0827634af18b..239b64c85098a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -45,18 +45,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -/* - * Global properties - */ -static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { - { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, - { DRM_PLANE_TYPE_PRIMARY, "Primary" }, - { DRM_PLANE_TYPE_CURSOR, "Cursor" }, -}; - -/* - * Optional properties - */ /** * drm_crtc_force_disable - Forcibly turn off a CRTC * @crtc: CRTC to turn off @@ -114,7 +102,7 @@ static unsigned int drm_num_crtcs(struct drm_device *dev) return num; } -static int drm_crtc_register_all(struct drm_device *dev) +int drm_crtc_register_all(struct drm_device *dev) { struct drm_crtc *crtc; int ret = 0; @@ -133,7 +121,7 @@ static int drm_crtc_register_all(struct drm_device *dev) return 0; } -static void drm_crtc_unregister_all(struct drm_device *dev) +void drm_crtc_unregister_all(struct drm_device *dev) { struct drm_crtc *crtc; @@ -285,301 +273,6 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); -int drm_modeset_register_all(struct drm_device *dev) -{ - int ret; - - ret = drm_plane_register_all(dev); - if (ret) - goto err_plane; - - ret = drm_crtc_register_all(dev); - if (ret) - goto err_crtc; - - ret = drm_encoder_register_all(dev); - if (ret) - goto err_encoder; - - ret = drm_connector_register_all(dev); - if (ret) - goto err_connector; - - return 0; - -err_connector: - drm_encoder_unregister_all(dev); -err_encoder: - drm_crtc_unregister_all(dev); -err_crtc: - drm_plane_unregister_all(dev); -err_plane: - return ret; -} - -void drm_modeset_unregister_all(struct drm_device *dev) -{ - drm_connector_unregister_all(dev); - drm_encoder_unregister_all(dev); - drm_crtc_unregister_all(dev); - drm_plane_unregister_all(dev); -} - -static int drm_mode_create_standard_properties(struct drm_device *dev) -{ - struct drm_property *prop; - int ret; - - ret = drm_connector_create_standard_properties(dev); - if (ret) - return ret; - - prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, - "type", drm_plane_type_enum_list, - ARRAY_SIZE(drm_plane_type_enum_list)); - if (!prop) - return -ENOMEM; - dev->mode_config.plane_type_property = prop; - - prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, - "SRC_X", 0, UINT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_src_x = prop; - - prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, - "SRC_Y", 0, UINT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_src_y = prop; - - prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, - "SRC_W", 0, UINT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_src_w = prop; - - prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, - "SRC_H", 0, UINT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_src_h = prop; - - prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, - "CRTC_X", INT_MIN, INT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_crtc_x = prop; - - prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, - "CRTC_Y", INT_MIN, INT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_crtc_y = prop; - - prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, - "CRTC_W", 0, INT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_crtc_w = prop; - - prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, - "CRTC_H", 0, INT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_crtc_h = prop; - - prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, - "FB_ID", DRM_MODE_OBJECT_FB); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_fb_id = prop; - - prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, - "CRTC_ID", DRM_MODE_OBJECT_CRTC); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_crtc_id = prop; - - prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, - "ACTIVE"); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_active = prop; - - prop = drm_property_create(dev, - DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, - "MODE_ID", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.prop_mode_id = prop; - - prop = drm_property_create(dev, - DRM_MODE_PROP_BLOB, - "DEGAMMA_LUT", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.degamma_lut_property = prop; - - prop = drm_property_create_range(dev, - DRM_MODE_PROP_IMMUTABLE, - "DEGAMMA_LUT_SIZE", 0, UINT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.degamma_lut_size_property = prop; - - prop = drm_property_create(dev, - DRM_MODE_PROP_BLOB, - "CTM", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.ctm_property = prop; - - prop = drm_property_create(dev, - DRM_MODE_PROP_BLOB, - "GAMMA_LUT", 0); - if (!prop) - return -ENOMEM; - dev->mode_config.gamma_lut_property = prop; - - prop = drm_property_create_range(dev, - DRM_MODE_PROP_IMMUTABLE, - "GAMMA_LUT_SIZE", 0, UINT_MAX); - if (!prop) - return -ENOMEM; - dev->mode_config.gamma_lut_size_property = prop; - - return 0; -} - -/** - * drm_mode_getresources - get graphics configuration - * @dev: drm device for the ioctl - * @data: data pointer for the ioctl - * @file_priv: drm file for the ioctl call - * - * Construct a set of configuration description structures and return - * them to the user, including CRTC, connector and framebuffer configuration. - * - * Called by the user via ioctl. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_getresources(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_mode_card_res *card_res = data; - struct list_head *lh; - struct drm_framebuffer *fb; - struct drm_connector *connector; - struct drm_crtc *crtc; - struct drm_encoder *encoder; - int ret = 0; - int connector_count = 0; - int crtc_count = 0; - int fb_count = 0; - int encoder_count = 0; - int copied = 0; - uint32_t __user *fb_id; - uint32_t __user *crtc_id; - uint32_t __user *connector_id; - uint32_t __user *encoder_id; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - - mutex_lock(&file_priv->fbs_lock); - /* - * For the non-control nodes we need to limit the list of resources - * by IDs in the group list for this node - */ - list_for_each(lh, &file_priv->fbs) - fb_count++; - - /* handle this in 4 parts */ - /* FBs */ - if (card_res->count_fbs >= fb_count) { - copied = 0; - fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; - list_for_each_entry(fb, &file_priv->fbs, filp_head) { - if (put_user(fb->base.id, fb_id + copied)) { - mutex_unlock(&file_priv->fbs_lock); - return -EFAULT; - } - copied++; - } - } - card_res->count_fbs = fb_count; - mutex_unlock(&file_priv->fbs_lock); - - /* mode_config.mutex protects the connector list against e.g. DP MST - * connector hot-adding. CRTC/Plane lists are invariant. */ - mutex_lock(&dev->mode_config.mutex); - drm_for_each_crtc(crtc, dev) - crtc_count++; - - drm_for_each_connector(connector, dev) - connector_count++; - - drm_for_each_encoder(encoder, dev) - encoder_count++; - - card_res->max_height = dev->mode_config.max_height; - card_res->min_height = dev->mode_config.min_height; - card_res->max_width = dev->mode_config.max_width; - card_res->min_width = dev->mode_config.min_width; - - /* CRTCs */ - if (card_res->count_crtcs >= crtc_count) { - copied = 0; - crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; - drm_for_each_crtc(crtc, dev) { - if (put_user(crtc->base.id, crtc_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - card_res->count_crtcs = crtc_count; - - /* Encoders */ - if (card_res->count_encoders >= encoder_count) { - copied = 0; - encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; - drm_for_each_encoder(encoder, dev) { - if (put_user(encoder->base.id, encoder_id + - copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - card_res->count_encoders = encoder_count; - - /* Connectors */ - if (card_res->count_connectors >= connector_count) { - copied = 0; - connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; - drm_for_each_connector(connector, dev) { - if (put_user(connector->base.id, - connector_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } - card_res->count_connectors = connector_count; - -out: - mutex_unlock(&dev->mode_config.mutex); - return ret; -} - /** * drm_mode_getcrtc - get CRTC configuration * @dev: drm device for the ioctl @@ -933,157 +626,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, return ret; } -/** - * drm_mode_config_reset - call ->reset callbacks - * @dev: drm device - * - * This functions calls all the crtc's, encoder's and connector's ->reset - * callback. Drivers can use this in e.g. their driver load or resume code to - * reset hardware and software state. - */ -void drm_mode_config_reset(struct drm_device *dev) -{ - struct drm_crtc *crtc; - struct drm_plane *plane; - struct drm_encoder *encoder; - struct drm_connector *connector; - - drm_for_each_plane(plane, dev) - if (plane->funcs->reset) - plane->funcs->reset(plane); - - drm_for_each_crtc(crtc, dev) - if (crtc->funcs->reset) - crtc->funcs->reset(crtc); - - drm_for_each_encoder(encoder, dev) - if (encoder->funcs->reset) - encoder->funcs->reset(encoder); - - mutex_lock(&dev->mode_config.mutex); - drm_for_each_connector(connector, dev) - if (connector->funcs->reset) - connector->funcs->reset(connector); - mutex_unlock(&dev->mode_config.mutex); -} -EXPORT_SYMBOL(drm_mode_config_reset); - -/** - * drm_mode_config_init - initialize DRM mode_configuration structure - * @dev: DRM device - * - * Initialize @dev's mode_config structure, used for tracking the graphics - * configuration of @dev. - * - * Since this initializes the modeset locks, no locking is possible. Which is no - * problem, since this should happen single threaded at init time. It is the - * driver's problem to ensure this guarantee. - * - */ -void drm_mode_config_init(struct drm_device *dev) -{ - mutex_init(&dev->mode_config.mutex); - drm_modeset_lock_init(&dev->mode_config.connection_mutex); - mutex_init(&dev->mode_config.idr_mutex); - mutex_init(&dev->mode_config.fb_lock); - mutex_init(&dev->mode_config.blob_lock); - INIT_LIST_HEAD(&dev->mode_config.fb_list); - INIT_LIST_HEAD(&dev->mode_config.crtc_list); - INIT_LIST_HEAD(&dev->mode_config.connector_list); - INIT_LIST_HEAD(&dev->mode_config.encoder_list); - INIT_LIST_HEAD(&dev->mode_config.property_list); - INIT_LIST_HEAD(&dev->mode_config.property_blob_list); - INIT_LIST_HEAD(&dev->mode_config.plane_list); - idr_init(&dev->mode_config.crtc_idr); - idr_init(&dev->mode_config.tile_idr); - ida_init(&dev->mode_config.connector_ida); - - drm_modeset_lock_all(dev); - drm_mode_create_standard_properties(dev); - drm_modeset_unlock_all(dev); - - /* Just to be sure */ - dev->mode_config.num_fb = 0; - dev->mode_config.num_connector = 0; - dev->mode_config.num_crtc = 0; - dev->mode_config.num_encoder = 0; - dev->mode_config.num_overlay_plane = 0; - dev->mode_config.num_total_plane = 0; -} -EXPORT_SYMBOL(drm_mode_config_init); - -/** - * drm_mode_config_cleanup - free up DRM mode_config info - * @dev: DRM device - * - * Free up all the connectors and CRTCs associated with this DRM device, then - * free up the framebuffers and associated buffer objects. - * - * Note that since this /should/ happen single-threaded at driver/device - * teardown time, no locking is required. It's the driver's job to ensure that - * this guarantee actually holds true. - * - * FIXME: cleanup any dangling user buffer objects too - */ -void drm_mode_config_cleanup(struct drm_device *dev) -{ - struct drm_connector *connector, *ot; - struct drm_crtc *crtc, *ct; - struct drm_encoder *encoder, *enct; - struct drm_framebuffer *fb, *fbt; - struct drm_property *property, *pt; - struct drm_property_blob *blob, *bt; - struct drm_plane *plane, *plt; - - list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, - head) { - encoder->funcs->destroy(encoder); - } - - list_for_each_entry_safe(connector, ot, - &dev->mode_config.connector_list, head) { - connector->funcs->destroy(connector); - } - - list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, - head) { - drm_property_destroy(dev, property); - } - - list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, - head) { - plane->funcs->destroy(plane); - } - - list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { - crtc->funcs->destroy(crtc); - } - - list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, - head_global) { - drm_property_unreference_blob(blob); - } - - /* - * Single-threaded teardown context, so it's not required to grab the - * fb_lock to protect against concurrent fb_list access. Contrary, it - * would actually deadlock with the drm_framebuffer_cleanup function. - * - * Also, if there are any framebuffers left, that's a driver leak now, - * so politely WARN about this. - */ - WARN_ON(!list_empty(&dev->mode_config.fb_list)); - list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - drm_framebuffer_free(&fb->base.refcount); - } - - ida_destroy(&dev->mode_config.connector_ida); - idr_destroy(&dev->mode_config.tile_idr); - idr_destroy(&dev->mode_config.crtc_idr); - drm_modeset_lock_fini(&dev->mode_config.connection_mutex); -} -EXPORT_SYMBOL(drm_mode_config_cleanup); - /** * DOC: Tile group * diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 64bb3eb7f8069..f78d5aaf7e911 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -40,19 +40,26 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, int x, int y, const struct drm_display_mode *mode, const struct drm_framebuffer *fb); - -void drm_fb_release(struct drm_file *file_priv); +int drm_crtc_register_all(struct drm_device *dev); +void drm_crtc_unregister_all(struct drm_device *dev); /* IOCTLs */ -int drm_mode_getresources(struct drm_device *dev, - void *data, struct drm_file *file_priv); int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); -/* drm_dumb_buffers.c */ + +/* drm_mode_config.c */ +int drm_modeset_register_all(struct drm_device *dev); +void drm_modeset_unregister_all(struct drm_device *dev); +/* IOCTLs */ +int drm_mode_getresources(struct drm_device *dev, + void *data, struct drm_file *file_priv); + + +/* drm_dumb_buffers.c */ /* IOCTLs */ int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -149,6 +156,8 @@ void drm_framebuffer_free(struct kref *kref); int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, const struct drm_framebuffer *fb); +void drm_fb_release(struct drm_file *file_priv); + /* IOCTL */ int drm_mode_addfb(struct drm_device *dev, @@ -168,9 +177,6 @@ int drm_atomic_get_property(struct drm_mode_object *obj, int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_modeset_register_all(struct drm_device *dev); -void drm_modeset_unregister_all(struct drm_device *dev); - /* drm_plane.c */ int drm_plane_register_all(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c new file mode 100644 index 0000000000000..6f80886ed40b1 --- /dev/null +++ b/drivers/gpu/drm/drm_mode_config.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include + +#include "drm_crtc_internal.h" +#include "drm_internal.h" + +int drm_modeset_register_all(struct drm_device *dev) +{ + int ret; + + ret = drm_plane_register_all(dev); + if (ret) + goto err_plane; + + ret = drm_crtc_register_all(dev); + if (ret) + goto err_crtc; + + ret = drm_encoder_register_all(dev); + if (ret) + goto err_encoder; + + ret = drm_connector_register_all(dev); + if (ret) + goto err_connector; + + return 0; + +err_connector: + drm_encoder_unregister_all(dev); +err_encoder: + drm_crtc_unregister_all(dev); +err_crtc: + drm_plane_unregister_all(dev); +err_plane: + return ret; +} + +void drm_modeset_unregister_all(struct drm_device *dev) +{ + drm_connector_unregister_all(dev); + drm_encoder_unregister_all(dev); + drm_crtc_unregister_all(dev); + drm_plane_unregister_all(dev); +} + +/** + * drm_mode_getresources - get graphics configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Construct a set of configuration description structures and return + * them to the user, including CRTC, connector and framebuffer configuration. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_getresources(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_mode_card_res *card_res = data; + struct list_head *lh; + struct drm_framebuffer *fb; + struct drm_connector *connector; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + int ret = 0; + int connector_count = 0; + int crtc_count = 0; + int fb_count = 0; + int encoder_count = 0; + int copied = 0; + uint32_t __user *fb_id; + uint32_t __user *crtc_id; + uint32_t __user *connector_id; + uint32_t __user *encoder_id; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + + mutex_lock(&file_priv->fbs_lock); + /* + * For the non-control nodes we need to limit the list of resources + * by IDs in the group list for this node + */ + list_for_each(lh, &file_priv->fbs) + fb_count++; + + /* handle this in 4 parts */ + /* FBs */ + if (card_res->count_fbs >= fb_count) { + copied = 0; + fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; + list_for_each_entry(fb, &file_priv->fbs, filp_head) { + if (put_user(fb->base.id, fb_id + copied)) { + mutex_unlock(&file_priv->fbs_lock); + return -EFAULT; + } + copied++; + } + } + card_res->count_fbs = fb_count; + mutex_unlock(&file_priv->fbs_lock); + + /* mode_config.mutex protects the connector list against e.g. DP MST + * connector hot-adding. CRTC/Plane lists are invariant. */ + mutex_lock(&dev->mode_config.mutex); + drm_for_each_crtc(crtc, dev) + crtc_count++; + + drm_for_each_connector(connector, dev) + connector_count++; + + drm_for_each_encoder(encoder, dev) + encoder_count++; + + card_res->max_height = dev->mode_config.max_height; + card_res->min_height = dev->mode_config.min_height; + card_res->max_width = dev->mode_config.max_width; + card_res->min_width = dev->mode_config.min_width; + + /* CRTCs */ + if (card_res->count_crtcs >= crtc_count) { + copied = 0; + crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; + drm_for_each_crtc(crtc, dev) { + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + card_res->count_crtcs = crtc_count; + + /* Encoders */ + if (card_res->count_encoders >= encoder_count) { + copied = 0; + encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; + drm_for_each_encoder(encoder, dev) { + if (put_user(encoder->base.id, encoder_id + + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + card_res->count_encoders = encoder_count; + + /* Connectors */ + if (card_res->count_connectors >= connector_count) { + copied = 0; + connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; + drm_for_each_connector(connector, dev) { + if (put_user(connector->base.id, + connector_id + copied)) { + ret = -EFAULT; + goto out; + } + copied++; + } + } + card_res->count_connectors = connector_count; + +out: + mutex_unlock(&dev->mode_config.mutex); + return ret; +} + +/** + * drm_mode_config_reset - call ->reset callbacks + * @dev: drm device + * + * This functions calls all the crtc's, encoder's and connector's ->reset + * callback. Drivers can use this in e.g. their driver load or resume code to + * reset hardware and software state. + */ +void drm_mode_config_reset(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_encoder *encoder; + struct drm_connector *connector; + + drm_for_each_plane(plane, dev) + if (plane->funcs->reset) + plane->funcs->reset(plane); + + drm_for_each_crtc(crtc, dev) + if (crtc->funcs->reset) + crtc->funcs->reset(crtc); + + drm_for_each_encoder(encoder, dev) + if (encoder->funcs->reset) + encoder->funcs->reset(encoder); + + mutex_lock(&dev->mode_config.mutex); + drm_for_each_connector(connector, dev) + if (connector->funcs->reset) + connector->funcs->reset(connector); + mutex_unlock(&dev->mode_config.mutex); +} +EXPORT_SYMBOL(drm_mode_config_reset); + +/* + * Global properties + */ +static const struct drm_prop_enum_list drm_plane_type_enum_list[] = { + { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, + { DRM_PLANE_TYPE_PRIMARY, "Primary" }, + { DRM_PLANE_TYPE_CURSOR, "Cursor" }, +}; + +static int drm_mode_create_standard_properties(struct drm_device *dev) +{ + struct drm_property *prop; + int ret; + + ret = drm_connector_create_standard_properties(dev); + if (ret) + return ret; + + prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, + "type", drm_plane_type_enum_list, + ARRAY_SIZE(drm_plane_type_enum_list)); + if (!prop) + return -ENOMEM; + dev->mode_config.plane_type_property = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_X", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_x = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_Y", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_y = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_W", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_w = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "SRC_H", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_src_h = prop; + + prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_X", INT_MIN, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_x = prop; + + prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_Y", INT_MIN, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_y = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_W", 0, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_w = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_H", 0, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_h = prop; + + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, + "FB_ID", DRM_MODE_OBJECT_FB); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_fb_id = prop; + + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, + "CRTC_ID", DRM_MODE_OBJECT_CRTC); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_crtc_id = prop; + + prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC, + "ACTIVE"); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_active = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB, + "MODE_ID", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_mode_id = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "DEGAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.degamma_lut_property = prop; + + prop = drm_property_create_range(dev, + DRM_MODE_PROP_IMMUTABLE, + "DEGAMMA_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.degamma_lut_size_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "CTM", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.ctm_property = prop; + + prop = drm_property_create(dev, + DRM_MODE_PROP_BLOB, + "GAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + dev->mode_config.gamma_lut_property = prop; + + prop = drm_property_create_range(dev, + DRM_MODE_PROP_IMMUTABLE, + "GAMMA_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.gamma_lut_size_property = prop; + + return 0; +} + +/** + * drm_mode_config_init - initialize DRM mode_configuration structure + * @dev: DRM device + * + * Initialize @dev's mode_config structure, used for tracking the graphics + * configuration of @dev. + * + * Since this initializes the modeset locks, no locking is possible. Which is no + * problem, since this should happen single threaded at init time. It is the + * driver's problem to ensure this guarantee. + * + */ +void drm_mode_config_init(struct drm_device *dev) +{ + mutex_init(&dev->mode_config.mutex); + drm_modeset_lock_init(&dev->mode_config.connection_mutex); + mutex_init(&dev->mode_config.idr_mutex); + mutex_init(&dev->mode_config.fb_lock); + mutex_init(&dev->mode_config.blob_lock); + INIT_LIST_HEAD(&dev->mode_config.fb_list); + INIT_LIST_HEAD(&dev->mode_config.crtc_list); + INIT_LIST_HEAD(&dev->mode_config.connector_list); + INIT_LIST_HEAD(&dev->mode_config.encoder_list); + INIT_LIST_HEAD(&dev->mode_config.property_list); + INIT_LIST_HEAD(&dev->mode_config.property_blob_list); + INIT_LIST_HEAD(&dev->mode_config.plane_list); + idr_init(&dev->mode_config.crtc_idr); + idr_init(&dev->mode_config.tile_idr); + ida_init(&dev->mode_config.connector_ida); + + drm_modeset_lock_all(dev); + drm_mode_create_standard_properties(dev); + drm_modeset_unlock_all(dev); + + /* Just to be sure */ + dev->mode_config.num_fb = 0; + dev->mode_config.num_connector = 0; + dev->mode_config.num_crtc = 0; + dev->mode_config.num_encoder = 0; + dev->mode_config.num_overlay_plane = 0; + dev->mode_config.num_total_plane = 0; +} +EXPORT_SYMBOL(drm_mode_config_init); + +/** + * drm_mode_config_cleanup - free up DRM mode_config info + * @dev: DRM device + * + * Free up all the connectors and CRTCs associated with this DRM device, then + * free up the framebuffers and associated buffer objects. + * + * Note that since this /should/ happen single-threaded at driver/device + * teardown time, no locking is required. It's the driver's job to ensure that + * this guarantee actually holds true. + * + * FIXME: cleanup any dangling user buffer objects too + */ +void drm_mode_config_cleanup(struct drm_device *dev) +{ + struct drm_connector *connector, *ot; + struct drm_crtc *crtc, *ct; + struct drm_encoder *encoder, *enct; + struct drm_framebuffer *fb, *fbt; + struct drm_property *property, *pt; + struct drm_property_blob *blob, *bt; + struct drm_plane *plane, *plt; + + list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, + head) { + encoder->funcs->destroy(encoder); + } + + list_for_each_entry_safe(connector, ot, + &dev->mode_config.connector_list, head) { + connector->funcs->destroy(connector); + } + + list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, + head) { + drm_property_destroy(dev, property); + } + + list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, + head) { + plane->funcs->destroy(plane); + } + + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { + crtc->funcs->destroy(crtc); + } + + list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, + head_global) { + drm_property_unreference_blob(blob); + } + + /* + * Single-threaded teardown context, so it's not required to grab the + * fb_lock to protect against concurrent fb_list access. Contrary, it + * would actually deadlock with the drm_framebuffer_cleanup function. + * + * Also, if there are any framebuffers left, that's a driver leak now, + * so politely WARN about this. + */ + WARN_ON(!list_empty(&dev->mode_config.fb_list)); + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { + drm_framebuffer_free(&fb->base.refcount); + } + + ida_destroy(&dev->mode_config.connector_ida); + idr_destroy(&dev->mode_config.tile_idr); + idr_destroy(&dev->mode_config.crtc_idr); + drm_modeset_lock_fini(&dev->mode_config.connection_mutex); +} +EXPORT_SYMBOL(drm_mode_config_cleanup); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8cca2a895981a..98de488a95a5c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #include #include +#include struct drm_device; struct drm_mode_set; @@ -768,616 +768,6 @@ struct drm_mode_set { size_t num_connectors; }; -/** - * struct drm_mode_config_funcs - basic driver provided mode setting functions - * - * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that - * involve drivers. - */ -struct drm_mode_config_funcs { - /** - * @fb_create: - * - * Create a new framebuffer object. The core does basic checks on the - * requested metadata, but most of that is left to the driver. See - * struct &drm_mode_fb_cmd2 for details. - * - * If the parameters are deemed valid and the backing storage objects in - * the underlying memory manager all exist, then the driver allocates - * a new &drm_framebuffer structure, subclassed to contain - * driver-specific information (like the internal native buffer object - * references). It also needs to fill out all relevant metadata, which - * should be done by calling drm_helper_mode_fill_fb_struct(). - * - * The initialization is finalized by calling drm_framebuffer_init(), - * which registers the framebuffer and makes it accessible to other - * threads. - * - * RETURNS: - * - * A new framebuffer with an initial reference count of 1 or a negative - * error code encoded with ERR_PTR(). - */ - struct drm_framebuffer *(*fb_create)(struct drm_device *dev, - struct drm_file *file_priv, - const struct drm_mode_fb_cmd2 *mode_cmd); - - /** - * @output_poll_changed: - * - * Callback used by helpers to inform the driver of output configuration - * changes. - * - * Drivers implementing fbdev emulation with the helpers can call - * drm_fb_helper_hotplug_changed from this hook to inform the fbdev - * helper of output changes. - * - * FIXME: - * - * Except that there's no vtable for device-level helper callbacks - * there's no reason this is a core function. - */ - void (*output_poll_changed)(struct drm_device *dev); - - /** - * @atomic_check: - * - * This is the only hook to validate an atomic modeset update. This - * function must reject any modeset and state changes which the hardware - * or driver doesn't support. This includes but is of course not limited - * to: - * - * - Checking that the modes, framebuffers, scaling and placement - * requirements and so on are within the limits of the hardware. - * - * - Checking that any hidden shared resources are not oversubscribed. - * This can be shared PLLs, shared lanes, overall memory bandwidth, - * display fifo space (where shared between planes or maybe even - * CRTCs). - * - * - Checking that virtualized resources exported to userspace are not - * oversubscribed. For various reasons it can make sense to expose - * more planes, crtcs or encoders than which are physically there. One - * example is dual-pipe operations (which generally should be hidden - * from userspace if when lockstepped in hardware, exposed otherwise), - * where a plane might need 1 hardware plane (if it's just on one - * pipe), 2 hardware planes (when it spans both pipes) or maybe even - * shared a hardware plane with a 2nd plane (if there's a compatible - * plane requested on the area handled by the other pipe). - * - * - Check that any transitional state is possible and that if - * requested, the update can indeed be done in the vblank period - * without temporarily disabling some functions. - * - * - Check any other constraints the driver or hardware might have. - * - * - This callback also needs to correctly fill out the &drm_crtc_state - * in this update to make sure that drm_atomic_crtc_needs_modeset() - * reflects the nature of the possible update and returns true if and - * only if the update cannot be applied without tearing within one - * vblank on that CRTC. The core uses that information to reject - * updates which require a full modeset (i.e. blanking the screen, or - * at least pausing updates for a substantial amount of time) if - * userspace has disallowed that in its request. - * - * - The driver also does not need to repeat basic input validation - * like done for the corresponding legacy entry points. The core does - * that before calling this hook. - * - * See the documentation of @atomic_commit for an exhaustive list of - * error conditions which don't have to be checked at the - * ->atomic_check() stage? - * - * See the documentation for struct &drm_atomic_state for how exactly - * an atomic modeset update is described. - * - * Drivers using the atomic helpers can implement this hook using - * drm_atomic_helper_check(), or one of the exported sub-functions of - * it. - * - * RETURNS: - * - * 0 on success or one of the below negative error codes: - * - * - -EINVAL, if any of the above constraints are violated. - * - * - -EDEADLK, when returned from an attempt to acquire an additional - * &drm_modeset_lock through drm_modeset_lock(). - * - * - -ENOMEM, if allocating additional state sub-structures failed due - * to lack of memory. - * - * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. - * This can either be due to a pending signal, or because the driver - * needs to completely bail out to recover from an exceptional - * situation like a GPU hang. From a userspace point all errors are - * treated equally. - */ - int (*atomic_check)(struct drm_device *dev, - struct drm_atomic_state *state); - - /** - * @atomic_commit: - * - * This is the only hook to commit an atomic modeset update. The core - * guarantees that @atomic_check has been called successfully before - * calling this function, and that nothing has been changed in the - * interim. - * - * See the documentation for struct &drm_atomic_state for how exactly - * an atomic modeset update is described. - * - * Drivers using the atomic helpers can implement this hook using - * drm_atomic_helper_commit(), or one of the exported sub-functions of - * it. - * - * Nonblocking commits (as indicated with the nonblock parameter) must - * do any preparatory work which might result in an unsuccessful commit - * in the context of this callback. The only exceptions are hardware - * errors resulting in -EIO. But even in that case the driver must - * ensure that the display pipe is at least running, to avoid - * compositors crashing when pageflips don't work. Anything else, - * specifically committing the update to the hardware, should be done - * without blocking the caller. For updates which do not require a - * modeset this must be guaranteed. - * - * The driver must wait for any pending rendering to the new - * framebuffers to complete before executing the flip. It should also - * wait for any pending rendering from other drivers if the underlying - * buffer is a shared dma-buf. Nonblocking commits must not wait for - * rendering in the context of this callback. - * - * An application can request to be notified when the atomic commit has - * completed. These events are per-CRTC and can be distinguished by the - * CRTC index supplied in &drm_event to userspace. - * - * The drm core will supply a struct &drm_event in the event - * member of each CRTC's &drm_crtc_state structure. See the - * documentation for &drm_crtc_state for more details about the precise - * semantics of this event. - * - * NOTE: - * - * Drivers are not allowed to shut down any display pipe successfully - * enabled through an atomic commit on their own. Doing so can result in - * compositors crashing if a page flip is suddenly rejected because the - * pipe is off. - * - * RETURNS: - * - * 0 on success or one of the below negative error codes: - * - * - -EBUSY, if a nonblocking updated is requested and there is - * an earlier updated pending. Drivers are allowed to support a queue - * of outstanding updates, but currently no driver supports that. - * Note that drivers must wait for preceding updates to complete if a - * synchronous update is requested, they are not allowed to fail the - * commit in that case. - * - * - -ENOMEM, if the driver failed to allocate memory. Specifically - * this can happen when trying to pin framebuffers, which must only - * be done when committing the state. - * - * - -ENOSPC, as a refinement of the more generic -ENOMEM to indicate - * that the driver has run out of vram, iommu space or similar GPU - * address space needed for framebuffer. - * - * - -EIO, if the hardware completely died. - * - * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. - * This can either be due to a pending signal, or because the driver - * needs to completely bail out to recover from an exceptional - * situation like a GPU hang. From a userspace point of view all errors are - * treated equally. - * - * This list is exhaustive. Specifically this hook is not allowed to - * return -EINVAL (any invalid requests should be caught in - * @atomic_check) or -EDEADLK (this function must not acquire - * additional modeset locks). - */ - int (*atomic_commit)(struct drm_device *dev, - struct drm_atomic_state *state, - bool nonblock); - - /** - * @atomic_state_alloc: - * - * This optional hook can be used by drivers that want to subclass struct - * &drm_atomic_state to be able to track their own driver-private global - * state easily. If this hook is implemented, drivers must also - * implement @atomic_state_clear and @atomic_state_free. - * - * RETURNS: - * - * A new &drm_atomic_state on success or NULL on failure. - */ - struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev); - - /** - * @atomic_state_clear: - * - * This hook must clear any driver private state duplicated into the - * passed-in &drm_atomic_state. This hook is called when the caller - * encountered a &drm_modeset_lock deadlock and needs to drop all - * already acquired locks as part of the deadlock avoidance dance - * implemented in drm_modeset_lock_backoff(). - * - * Any duplicated state must be invalidated since a concurrent atomic - * update might change it, and the drm atomic interfaces always apply - * updates as relative changes to the current state. - * - * Drivers that implement this must call drm_atomic_state_default_clear() - * to clear common state. - */ - void (*atomic_state_clear)(struct drm_atomic_state *state); - - /** - * @atomic_state_free: - * - * This hook needs driver private resources and the &drm_atomic_state - * itself. Note that the core first calls drm_atomic_state_clear() to - * avoid code duplicate between the clear and free hooks. - * - * Drivers that implement this must call drm_atomic_state_default_free() - * to release common resources. - */ - void (*atomic_state_free)(struct drm_atomic_state *state); -}; - -/** - * struct drm_mode_config - Mode configuration control structure - * @mutex: mutex protecting KMS related lists and structures - * @connection_mutex: ww mutex protecting connector state and routing - * @acquire_ctx: global implicit acquire context used by atomic drivers for - * legacy IOCTLs - * @fb_lock: mutex to protect fb state and lists - * @num_fb: number of fbs available - * @fb_list: list of framebuffers available - * @num_encoder: number of encoders on this device - * @encoder_list: list of encoder objects - * @num_overlay_plane: number of overlay planes on this device - * @num_total_plane: number of universal (i.e. with primary/curso) planes on this device - * @plane_list: list of plane objects - * @num_crtc: number of CRTCs on this device - * @crtc_list: list of CRTC objects - * @property_list: list of property objects - * @min_width: minimum pixel width on this device - * @min_height: minimum pixel height on this device - * @max_width: maximum pixel width on this device - * @max_height: maximum pixel height on this device - * @funcs: core driver provided mode setting functions - * @fb_base: base address of the framebuffer - * @poll_enabled: track polling support for this device - * @poll_running: track polling status for this device - * @delayed_event: track delayed poll uevent deliver for this device - * @output_poll_work: delayed work for polling in process context - * @property_blob_list: list of all the blob property objects - * @blob_lock: mutex for blob property allocation and management - * @*_property: core property tracking - * @preferred_depth: preferred RBG pixel depth, used by fb helpers - * @prefer_shadow: hint to userspace to prefer shadow-fb rendering - * @cursor_width: hint to userspace for max cursor width - * @cursor_height: hint to userspace for max cursor height - * @helper_private: mid-layer private data - * - * Core mode resource tracking structure. All CRTC, encoders, and connectors - * enumerated by the driver are added here, as are global properties. Some - * global restrictions are also here, e.g. dimension restrictions. - */ -struct drm_mode_config { - struct mutex mutex; /* protects configuration (mode lists etc.) */ - struct drm_modeset_lock connection_mutex; /* protects connector->encoder and encoder->crtc links */ - struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ - - /** - * @idr_mutex: - * - * Mutex for KMS ID allocation and management. Protects both @crtc_idr - * and @tile_idr. - */ - struct mutex idr_mutex; - - /** - * @crtc_idr: - * - * Main KMS ID tracking object. Use this idr for all IDs, fb, crtc, - * connector, modes - just makes life easier to have only one. - */ - struct idr crtc_idr; - - /** - * @tile_idr: - * - * Use this idr for allocating new IDs for tiled sinks like use in some - * high-res DP MST screens. - */ - struct idr tile_idr; - - struct mutex fb_lock; /* proctects global and per-file fb lists */ - int num_fb; - struct list_head fb_list; - - /** - * @num_connector: Number of connectors on this device. - */ - int num_connector; - /** - * @connector_ida: ID allocator for connector indices. - */ - struct ida connector_ida; - /** - * @connector_list: List of connector objects. - */ - struct list_head connector_list; - int num_encoder; - struct list_head encoder_list; - - /* - * Track # of overlay planes separately from # of total planes. By - * default we only advertise overlay planes to userspace; if userspace - * sets the "universal plane" capability bit, we'll go ahead and - * expose all planes. - */ - int num_overlay_plane; - int num_total_plane; - struct list_head plane_list; - - int num_crtc; - struct list_head crtc_list; - - struct list_head property_list; - - int min_width, min_height; - int max_width, max_height; - const struct drm_mode_config_funcs *funcs; - resource_size_t fb_base; - - /* output poll support */ - bool poll_enabled; - bool poll_running; - bool delayed_event; - struct delayed_work output_poll_work; - - struct mutex blob_lock; - - /* pointers to standard properties */ - struct list_head property_blob_list; - /** - * @edid_property: Default connector property to hold the EDID of the - * currently connected sink, if any. - */ - struct drm_property *edid_property; - /** - * @dpms_property: Default connector property to control the - * connector's DPMS state. - */ - struct drm_property *dpms_property; - /** - * @path_property: Default connector property to hold the DP MST path - * for the port. - */ - struct drm_property *path_property; - /** - * @tile_property: Default connector property to store the tile - * position of a tiled screen, for sinks which need to be driven with - * multiple CRTCs. - */ - struct drm_property *tile_property; - /** - * @plane_type_property: Default plane property to differentiate - * CURSOR, PRIMARY and OVERLAY legacy uses of planes. - */ - struct drm_property *plane_type_property; - /** - * @prop_src_x: Default atomic plane property for the plane source - * position in the connected &drm_framebuffer. - */ - struct drm_property *prop_src_x; - /** - * @prop_src_y: Default atomic plane property for the plane source - * position in the connected &drm_framebuffer. - */ - struct drm_property *prop_src_y; - /** - * @prop_src_w: Default atomic plane property for the plane source - * position in the connected &drm_framebuffer. - */ - struct drm_property *prop_src_w; - /** - * @prop_src_h: Default atomic plane property for the plane source - * position in the connected &drm_framebuffer. - */ - struct drm_property *prop_src_h; - /** - * @prop_crtc_x: Default atomic plane property for the plane destination - * position in the &drm_crtc is is being shown on. - */ - struct drm_property *prop_crtc_x; - /** - * @prop_crtc_y: Default atomic plane property for the plane destination - * position in the &drm_crtc is is being shown on. - */ - struct drm_property *prop_crtc_y; - /** - * @prop_crtc_w: Default atomic plane property for the plane destination - * position in the &drm_crtc is is being shown on. - */ - struct drm_property *prop_crtc_w; - /** - * @prop_crtc_h: Default atomic plane property for the plane destination - * position in the &drm_crtc is is being shown on. - */ - struct drm_property *prop_crtc_h; - /** - * @prop_fb_id: Default atomic plane property to specify the - * &drm_framebuffer. - */ - struct drm_property *prop_fb_id; - /** - * @prop_crtc_id: Default atomic plane property to specify the - * &drm_crtc. - */ - struct drm_property *prop_crtc_id; - /** - * @prop_active: Default atomic CRTC property to control the active - * state, which is the simplified implementation for DPMS in atomic - * drivers. - */ - struct drm_property *prop_active; - /** - * @prop_mode_id: Default atomic CRTC property to set the mode for a - * CRTC. A 0 mode implies that the CRTC is entirely disabled - all - * connectors must be of and active must be set to disabled, too. - */ - struct drm_property *prop_mode_id; - - /** - * @dvi_i_subconnector_property: Optional DVI-I property to - * differentiate between analog or digital mode. - */ - struct drm_property *dvi_i_subconnector_property; - /** - * @dvi_i_select_subconnector_property: Optional DVI-I property to - * select between analog or digital mode. - */ - struct drm_property *dvi_i_select_subconnector_property; - - /** - * @tv_subconnector_property: Optional TV property to differentiate - * between different TV connector types. - */ - struct drm_property *tv_subconnector_property; - /** - * @tv_select_subconnector_property: Optional TV property to select - * between different TV connector types. - */ - struct drm_property *tv_select_subconnector_property; - /** - * @tv_mode_property: Optional TV property to select - * the output TV mode. - */ - struct drm_property *tv_mode_property; - /** - * @tv_left_margin_property: Optional TV property to set the left - * margin. - */ - struct drm_property *tv_left_margin_property; - /** - * @tv_right_margin_property: Optional TV property to set the right - * margin. - */ - struct drm_property *tv_right_margin_property; - /** - * @tv_top_margin_property: Optional TV property to set the right - * margin. - */ - struct drm_property *tv_top_margin_property; - /** - * @tv_bottom_margin_property: Optional TV property to set the right - * margin. - */ - struct drm_property *tv_bottom_margin_property; - /** - * @tv_brightness_property: Optional TV property to set the - * brightness. - */ - struct drm_property *tv_brightness_property; - /** - * @tv_contrast_property: Optional TV property to set the - * contrast. - */ - struct drm_property *tv_contrast_property; - /** - * @tv_flicker_reduction_property: Optional TV property to control the - * flicker reduction mode. - */ - struct drm_property *tv_flicker_reduction_property; - /** - * @tv_overscan_property: Optional TV property to control the overscan - * setting. - */ - struct drm_property *tv_overscan_property; - /** - * @tv_saturation_property: Optional TV property to set the - * saturation. - */ - struct drm_property *tv_saturation_property; - /** - * @tv_hue_property: Optional TV property to set the hue. - */ - struct drm_property *tv_hue_property; - - /** - * @scaling_mode_property: Optional connector property to control the - * upscaling, mostly used for built-in panels. - */ - struct drm_property *scaling_mode_property; - /** - * @aspect_ratio_property: Optional connector property to control the - * HDMI infoframe aspect ratio setting. - */ - struct drm_property *aspect_ratio_property; - /** - * @degamma_lut_property: Optional CRTC property to set the LUT used to - * convert the framebuffer's colors to linear gamma. - */ - struct drm_property *degamma_lut_property; - /** - * @degamma_lut_size_property: Optional CRTC property for the size of - * the degamma LUT as supported by the driver (read-only). - */ - struct drm_property *degamma_lut_size_property; - /** - * @ctm_property: Optional CRTC property to set the - * matrix used to convert colors after the lookup in the - * degamma LUT. - */ - struct drm_property *ctm_property; - /** - * @gamma_lut_property: Optional CRTC property to set the LUT used to - * convert the colors, after the CTM matrix, to the gamma space of the - * connected screen. - */ - struct drm_property *gamma_lut_property; - /** - * @gamma_lut_size_property: Optional CRTC property for the size of the - * gamma LUT as supported by the driver (read-only). - */ - struct drm_property *gamma_lut_size_property; - - /** - * @suggested_x_property: Optional connector property with a hint for - * the position of the output on the host's screen. - */ - struct drm_property *suggested_x_property; - /** - * @suggested_y_property: Optional connector property with a hint for - * the position of the output on the host's screen. - */ - struct drm_property *suggested_y_property; - - /* dumb ioctl parameters */ - uint32_t preferred_depth, prefer_shadow; - - /** - * @async_page_flip: Does this device support async flips on the primary - * plane? - */ - bool async_page_flip; - - /** - * @allow_fb_modifiers: - * - * Whether the driver supports fb modifiers in the ADDFB2.1 ioctl call. - */ - bool allow_fb_modifiers; - - /* cursor size */ - uint32_t cursor_width, cursor_height; - - struct drm_mode_config_helper_funcs *helper_private; -}; - #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) extern __printf(6, 7) @@ -1418,10 +808,6 @@ extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, extern int drm_crtc_force_disable(struct drm_crtc *crtc); extern int drm_crtc_force_disable_all(struct drm_device *dev); -extern void drm_mode_config_init(struct drm_device *dev); -extern void drm_mode_config_reset(struct drm_device *dev); -extern void drm_mode_config_cleanup(struct drm_device *dev); - extern int drm_mode_set_config_internal(struct drm_mode_set *set); extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h new file mode 100644 index 0000000000000..5d11b258512df --- /dev/null +++ b/include/drm/drm_mode_config.h @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifndef __DRM_MODE_CONFIG_H__ +#define __DRM_MODE_CONFIG_H__ + +#include +#include +#include +#include + +#include + +struct drm_file; +struct drm_device; +struct drm_atomic_state; +struct drm_mode_fb_cmd2; + +/** + * struct drm_mode_config_funcs - basic driver provided mode setting functions + * + * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that + * involve drivers. + */ +struct drm_mode_config_funcs { + /** + * @fb_create: + * + * Create a new framebuffer object. The core does basic checks on the + * requested metadata, but most of that is left to the driver. See + * struct &drm_mode_fb_cmd2 for details. + * + * If the parameters are deemed valid and the backing storage objects in + * the underlying memory manager all exist, then the driver allocates + * a new &drm_framebuffer structure, subclassed to contain + * driver-specific information (like the internal native buffer object + * references). It also needs to fill out all relevant metadata, which + * should be done by calling drm_helper_mode_fill_fb_struct(). + * + * The initialization is finalized by calling drm_framebuffer_init(), + * which registers the framebuffer and makes it accessible to other + * threads. + * + * RETURNS: + * + * A new framebuffer with an initial reference count of 1 or a negative + * error code encoded with ERR_PTR(). + */ + struct drm_framebuffer *(*fb_create)(struct drm_device *dev, + struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *mode_cmd); + + /** + * @output_poll_changed: + * + * Callback used by helpers to inform the driver of output configuration + * changes. + * + * Drivers implementing fbdev emulation with the helpers can call + * drm_fb_helper_hotplug_changed from this hook to inform the fbdev + * helper of output changes. + * + * FIXME: + * + * Except that there's no vtable for device-level helper callbacks + * there's no reason this is a core function. + */ + void (*output_poll_changed)(struct drm_device *dev); + + /** + * @atomic_check: + * + * This is the only hook to validate an atomic modeset update. This + * function must reject any modeset and state changes which the hardware + * or driver doesn't support. This includes but is of course not limited + * to: + * + * - Checking that the modes, framebuffers, scaling and placement + * requirements and so on are within the limits of the hardware. + * + * - Checking that any hidden shared resources are not oversubscribed. + * This can be shared PLLs, shared lanes, overall memory bandwidth, + * display fifo space (where shared between planes or maybe even + * CRTCs). + * + * - Checking that virtualized resources exported to userspace are not + * oversubscribed. For various reasons it can make sense to expose + * more planes, crtcs or encoders than which are physically there. One + * example is dual-pipe operations (which generally should be hidden + * from userspace if when lockstepped in hardware, exposed otherwise), + * where a plane might need 1 hardware plane (if it's just on one + * pipe), 2 hardware planes (when it spans both pipes) or maybe even + * shared a hardware plane with a 2nd plane (if there's a compatible + * plane requested on the area handled by the other pipe). + * + * - Check that any transitional state is possible and that if + * requested, the update can indeed be done in the vblank period + * without temporarily disabling some functions. + * + * - Check any other constraints the driver or hardware might have. + * + * - This callback also needs to correctly fill out the &drm_crtc_state + * in this update to make sure that drm_atomic_crtc_needs_modeset() + * reflects the nature of the possible update and returns true if and + * only if the update cannot be applied without tearing within one + * vblank on that CRTC. The core uses that information to reject + * updates which require a full modeset (i.e. blanking the screen, or + * at least pausing updates for a substantial amount of time) if + * userspace has disallowed that in its request. + * + * - The driver also does not need to repeat basic input validation + * like done for the corresponding legacy entry points. The core does + * that before calling this hook. + * + * See the documentation of @atomic_commit for an exhaustive list of + * error conditions which don't have to be checked at the + * ->atomic_check() stage? + * + * See the documentation for struct &drm_atomic_state for how exactly + * an atomic modeset update is described. + * + * Drivers using the atomic helpers can implement this hook using + * drm_atomic_helper_check(), or one of the exported sub-functions of + * it. + * + * RETURNS: + * + * 0 on success or one of the below negative error codes: + * + * - -EINVAL, if any of the above constraints are violated. + * + * - -EDEADLK, when returned from an attempt to acquire an additional + * &drm_modeset_lock through drm_modeset_lock(). + * + * - -ENOMEM, if allocating additional state sub-structures failed due + * to lack of memory. + * + * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. + * This can either be due to a pending signal, or because the driver + * needs to completely bail out to recover from an exceptional + * situation like a GPU hang. From a userspace point all errors are + * treated equally. + */ + int (*atomic_check)(struct drm_device *dev, + struct drm_atomic_state *state); + + /** + * @atomic_commit: + * + * This is the only hook to commit an atomic modeset update. The core + * guarantees that @atomic_check has been called successfully before + * calling this function, and that nothing has been changed in the + * interim. + * + * See the documentation for struct &drm_atomic_state for how exactly + * an atomic modeset update is described. + * + * Drivers using the atomic helpers can implement this hook using + * drm_atomic_helper_commit(), or one of the exported sub-functions of + * it. + * + * Nonblocking commits (as indicated with the nonblock parameter) must + * do any preparatory work which might result in an unsuccessful commit + * in the context of this callback. The only exceptions are hardware + * errors resulting in -EIO. But even in that case the driver must + * ensure that the display pipe is at least running, to avoid + * compositors crashing when pageflips don't work. Anything else, + * specifically committing the update to the hardware, should be done + * without blocking the caller. For updates which do not require a + * modeset this must be guaranteed. + * + * The driver must wait for any pending rendering to the new + * framebuffers to complete before executing the flip. It should also + * wait for any pending rendering from other drivers if the underlying + * buffer is a shared dma-buf. Nonblocking commits must not wait for + * rendering in the context of this callback. + * + * An application can request to be notified when the atomic commit has + * completed. These events are per-CRTC and can be distinguished by the + * CRTC index supplied in &drm_event to userspace. + * + * The drm core will supply a struct &drm_event in the event + * member of each CRTC's &drm_crtc_state structure. See the + * documentation for &drm_crtc_state for more details about the precise + * semantics of this event. + * + * NOTE: + * + * Drivers are not allowed to shut down any display pipe successfully + * enabled through an atomic commit on their own. Doing so can result in + * compositors crashing if a page flip is suddenly rejected because the + * pipe is off. + * + * RETURNS: + * + * 0 on success or one of the below negative error codes: + * + * - -EBUSY, if a nonblocking updated is requested and there is + * an earlier updated pending. Drivers are allowed to support a queue + * of outstanding updates, but currently no driver supports that. + * Note that drivers must wait for preceding updates to complete if a + * synchronous update is requested, they are not allowed to fail the + * commit in that case. + * + * - -ENOMEM, if the driver failed to allocate memory. Specifically + * this can happen when trying to pin framebuffers, which must only + * be done when committing the state. + * + * - -ENOSPC, as a refinement of the more generic -ENOMEM to indicate + * that the driver has run out of vram, iommu space or similar GPU + * address space needed for framebuffer. + * + * - -EIO, if the hardware completely died. + * + * - -EINTR, -EAGAIN or -ERESTARTSYS, if the IOCTL should be restarted. + * This can either be due to a pending signal, or because the driver + * needs to completely bail out to recover from an exceptional + * situation like a GPU hang. From a userspace point of view all errors are + * treated equally. + * + * This list is exhaustive. Specifically this hook is not allowed to + * return -EINVAL (any invalid requests should be caught in + * @atomic_check) or -EDEADLK (this function must not acquire + * additional modeset locks). + */ + int (*atomic_commit)(struct drm_device *dev, + struct drm_atomic_state *state, + bool nonblock); + + /** + * @atomic_state_alloc: + * + * This optional hook can be used by drivers that want to subclass struct + * &drm_atomic_state to be able to track their own driver-private global + * state easily. If this hook is implemented, drivers must also + * implement @atomic_state_clear and @atomic_state_free. + * + * RETURNS: + * + * A new &drm_atomic_state on success or NULL on failure. + */ + struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev); + + /** + * @atomic_state_clear: + * + * This hook must clear any driver private state duplicated into the + * passed-in &drm_atomic_state. This hook is called when the caller + * encountered a &drm_modeset_lock deadlock and needs to drop all + * already acquired locks as part of the deadlock avoidance dance + * implemented in drm_modeset_lock_backoff(). + * + * Any duplicated state must be invalidated since a concurrent atomic + * update might change it, and the drm atomic interfaces always apply + * updates as relative changes to the current state. + * + * Drivers that implement this must call drm_atomic_state_default_clear() + * to clear common state. + */ + void (*atomic_state_clear)(struct drm_atomic_state *state); + + /** + * @atomic_state_free: + * + * This hook needs driver private resources and the &drm_atomic_state + * itself. Note that the core first calls drm_atomic_state_clear() to + * avoid code duplicate between the clear and free hooks. + * + * Drivers that implement this must call drm_atomic_state_default_free() + * to release common resources. + */ + void (*atomic_state_free)(struct drm_atomic_state *state); +}; + +/** + * struct drm_mode_config - Mode configuration control structure + * @mutex: mutex protecting KMS related lists and structures + * @connection_mutex: ww mutex protecting connector state and routing + * @acquire_ctx: global implicit acquire context used by atomic drivers for + * legacy IOCTLs + * @fb_lock: mutex to protect fb state and lists + * @num_fb: number of fbs available + * @fb_list: list of framebuffers available + * @num_encoder: number of encoders on this device + * @encoder_list: list of encoder objects + * @num_overlay_plane: number of overlay planes on this device + * @num_total_plane: number of universal (i.e. with primary/curso) planes on this device + * @plane_list: list of plane objects + * @num_crtc: number of CRTCs on this device + * @crtc_list: list of CRTC objects + * @property_list: list of property objects + * @min_width: minimum pixel width on this device + * @min_height: minimum pixel height on this device + * @max_width: maximum pixel width on this device + * @max_height: maximum pixel height on this device + * @funcs: core driver provided mode setting functions + * @fb_base: base address of the framebuffer + * @poll_enabled: track polling support for this device + * @poll_running: track polling status for this device + * @delayed_event: track delayed poll uevent deliver for this device + * @output_poll_work: delayed work for polling in process context + * @property_blob_list: list of all the blob property objects + * @blob_lock: mutex for blob property allocation and management + * @*_property: core property tracking + * @preferred_depth: preferred RBG pixel depth, used by fb helpers + * @prefer_shadow: hint to userspace to prefer shadow-fb rendering + * @cursor_width: hint to userspace for max cursor width + * @cursor_height: hint to userspace for max cursor height + * @helper_private: mid-layer private data + * + * Core mode resource tracking structure. All CRTC, encoders, and connectors + * enumerated by the driver are added here, as are global properties. Some + * global restrictions are also here, e.g. dimension restrictions. + */ +struct drm_mode_config { + struct mutex mutex; /* protects configuration (mode lists etc.) */ + struct drm_modeset_lock connection_mutex; /* protects connector->encoder and encoder->crtc links */ + struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */ + + /** + * @idr_mutex: + * + * Mutex for KMS ID allocation and management. Protects both @crtc_idr + * and @tile_idr. + */ + struct mutex idr_mutex; + + /** + * @crtc_idr: + * + * Main KMS ID tracking object. Use this idr for all IDs, fb, crtc, + * connector, modes - just makes life easier to have only one. + */ + struct idr crtc_idr; + + /** + * @tile_idr: + * + * Use this idr for allocating new IDs for tiled sinks like use in some + * high-res DP MST screens. + */ + struct idr tile_idr; + + struct mutex fb_lock; /* proctects global and per-file fb lists */ + int num_fb; + struct list_head fb_list; + + /** + * @num_connector: Number of connectors on this device. + */ + int num_connector; + /** + * @connector_ida: ID allocator for connector indices. + */ + struct ida connector_ida; + /** + * @connector_list: List of connector objects. + */ + struct list_head connector_list; + int num_encoder; + struct list_head encoder_list; + + /* + * Track # of overlay planes separately from # of total planes. By + * default we only advertise overlay planes to userspace; if userspace + * sets the "universal plane" capability bit, we'll go ahead and + * expose all planes. + */ + int num_overlay_plane; + int num_total_plane; + struct list_head plane_list; + + int num_crtc; + struct list_head crtc_list; + + struct list_head property_list; + + int min_width, min_height; + int max_width, max_height; + const struct drm_mode_config_funcs *funcs; + resource_size_t fb_base; + + /* output poll support */ + bool poll_enabled; + bool poll_running; + bool delayed_event; + struct delayed_work output_poll_work; + + struct mutex blob_lock; + + /* pointers to standard properties */ + struct list_head property_blob_list; + /** + * @edid_property: Default connector property to hold the EDID of the + * currently connected sink, if any. + */ + struct drm_property *edid_property; + /** + * @dpms_property: Default connector property to control the + * connector's DPMS state. + */ + struct drm_property *dpms_property; + /** + * @path_property: Default connector property to hold the DP MST path + * for the port. + */ + struct drm_property *path_property; + /** + * @tile_property: Default connector property to store the tile + * position of a tiled screen, for sinks which need to be driven with + * multiple CRTCs. + */ + struct drm_property *tile_property; + /** + * @plane_type_property: Default plane property to differentiate + * CURSOR, PRIMARY and OVERLAY legacy uses of planes. + */ + struct drm_property *plane_type_property; + /** + * @prop_src_x: Default atomic plane property for the plane source + * position in the connected &drm_framebuffer. + */ + struct drm_property *prop_src_x; + /** + * @prop_src_y: Default atomic plane property for the plane source + * position in the connected &drm_framebuffer. + */ + struct drm_property *prop_src_y; + /** + * @prop_src_w: Default atomic plane property for the plane source + * position in the connected &drm_framebuffer. + */ + struct drm_property *prop_src_w; + /** + * @prop_src_h: Default atomic plane property for the plane source + * position in the connected &drm_framebuffer. + */ + struct drm_property *prop_src_h; + /** + * @prop_crtc_x: Default atomic plane property for the plane destination + * position in the &drm_crtc is is being shown on. + */ + struct drm_property *prop_crtc_x; + /** + * @prop_crtc_y: Default atomic plane property for the plane destination + * position in the &drm_crtc is is being shown on. + */ + struct drm_property *prop_crtc_y; + /** + * @prop_crtc_w: Default atomic plane property for the plane destination + * position in the &drm_crtc is is being shown on. + */ + struct drm_property *prop_crtc_w; + /** + * @prop_crtc_h: Default atomic plane property for the plane destination + * position in the &drm_crtc is is being shown on. + */ + struct drm_property *prop_crtc_h; + /** + * @prop_fb_id: Default atomic plane property to specify the + * &drm_framebuffer. + */ + struct drm_property *prop_fb_id; + /** + * @prop_crtc_id: Default atomic plane property to specify the + * &drm_crtc. + */ + struct drm_property *prop_crtc_id; + /** + * @prop_active: Default atomic CRTC property to control the active + * state, which is the simplified implementation for DPMS in atomic + * drivers. + */ + struct drm_property *prop_active; + /** + * @prop_mode_id: Default atomic CRTC property to set the mode for a + * CRTC. A 0 mode implies that the CRTC is entirely disabled - all + * connectors must be of and active must be set to disabled, too. + */ + struct drm_property *prop_mode_id; + + /** + * @dvi_i_subconnector_property: Optional DVI-I property to + * differentiate between analog or digital mode. + */ + struct drm_property *dvi_i_subconnector_property; + /** + * @dvi_i_select_subconnector_property: Optional DVI-I property to + * select between analog or digital mode. + */ + struct drm_property *dvi_i_select_subconnector_property; + + /** + * @tv_subconnector_property: Optional TV property to differentiate + * between different TV connector types. + */ + struct drm_property *tv_subconnector_property; + /** + * @tv_select_subconnector_property: Optional TV property to select + * between different TV connector types. + */ + struct drm_property *tv_select_subconnector_property; + /** + * @tv_mode_property: Optional TV property to select + * the output TV mode. + */ + struct drm_property *tv_mode_property; + /** + * @tv_left_margin_property: Optional TV property to set the left + * margin. + */ + struct drm_property *tv_left_margin_property; + /** + * @tv_right_margin_property: Optional TV property to set the right + * margin. + */ + struct drm_property *tv_right_margin_property; + /** + * @tv_top_margin_property: Optional TV property to set the right + * margin. + */ + struct drm_property *tv_top_margin_property; + /** + * @tv_bottom_margin_property: Optional TV property to set the right + * margin. + */ + struct drm_property *tv_bottom_margin_property; + /** + * @tv_brightness_property: Optional TV property to set the + * brightness. + */ + struct drm_property *tv_brightness_property; + /** + * @tv_contrast_property: Optional TV property to set the + * contrast. + */ + struct drm_property *tv_contrast_property; + /** + * @tv_flicker_reduction_property: Optional TV property to control the + * flicker reduction mode. + */ + struct drm_property *tv_flicker_reduction_property; + /** + * @tv_overscan_property: Optional TV property to control the overscan + * setting. + */ + struct drm_property *tv_overscan_property; + /** + * @tv_saturation_property: Optional TV property to set the + * saturation. + */ + struct drm_property *tv_saturation_property; + /** + * @tv_hue_property: Optional TV property to set the hue. + */ + struct drm_property *tv_hue_property; + + /** + * @scaling_mode_property: Optional connector property to control the + * upscaling, mostly used for built-in panels. + */ + struct drm_property *scaling_mode_property; + /** + * @aspect_ratio_property: Optional connector property to control the + * HDMI infoframe aspect ratio setting. + */ + struct drm_property *aspect_ratio_property; + /** + * @degamma_lut_property: Optional CRTC property to set the LUT used to + * convert the framebuffer's colors to linear gamma. + */ + struct drm_property *degamma_lut_property; + /** + * @degamma_lut_size_property: Optional CRTC property for the size of + * the degamma LUT as supported by the driver (read-only). + */ + struct drm_property *degamma_lut_size_property; + /** + * @ctm_property: Optional CRTC property to set the + * matrix used to convert colors after the lookup in the + * degamma LUT. + */ + struct drm_property *ctm_property; + /** + * @gamma_lut_property: Optional CRTC property to set the LUT used to + * convert the colors, after the CTM matrix, to the gamma space of the + * connected screen. + */ + struct drm_property *gamma_lut_property; + /** + * @gamma_lut_size_property: Optional CRTC property for the size of the + * gamma LUT as supported by the driver (read-only). + */ + struct drm_property *gamma_lut_size_property; + + /** + * @suggested_x_property: Optional connector property with a hint for + * the position of the output on the host's screen. + */ + struct drm_property *suggested_x_property; + /** + * @suggested_y_property: Optional connector property with a hint for + * the position of the output on the host's screen. + */ + struct drm_property *suggested_y_property; + + /* dumb ioctl parameters */ + uint32_t preferred_depth, prefer_shadow; + + /** + * @async_page_flip: Does this device support async flips on the primary + * plane? + */ + bool async_page_flip; + + /** + * @allow_fb_modifiers: + * + * Whether the driver supports fb modifiers in the ADDFB2.1 ioctl call. + */ + bool allow_fb_modifiers; + + /* cursor size */ + uint32_t cursor_width, cursor_height; + + struct drm_mode_config_helper_funcs *helper_private; +}; + +void drm_mode_config_init(struct drm_device *dev); +void drm_mode_config_reset(struct drm_device *dev); +void drm_mode_config_cleanup(struct drm_device *dev); + +#endif From 9498c19b3f53e08c61b344ce8dbc92c9c96f23c5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:24 +0100 Subject: [PATCH 39/51] drm: Move tile group code into drm_connector.c And also put the overview section into the KMS Properties part of the docs, instead of randomly-placed within the helpers - this is part of the uabi. With this patch I think drm_crtc.[hc] is cleaned up and entirely documented. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- Documentation/gpu/drm-kms-helpers.rst | 8 -- Documentation/gpu/drm-kms.rst | 6 ++ drivers/gpu/drm/drm_connector.c | 104 ++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 99 ------------------------ include/drm/drm_connector.h | 24 ++++++ include/drm/drm_crtc.h | 15 ---- 6 files changed, 134 insertions(+), 122 deletions(-) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index bb4254d19cbb8..4ca77f675967e 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -261,14 +261,6 @@ Plane Helper Reference .. kernel-doc:: drivers/gpu/drm/drm_plane_helper.c :export: -Tile group -========== - -# FIXME: This should probably be moved into a property documentation section - -.. kernel-doc:: drivers/gpu/drm/drm_crtc.c - :doc: Tile group - Auxiliary Modeset Helpers ========================= diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index a8ff2c87c0e9b..568f3c2b6e46e 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -281,6 +281,12 @@ Color Management Properties .. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c :export: +Tile Group Property +------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_connector.c + :doc: Tile group + Existing KMS Properties ----------------------- diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 2db7fb510b6c9..b5c6a8ee831eb 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1121,3 +1121,107 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, return ret; } + +/** + * DOC: Tile group + * + * Tile groups are used to represent tiled monitors with a unique integer + * identifier. Tiled monitors using DisplayID v1.3 have a unique 8-byte handle, + * we store this in a tile group, so we have a common identifier for all tiles + * in a monitor group. The property is called "TILE". Drivers can manage tile + * groups using drm_mode_create_tile_group(), drm_mode_put_tile_group() and + * drm_mode_get_tile_group(). But this is only needed for internal panels where + * the tile group information is exposed through a non-standard way. + */ + +static void drm_tile_group_free(struct kref *kref) +{ + struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); + struct drm_device *dev = tg->dev; + mutex_lock(&dev->mode_config.idr_mutex); + idr_remove(&dev->mode_config.tile_idr, tg->id); + mutex_unlock(&dev->mode_config.idr_mutex); + kfree(tg); +} + +/** + * drm_mode_put_tile_group - drop a reference to a tile group. + * @dev: DRM device + * @tg: tile group to drop reference to. + * + * drop reference to tile group and free if 0. + */ +void drm_mode_put_tile_group(struct drm_device *dev, + struct drm_tile_group *tg) +{ + kref_put(&tg->refcount, drm_tile_group_free); +} +EXPORT_SYMBOL(drm_mode_put_tile_group); + +/** + * drm_mode_get_tile_group - get a reference to an existing tile group + * @dev: DRM device + * @topology: 8-bytes unique per monitor. + * + * Use the unique bytes to get a reference to an existing tile group. + * + * RETURNS: + * tile group or NULL if not found. + */ +struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, + char topology[8]) +{ + struct drm_tile_group *tg; + int id; + mutex_lock(&dev->mode_config.idr_mutex); + idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { + if (!memcmp(tg->group_data, topology, 8)) { + if (!kref_get_unless_zero(&tg->refcount)) + tg = NULL; + mutex_unlock(&dev->mode_config.idr_mutex); + return tg; + } + } + mutex_unlock(&dev->mode_config.idr_mutex); + return NULL; +} +EXPORT_SYMBOL(drm_mode_get_tile_group); + +/** + * drm_mode_create_tile_group - create a tile group from a displayid description + * @dev: DRM device + * @topology: 8-bytes unique per monitor. + * + * Create a tile group for the unique monitor, and get a unique + * identifier for the tile group. + * + * RETURNS: + * new tile group or error. + */ +struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, + char topology[8]) +{ + struct drm_tile_group *tg; + int ret; + + tg = kzalloc(sizeof(*tg), GFP_KERNEL); + if (!tg) + return ERR_PTR(-ENOMEM); + + kref_init(&tg->refcount); + memcpy(tg->group_data, topology, 8); + tg->dev = dev; + + mutex_lock(&dev->mode_config.idr_mutex); + ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); + if (ret >= 0) { + tg->id = ret; + } else { + kfree(tg); + tg = ERR_PTR(ret); + } + + mutex_unlock(&dev->mode_config.idr_mutex); + return tg; +} +EXPORT_SYMBOL(drm_mode_create_tile_group); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 239b64c85098a..159458b3c287e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -625,102 +625,3 @@ int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj, return ret; } - -/** - * DOC: Tile group - * - * Tile groups are used to represent tiled monitors with a unique - * integer identifier. Tiled monitors using DisplayID v1.3 have - * a unique 8-byte handle, we store this in a tile group, so we - * have a common identifier for all tiles in a monitor group. - */ -static void drm_tile_group_free(struct kref *kref) -{ - struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount); - struct drm_device *dev = tg->dev; - mutex_lock(&dev->mode_config.idr_mutex); - idr_remove(&dev->mode_config.tile_idr, tg->id); - mutex_unlock(&dev->mode_config.idr_mutex); - kfree(tg); -} - -/** - * drm_mode_put_tile_group - drop a reference to a tile group. - * @dev: DRM device - * @tg: tile group to drop reference to. - * - * drop reference to tile group and free if 0. - */ -void drm_mode_put_tile_group(struct drm_device *dev, - struct drm_tile_group *tg) -{ - kref_put(&tg->refcount, drm_tile_group_free); -} - -/** - * drm_mode_get_tile_group - get a reference to an existing tile group - * @dev: DRM device - * @topology: 8-bytes unique per monitor. - * - * Use the unique bytes to get a reference to an existing tile group. - * - * RETURNS: - * tile group or NULL if not found. - */ -struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, - char topology[8]) -{ - struct drm_tile_group *tg; - int id; - mutex_lock(&dev->mode_config.idr_mutex); - idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) { - if (!memcmp(tg->group_data, topology, 8)) { - if (!kref_get_unless_zero(&tg->refcount)) - tg = NULL; - mutex_unlock(&dev->mode_config.idr_mutex); - return tg; - } - } - mutex_unlock(&dev->mode_config.idr_mutex); - return NULL; -} -EXPORT_SYMBOL(drm_mode_get_tile_group); - -/** - * drm_mode_create_tile_group - create a tile group from a displayid description - * @dev: DRM device - * @topology: 8-bytes unique per monitor. - * - * Create a tile group for the unique monitor, and get a unique - * identifier for the tile group. - * - * RETURNS: - * new tile group or error. - */ -struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, - char topology[8]) -{ - struct drm_tile_group *tg; - int ret; - - tg = kzalloc(sizeof(*tg), GFP_KERNEL); - if (!tg) - return ERR_PTR(-ENOMEM); - - kref_init(&tg->refcount); - memcpy(tg->group_data, topology, 8); - tg->dev = dev; - - mutex_lock(&dev->mode_config.idr_mutex); - ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL); - if (ret >= 0) { - tg->id = ret; - } else { - kfree(tg); - tg = ERR_PTR(ret); - } - - mutex_unlock(&dev->mode_config.idr_mutex); - return tg; -} -EXPORT_SYMBOL(drm_mode_create_tile_group); diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 3e9727264b65f..34f9741ebb5b3 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -774,6 +774,30 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector); int drm_mode_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid); +/** + * struct drm_tile_group - Tile group metadata + * @refcount: reference count + * @dev: DRM device + * @id: tile group id exposed to userspace + * @group_data: Sink-private data identifying this group + * + * @group_data corresponds to displayid vend/prod/serial for external screens + * with an EDID. + */ +struct drm_tile_group { + struct kref refcount; + struct drm_device *dev; + int id; + u8 group_data[8]; +}; + +struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, + char topology[8]); +struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, + char topology[8]); +void drm_mode_put_tile_group(struct drm_device *dev, + struct drm_tile_group *tg); + /** * drm_for_each_connector - iterate over all connectors * @connector: the loop cursor diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 98de488a95a5c..cf96b393091a8 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -67,14 +67,6 @@ static inline uint64_t I642U64(int64_t val) return (uint64_t)*((uint64_t *)&val); } -/* data corresponds to displayid vend/prod/serial */ -struct drm_tile_group { - struct kref refcount; - struct drm_device *dev; - int id; - u8 group_data[8]; -}; - struct drm_crtc; struct drm_encoder; struct drm_pending_vblank_event; @@ -810,13 +802,6 @@ extern int drm_crtc_force_disable_all(struct drm_device *dev); extern int drm_mode_set_config_internal(struct drm_mode_set *set); -extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, - char topology[8]); -extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev, - char topology[8]); -extern void drm_mode_put_tile_group(struct drm_device *dev, - struct drm_tile_group *tg); - /* Helpers */ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, uint32_t id) From edd420eaffb3a618ddc8740683abc039ad97237f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 12:58:25 +0100 Subject: [PATCH 40/51] drm: Drop externs from drm_crtc.h Just noise. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114115825.22050-11-daniel.vetter@ffwll.ch --- include/drm/drm_crtc.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index cf96b393091a8..bcc1a4d1d1a67 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -762,14 +762,14 @@ struct drm_mode_set { #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) -extern __printf(6, 7) +__printf(6, 7) int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, struct drm_plane *cursor, const struct drm_crtc_funcs *funcs, const char *name, ...); -extern void drm_crtc_cleanup(struct drm_crtc *crtc); +void drm_crtc_cleanup(struct drm_crtc *crtc); /** * drm_crtc_index - find the index of a registered CRTC @@ -795,12 +795,12 @@ static inline uint32_t drm_crtc_mask(const struct drm_crtc *crtc) return 1 << drm_crtc_index(crtc); } -extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, - int *hdisplay, int *vdisplay); -extern int drm_crtc_force_disable(struct drm_crtc *crtc); -extern int drm_crtc_force_disable_all(struct drm_device *dev); +void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, + int *hdisplay, int *vdisplay); +int drm_crtc_force_disable(struct drm_crtc *crtc); +int drm_crtc_force_disable_all(struct drm_device *dev); -extern int drm_mode_set_config_internal(struct drm_mode_set *set); +int drm_mode_set_config_internal(struct drm_mode_set *set); /* Helpers */ static inline struct drm_crtc *drm_crtc_find(struct drm_device *dev, From 717fd813b8130e36971205af09b0e6a5e6d3c433 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 26 Sep 2016 11:04:37 +0200 Subject: [PATCH 41/51] drm/color: document NULL values and default settings better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brought up in a discussion for enabling gamma on fsl-dcu. Cc: Ville Syrjälä Cc: Meng Yi Cc: Lionel Landwerlin Reviewed-by: Lionel Landwerlin Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20160926090437.22676-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_color_mgmt.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c index d28ffdd2b9298..6543ebde501a7 100644 --- a/drivers/gpu/drm/drm_color_mgmt.c +++ b/drivers/gpu/drm/drm_color_mgmt.c @@ -41,6 +41,10 @@ * nor use all the elements of the LUT (for example the hardware might * choose to interpolate between LUT[0] and LUT[4]). * + * Setting this to NULL (blob property value set to 0) means a + * linear/pass-thru gamma table should be used. This is generally the + * driver boot-up state too. + * * “DEGAMMA_LUT_SIZE”: * Unsinged range property to give the size of the lookup table to be set * on the DEGAMMA_LUT property (the size depends on the underlying @@ -54,6 +58,10 @@ * lookup through the gamma LUT. The data is interpreted as a struct * &drm_color_ctm. * + * Setting this to NULL (blob property value set to 0) means a + * unit/pass-thru matrix should be used. This is generally the driver + * boot-up state too. + * * “GAMMA_LUT”: * Blob property to set the gamma lookup table (LUT) mapping pixel data * after the transformation matrix to data sent to the connector. The @@ -62,6 +70,10 @@ * nor use all the elements of the LUT (for example the hardware might * choose to interpolate between LUT[0] and LUT[4]). * + * Setting this to NULL (blob property value set to 0) means a + * linear/pass-thru gamma table should be used. This is generally the + * driver boot-up state too. + * * “GAMMA_LUT_SIZE”: * Unsigned range property to give the size of the lookup table to be set * on the GAMMA_LUT property (the size depends on the underlying hardware). From 778e1a5419ce2f535c71ec54f483703323a2462f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 10:02:50 +0100 Subject: [PATCH 42/51] drm/amdgpu: Use drm_crtc_vblank_on/off for dce6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This old code pattern was reintroduced in Author: Ken Wang Date: Tue Jan 19 14:03:24 2016 +0800 drm/amdgpu: add display controller implementation for si v10 Realign it with later display code. Tsk, tsk for massive copypasting ;-) Cc: Christian König Cc: Ken Wang Cc: Alex Deucher Acked-by: Christian König for the whole series. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114090255.31595-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index c1bd1beab655c..bc9f2f423270d 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -2040,13 +2040,13 @@ static void dce_v6_0_crtc_dpms(struct drm_crtc *crtc, int mode) type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); amdgpu_irq_update(adev, &adev->pageflip_irq, type); - drm_vblank_post_modeset(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_on(crtc); dce_v6_0_crtc_load_lut(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_pre_modeset(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_off(crtc); if (amdgpu_crtc->enabled) amdgpu_atombios_crtc_blank(crtc, ATOM_ENABLE); amdgpu_atombios_crtc_enable(crtc, ATOM_DISABLE); From 9bc6db0d9127d60ed1fc7a548f813f957a3cfd28 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 15 Nov 2016 22:58:19 +0100 Subject: [PATCH 43/51] drm/nouveau: Use drm_crtc_vblank_off/on With atomic nv50+ is already converted over to them, but the old display code is still using it. Found in a 2 year old patch I have lying around to un-export these old helpers! v2: Drop the hand-rolled versions from resume/suspend code. Now that crtc callbacks do this, we don't need a special case for s/r anymore. v3: Remove unused variables. v4: Don't remove drm_crtc_vblank_off from suspend paths, non-atomic nouveau still needs that. But still switch to drm_crtc_vblank_off since drm_vblank_off will disappear. Cc: Mario Kleiner Cc: Ben Skeggs Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114114101.21731-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 4 ++-- drivers/gpu/drm/nouveau/nouveau_display.c | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 0cb7a18cde261..59d1d1c5de5f2 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -702,7 +702,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc) if (nv_two_heads(dev)) NVSetOwner(dev, nv_crtc->index); - drm_vblank_pre_modeset(dev, nv_crtc->index); + drm_crtc_vblank_off(crtc); funcs->dpms(crtc, DRM_MODE_DPMS_OFF); NVBlankScreen(dev, nv_crtc->index, true); @@ -734,7 +734,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc) #endif funcs->dpms(crtc, DRM_MODE_DPMS_ON); - drm_vblank_post_modeset(dev, nv_crtc->index); + drm_crtc_vblank_on(crtc); } static void nv_crtc_destroy(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 75c90a8da18a6..5698687bc1974 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -380,14 +380,14 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; - int head; + struct drm_crtc *crtc; if (!suspend) drm_crtc_force_disable_all(dev); /* Make sure that drm and hw vblank irqs get properly disabled. */ - for (head = 0; head < dev->mode_config.num_crtc; head++) - drm_vblank_off(dev, head); + drm_for_each_crtc(crtc, dev) + drm_crtc_vblank_off(crtc); /* disable flip completion events */ nvif_notify_put(&drm->flip); @@ -723,7 +723,7 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; - int ret, head; + int ret; if (dev->mode_config.funcs->atomic_commit) { nouveau_display_init(dev); @@ -777,10 +777,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) drm_helper_resume_force_mode(dev); - /* Make sure that drm and hw vblank irqs get resumed if needed. */ - for (head = 0; head < dev->mode_config.num_crtc; head++) - drm_vblank_on(dev, head); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); From 07600c536341f3062055548409cc0c8e1a862198 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 10:02:52 +0100 Subject: [PATCH 44/51] drm/irq: Make drm_vblank_pre/post_modeset internal Now that all drivers are switched over to drm_crtc_vblank_on/off we can relegate pre/post_modeset to the purely drm_irq.c internal role of supporting old ums userspace. As usual switch to the drm_legacy_ prefix to make it clear this is for old drivers only. v2: Rebase on top of Thierry's s/int crtc/unsigned int pipe/ changes. Cc: Ben Skeggs Cc: Alex Deucher Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 43 ++++++--------------------------------- include/drm/drmP.h | 4 ---- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 48a6167f5e7ba..2fb5861b04b77 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1445,30 +1445,8 @@ void drm_crtc_vblank_on(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_on); -/** - * drm_vblank_pre_modeset - account for vblanks across mode sets - * @dev: DRM device - * @pipe: CRTC index - * - * Account for vblank events across mode setting events, which will likely - * reset the hardware frame counter. - * - * This is done by grabbing a temporary vblank reference to ensure that the - * vblank interrupt keeps running across the modeset sequence. With this the - * software-side vblank frame counting will ensure that there are no jumps or - * discontinuities. - * - * Unfortunately this approach is racy and also doesn't work when the vblank - * interrupt stops running, e.g. across system suspend resume. It is therefore - * highly recommended that drivers use the newer drm_vblank_off() and - * drm_vblank_on() instead. drm_vblank_pre_modeset() only works correctly when - * using "cooked" software vblank frame counters and not relying on any hardware - * counters. - * - * Drivers must call drm_vblank_post_modeset() when re-enabling the same crtc - * again. - */ -void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe) +static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, + unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; @@ -1492,17 +1470,9 @@ void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe) vblank->inmodeset |= 0x2; } } -EXPORT_SYMBOL(drm_vblank_pre_modeset); -/** - * drm_vblank_post_modeset - undo drm_vblank_pre_modeset changes - * @dev: DRM device - * @pipe: CRTC index - * - * This function again drops the temporary vblank reference acquired in - * drm_vblank_pre_modeset. - */ -void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) +static void drm_legacy_vblank_post_modeset(struct drm_device *dev, + unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; @@ -1525,7 +1495,6 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) vblank->inmodeset = 0; } } -EXPORT_SYMBOL(drm_vblank_post_modeset); /* * drm_modeset_ctl - handle vblank event counter changes across mode switch @@ -1558,10 +1527,10 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, switch (modeset->cmd) { case _DRM_PRE_MODESET: - drm_vblank_pre_modeset(dev, pipe); + drm_legacy_vblank_pre_modeset(dev, pipe); break; case _DRM_POST_MODESET: - drm_vblank_post_modeset(dev, pipe); + drm_legacy_vblank_post_modeset(dev, pipe); break; default: return -EINVAL; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 96a620ffd2989..b352a7b812e6c 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -727,10 +727,6 @@ void drm_clflush_virt_range(void *addr, unsigned long length); * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. */ -/* Modesetting support */ -extern void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe); -extern void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe); - /* Debugfs support */ #if defined(CONFIG_DEBUG_FS) extern int drm_debugfs_create_files(const struct drm_info_list *files, From d6b0f626375739b1faa2d9dfbca335a923b2a760 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 10:02:53 +0100 Subject: [PATCH 45/51] drm/irq: Unexport drm_vblank_count No one outside of drm_irq.c should ever need this. The correct way to implement get_vblank_count for hw lacking a vblank counter is drm_vblank_no_hw_counter. Fix this up in mtk, which is the only offender left over. Cc: CK Hu Cc: Philipp Zabel Acked-by: Philipp Zabel Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114090255.31595-4-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_irq.c | 37 +++++++------------------- drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 +- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 2fb5861b04b77..1681e919b8661 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -234,6 +234,16 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, store_vblank(dev, pipe, diff, &t_vblank, cur_vblank); } +static u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe) +{ + struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; + + if (WARN_ON(pipe >= dev->num_crtcs)) + return 0; + + return vblank->count; +} + /** * drm_accurate_vblank_count - retrieve the master vblank counter * @crtc: which counter to retrieve @@ -887,31 +897,6 @@ drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe, return false; } -/** - * drm_vblank_count - retrieve "cooked" vblank counter value - * @dev: DRM device - * @pipe: index of CRTC for which to retrieve the counter - * - * Fetches the "cooked" vblank count value that represents the number of - * vblank events since the system was booted, including lost events due to - * modesetting activity. - * - * This is the legacy version of drm_crtc_vblank_count(). - * - * Returns: - * The software vblank counter. - */ -u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe) -{ - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - - if (WARN_ON(pipe >= dev->num_crtcs)) - return 0; - - return vblank->count; -} -EXPORT_SYMBOL(drm_vblank_count); - /** * drm_crtc_vblank_count - retrieve "cooked" vblank counter value * @crtc: which counter to retrieve @@ -920,8 +905,6 @@ EXPORT_SYMBOL(drm_vblank_count); * vblank events since the system was booted, including lost events due to * modesetting activity. * - * This is the native KMS version of drm_vblank_count(). - * * Returns: * The software vblank counter. */ diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index d90152e85ed0f..4b7fe7eaec014 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -256,7 +256,7 @@ static struct drm_driver mtk_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, - .get_vblank_counter = drm_vblank_count, + .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = mtk_drm_crtc_enable_vblank, .disable_vblank = mtk_drm_crtc_disable_vblank, From 2d1e331fa942c963a92f50e3a2a5761fee006369 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 10:02:54 +0100 Subject: [PATCH 46/51] drm/irq: Unexport drm_vblank_on/off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only remaining use was in amdgpu, and trivial to convert over to drm_crtc_vblank_* variants. Cc: Alex Deucher Cc: Christian König Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114090255.31595-5-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 4 +- drivers/gpu/drm/drm_irq.c | 80 +++++++----------------- include/drm/drm_irq.h | 3 - 3 files changed, 23 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index cc85676a68d9f..81cbf0b05dff1 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -214,12 +214,12 @@ static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) /* Make sure VBLANK interrupts are still enabled */ type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); amdgpu_irq_update(adev, &adev->crtc_irq, type); - drm_vblank_on(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_on(crtc); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - drm_vblank_off(dev, amdgpu_crtc->crtc_id); + drm_crtc_vblank_off(crtc); amdgpu_crtc->enabled = false; break; } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 1681e919b8661..273625a850369 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -93,7 +93,7 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe, * Reset the stored timestamp for the current vblank count to correspond * to the last vblank occurred. * - * Only to be called from drm_vblank_on(). + * Only to be called from drm_crtc_vblank_on(). * * Note: caller must hold dev->vbl_lock since this reads & writes * device vblank fields. @@ -306,7 +306,7 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) * Always update the count and timestamp to maintain the * appearance that the counter has been ticking all along until * this time. This makes the count account for the entire time - * between drm_vblank_on() and drm_vblank_off(). + * between drm_crtc_vblank_on() and drm_crtc_vblank_off(). */ drm_update_vblank_count(dev, pipe, 0); @@ -1255,21 +1255,20 @@ void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_crtc_wait_one_vblank); /** - * drm_vblank_off - disable vblank events on a CRTC - * @dev: DRM device - * @pipe: CRTC index + * drm_crtc_vblank_off - disable vblank events on a CRTC + * @crtc: CRTC in question * * Drivers can use this function to shut down the vblank interrupt handling when * disabling a crtc. This function ensures that the latest vblank frame count is - * stored so that drm_vblank_on() can restore it again. + * stored so that drm_vblank_on can restore it again. * * Drivers must use this function when the hardware vblank counter can get * reset, e.g. when suspending. - * - * This is the legacy version of drm_crtc_vblank_off(). */ -void drm_vblank_off(struct drm_device *dev, unsigned int pipe) +void drm_crtc_vblank_off(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_pending_vblank_event *e, *t; struct timeval now; @@ -1285,7 +1284,8 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe) DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", pipe, vblank->enabled, vblank->inmodeset); - /* Avoid redundant vblank disables without previous drm_vblank_on(). */ + /* Avoid redundant vblank disables without previous + * drm_crtc_vblank_on(). */ if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset) vblank_disable_and_save(dev, pipe); @@ -1316,25 +1316,6 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe) } spin_unlock_irqrestore(&dev->event_lock, irqflags); } -EXPORT_SYMBOL(drm_vblank_off); - -/** - * drm_crtc_vblank_off - disable vblank events on a CRTC - * @crtc: CRTC in question - * - * Drivers can use this function to shut down the vblank interrupt handling when - * disabling a crtc. This function ensures that the latest vblank frame count is - * stored so that drm_vblank_on can restore it again. - * - * Drivers must use this function when the hardware vblank counter can get - * reset, e.g. when suspending. - * - * This is the native kms version of drm_vblank_off(). - */ -void drm_crtc_vblank_off(struct drm_crtc *crtc) -{ - drm_vblank_off(crtc->dev, drm_crtc_index(crtc)); -} EXPORT_SYMBOL(drm_crtc_vblank_off); /** @@ -1370,19 +1351,18 @@ void drm_crtc_vblank_reset(struct drm_crtc *crtc) EXPORT_SYMBOL(drm_crtc_vblank_reset); /** - * drm_vblank_on - enable vblank events on a CRTC - * @dev: DRM device - * @pipe: CRTC index + * drm_crtc_vblank_on - enable vblank events on a CRTC + * @crtc: CRTC in question * * This functions restores the vblank interrupt state captured with - * drm_vblank_off() again. Note that calls to drm_vblank_on() and - * drm_vblank_off() can be unbalanced and so can also be unconditionally called + * drm_crtc_vblank_off() again. Note that calls to drm_crtc_vblank_on() and + * drm_crtc_vblank_off() can be unbalanced and so can also be unconditionally called * in driver load code to reflect the current hardware state of the crtc. - * - * This is the legacy version of drm_crtc_vblank_on(). */ -void drm_vblank_on(struct drm_device *dev, unsigned int pipe) +void drm_crtc_vblank_on(struct drm_crtc *crtc) { + struct drm_device *dev = crtc->dev; + unsigned int pipe = drm_crtc_index(crtc); struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; @@ -1409,23 +1389,6 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) WARN_ON(drm_vblank_enable(dev, pipe)); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } -EXPORT_SYMBOL(drm_vblank_on); - -/** - * drm_crtc_vblank_on - enable vblank events on a CRTC - * @crtc: CRTC in question - * - * This functions restores the vblank interrupt state captured with - * drm_vblank_off() again. Note that calls to drm_vblank_on() and - * drm_vblank_off() can be unbalanced and so can also be unconditionally called - * in driver load code to reflect the current hardware state of the crtc. - * - * This is the native kms version of drm_vblank_on(). - */ -void drm_crtc_vblank_on(struct drm_crtc *crtc) -{ - drm_vblank_on(crtc->dev, drm_crtc_index(crtc)); -} EXPORT_SYMBOL(drm_crtc_vblank_on); static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, @@ -1548,11 +1511,10 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, spin_lock_irqsave(&dev->event_lock, flags); /* - * drm_vblank_off() might have been called after we called - * drm_vblank_get(). drm_vblank_off() holds event_lock - * around the vblank disable, so no need for further locking. - * The reference from drm_vblank_get() protects against - * vblank disable from another source. + * drm_crtc_vblank_off() might have been called after we called + * drm_vblank_get(). drm_crtc_vblank_off() holds event_lock around the + * vblank disable, so no need for further locking. The reference from + * drm_vblank_get() protects against vblank disable from another source. */ if (!vblank->enabled) { ret = -EINVAL; diff --git a/include/drm/drm_irq.h b/include/drm/drm_irq.h index 2401b14d301f6..92e59d0a5ddb8 100644 --- a/include/drm/drm_irq.h +++ b/include/drm/drm_irq.h @@ -136,7 +136,6 @@ extern int drm_irq_uninstall(struct drm_device *dev); extern int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs); extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); -extern u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe); extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc); extern u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, struct timeval *vblanktime); @@ -150,8 +149,6 @@ extern int drm_crtc_vblank_get(struct drm_crtc *crtc); extern void drm_crtc_vblank_put(struct drm_crtc *crtc); extern void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe); extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); -extern void drm_vblank_off(struct drm_device *dev, unsigned int pipe); -extern void drm_vblank_on(struct drm_device *dev, unsigned int pipe); extern void drm_crtc_vblank_off(struct drm_crtc *crtc); extern void drm_crtc_vblank_reset(struct drm_crtc *crtc); extern void drm_crtc_vblank_on(struct drm_crtc *crtc); From b9876d5061a068ba647c8b9923aff8c975bb73a3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 14 Nov 2016 10:02:55 +0100 Subject: [PATCH 47/51] drm: drm_irq.h header cleanup - Drop extern for functions, it's noise. - Move&consolidate drm.ko internal parts into drm-internal.h. Reviewed-by: Alex Deucher Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161114090255.31595-6-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_internal.h | 8 +++-- include/drm/drm_irq.h | 60 ++++++++++++++++------------------ 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index b8cc0fc6d44cd..db80ec860e339 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -24,9 +24,6 @@ #define DRM_IF_MAJOR 1 #define DRM_IF_MINOR 4 -/* drm_irq.c */ -extern unsigned int drm_timestamp_monotonic; - /* drm_fops.c */ extern struct mutex drm_global_mutex; void drm_lastclose(struct drm_device *dev); @@ -56,6 +53,11 @@ int drm_clients_info(struct seq_file *m, void* data); int drm_gem_name_info(struct seq_file *m, void *data); /* drm_irq.c */ +extern unsigned int drm_timestamp_monotonic; + +/* IOCTLS */ +int drm_wait_vblank(struct drm_device *dev, void *data, + struct drm_file *filp); int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_modeset_ctl(struct drm_device *dev, void *data, diff --git a/include/drm/drm_irq.h b/include/drm/drm_irq.h index 92e59d0a5ddb8..293d08caab60e 100644 --- a/include/drm/drm_irq.h +++ b/include/drm/drm_irq.h @@ -130,39 +130,37 @@ struct drm_vblank_crtc { bool enabled; }; -extern int drm_irq_install(struct drm_device *dev, int irq); -extern int drm_irq_uninstall(struct drm_device *dev); +int drm_irq_install(struct drm_device *dev, int irq); +int drm_irq_uninstall(struct drm_device *dev); -extern int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs); -extern int drm_wait_vblank(struct drm_device *dev, void *data, - struct drm_file *filp); -extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc); -extern u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, - struct timeval *vblanktime); -extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc, - struct drm_pending_vblank_event *e); -extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, - struct drm_pending_vblank_event *e); -extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe); -extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc); -extern int drm_crtc_vblank_get(struct drm_crtc *crtc); -extern void drm_crtc_vblank_put(struct drm_crtc *crtc); -extern void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe); -extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); -extern void drm_crtc_vblank_off(struct drm_crtc *crtc); -extern void drm_crtc_vblank_reset(struct drm_crtc *crtc); -extern void drm_crtc_vblank_on(struct drm_crtc *crtc); -extern void drm_vblank_cleanup(struct drm_device *dev); -extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc); -extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe); +int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs); +u32 drm_crtc_vblank_count(struct drm_crtc *crtc); +u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, + struct timeval *vblanktime); +void drm_crtc_send_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e); +void drm_crtc_arm_vblank_event(struct drm_crtc *crtc, + struct drm_pending_vblank_event *e); +bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe); +bool drm_crtc_handle_vblank(struct drm_crtc *crtc); +int drm_crtc_vblank_get(struct drm_crtc *crtc); +void drm_crtc_vblank_put(struct drm_crtc *crtc); +void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe); +void drm_crtc_wait_one_vblank(struct drm_crtc *crtc); +void drm_crtc_vblank_off(struct drm_crtc *crtc); +void drm_crtc_vblank_reset(struct drm_crtc *crtc); +void drm_crtc_vblank_on(struct drm_crtc *crtc); +void drm_vblank_cleanup(struct drm_device *dev); +u32 drm_accurate_vblank_count(struct drm_crtc *crtc); +u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe); -extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, - unsigned int pipe, int *max_error, - struct timeval *vblank_time, - unsigned flags, - const struct drm_display_mode *mode); -extern void drm_calc_timestamping_constants(struct drm_crtc *crtc, - const struct drm_display_mode *mode); +int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, + unsigned int pipe, int *max_error, + struct timeval *vblank_time, + unsigned flags, + const struct drm_display_mode *mode); +void drm_calc_timestamping_constants(struct drm_crtc *crtc, + const struct drm_display_mode *mode); /** * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC From 19423ba7109a94dfb3beda88f9dcced54e4831d8 Mon Sep 17 00:00:00 2001 From: Jianqun Xu Date: Wed, 16 Nov 2016 08:13:39 +0800 Subject: [PATCH 48/51] drm/bridge: analogix_dp: return error if transfer none byte Reference from drm_dp_aux description (about transfer): Upon success, the implementation should return the number of payload bytes that were transferred, or a negative error-code on failure. Helpers propagate errors from the .transfer() function, with the exception of the -EBUSY error, which causes a transaction to be retried. On a short, helpers will return -EPROTO to make it simpler to check for failure. The analogix_dp_transfer will return num_transferred, but if there is none byte been transferred, the return value will be 0, which means success, we should return error-code if transfer none byte. for (retry = 0; retry < 32; retry++) { err = aux->transfer(aux, &msg); if (err < 0) { if (err == -EBUSY) continue; goto unlock; } } Cc: zain wang Reviewed-by: Sean Paul Signed-off-by: Jianqun Xu Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/1479255219-7243-1-git-send-email-jay.xu@rock-chips.com --- drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index cd37ac058675f..303083ad28e3f 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -1162,5 +1162,5 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) msg->reply = DP_AUX_NATIVE_REPLY_ACK; - return num_transferred; + return num_transferred > 0 ? num_transferred : -EBUSY; } From 9626014258a5957ff120b3987ee72decdbe0c798 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 15 Nov 2016 22:06:39 +0900 Subject: [PATCH 49/51] drm/fence: add in-fences support There is now a new property called IN_FENCE_FD attached to every plane state that receives sync_file fds from userspace via the atomic commit IOCTL. The fd is then translated to a fence (that may be a fence_array subclass or just a normal fence) and then used by DRM to fence_wait() for all fences in the sync_file to signal. So it only commits when all framebuffers are ready to scanout. v2: Comments by Daniel Vetter: - remove set state->fence = NULL in destroy phase - accept fence -1 as valid and just return 0 - do not call fence_get() - sync_file_fences_get() already calls it - fence_put() if state->fence is already set, in case userspace set the property more than once. v3: WARN_ON if fence is set but state has no FB v4: Comment from Maarten Lankhorst - allow set fence with no related fb v5: rename FENCE_FD to IN_FENCE_FD v6: Comments by Daniel Vetter: - rename plane_state->in_fence back to "fence" - re-introduce WARN_ON if fence set but no fb - rebase after fence -> dma_fence rename v7: Comments by Brian Starkey - set state->fence to NULL when duplicating the state - fail if IN_FENCE_FD was already set v8: rebase against latest drm-misc Signed-off-by: Gustavo Padovan Reviewed-by: Brian Starkey Reviewed-by: Sean Paul Tested-by: Robert Foss [danvet: Rebase onto extracted drm_mode_config.[hc].] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/drm_atomic.c | 14 ++++++++++++++ drivers/gpu/drm/drm_atomic_helper.c | 5 +++++ drivers/gpu/drm/drm_mode_config.c | 6 ++++++ drivers/gpu/drm/drm_plane.c | 1 + include/drm/drm_mode_config.h | 5 +++++ 6 files changed, 32 insertions(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 863cdcad9f902..95fc0410e129c 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -12,6 +12,7 @@ menuconfig DRM select I2C select I2C_ALGOBIT select DMA_SHARED_BUFFER + select SYNC_FILE help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 57e0a6e96f6d6..3ad780ad24f9a 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "drm_crtc_internal.h" @@ -712,6 +713,17 @@ int drm_atomic_plane_set_property(struct drm_plane *plane, drm_atomic_set_fb_for_plane(state, fb); if (fb) drm_framebuffer_unreference(fb); + } else if (property == config->prop_in_fence_fd) { + if (state->fence) + return -EINVAL; + + if (U642I64(val) == -1) + return 0; + + state->fence = sync_file_get_fence(val); + if (!state->fence) + return -EINVAL; + } else if (property == config->prop_crtc_id) { struct drm_crtc *crtc = drm_crtc_find(dev, val); return drm_atomic_set_crtc_for_plane(state, crtc); @@ -773,6 +785,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane, if (property == config->prop_fb_id) { *val = (state->fb) ? state->fb->base.id : 0; + } else if (property == config->prop_in_fence_fd) { + *val = -1; } else if (property == config->prop_crtc_id) { *val = (state->crtc) ? state->crtc->base.id : 0; } else if (property == config->prop_crtc_x) { diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 50077961228ab..0b16587cdc629 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3072,6 +3072,8 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, if (state->fb) drm_framebuffer_reference(state->fb); + + state->fence = NULL; } EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); @@ -3110,6 +3112,9 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) { if (state->fb) drm_framebuffer_unreference(state->fb); + + if (state->fence) + dma_fence_put(state->fence); } EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 6f80886ed40b1..8bee2addf7b4e 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -308,6 +308,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_fb_id = prop; + prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC, + "IN_FENCE_FD", -1, INT_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_in_fence_fd = prop; + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, "CRTC_ID", DRM_MODE_OBJECT_CRTC); if (!prop) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 2ba0c221bf1bc..419ac313c36fa 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -137,6 +137,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&plane->base, config->prop_fb_id, 0); + drm_object_attach_property(&plane->base, config->prop_in_fence_fd, -1); drm_object_attach_property(&plane->base, config->prop_crtc_id, 0); drm_object_attach_property(&plane->base, config->prop_crtc_x, 0); drm_object_attach_property(&plane->base, config->prop_crtc_y, 0); diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 5d11b258512df..c6754ccefe2b6 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -480,6 +480,11 @@ struct drm_mode_config { * &drm_framebuffer. */ struct drm_property *prop_fb_id; + /** + * @prop_in_fence_fd: Sync File fd representing the incoming fences + * for a Plane. + */ + struct drm_property *prop_in_fence_fd; /** * @prop_crtc_id: Default atomic plane property to specify the * &drm_crtc. From 6d6003c4b613c93973e4e870d83f4bed2ad9ac34 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Tue, 15 Nov 2016 23:37:08 +0900 Subject: [PATCH 50/51] drm/fence: add fence timeline to drm_crtc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create one timeline context for each CRTC to be able to handle out-fences and signal them. It adds a few members to struct drm_crtc: fence_context, where we store the context we get from fence_context_alloc(), the fence seqno and the fence lock, that we pass in fence_init() to be used by the fence. v2: Comment by Daniel Stone: - add BUG_ON() to fence_to_crtc() macro v3: Comment by Ville Syrjälä - Use more meaningful name as crtc timeline name v4: Comments by Brian Starkey - Use even more meaninful name for the crtc timeline - add doc for timeline_name Comment by Daniel Vetter - use in-line style for comments - rebase after fence -> dma_fence rename v5: Comment by Daniel Vetter - Add doc for drm_crtc_fence_ops v6: Comment by Chris Wilson - Move fence_to_crtc to drm_crtc.c - Move export of drm_crtc_fence_ops to drm_crtc_internal.h - rebase against latest drm-misc Signed-off-by: Gustavo Padovan Reviewed-by: Daniel Vetter (v5) Reviewed-by: Sean Paul (v5) Tested-by: Robert Foss (v5) Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479220628-10204-1-git-send-email-gustavo@padovan.org --- drivers/gpu/drm/drm_crtc.c | 38 +++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc_internal.h | 2 ++ include/drm/drm_crtc.h | 29 ++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 159458b3c287e..dbfae422241e0 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,38 @@ static void drm_crtc_crc_fini(struct drm_crtc *crtc) #endif } +static struct drm_crtc *fence_to_crtc(struct dma_fence *fence) +{ + BUG_ON(fence->ops != &drm_crtc_fence_ops); + return container_of(fence->lock, struct drm_crtc, fence_lock); +} + +static const char *drm_crtc_fence_get_driver_name(struct dma_fence *fence) +{ + struct drm_crtc *crtc = fence_to_crtc(fence); + + return crtc->dev->driver->name; +} + +static const char *drm_crtc_fence_get_timeline_name(struct dma_fence *fence) +{ + struct drm_crtc *crtc = fence_to_crtc(fence); + + return crtc->timeline_name; +} + +static bool drm_crtc_fence_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +const struct dma_fence_ops drm_crtc_fence_ops = { + .get_driver_name = drm_crtc_fence_get_driver_name, + .get_timeline_name = drm_crtc_fence_get_timeline_name, + .enable_signaling = drm_crtc_fence_enable_signaling, + .wait = dma_fence_default_wait, +}; + /** * drm_crtc_init_with_planes - Initialise a new CRTC object with * specified primary and cursor planes. @@ -208,6 +241,11 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, return -ENOMEM; } + crtc->fence_context = dma_fence_context_alloc(1); + spin_lock_init(&crtc->fence_lock); + snprintf(crtc->timeline_name, sizeof(crtc->timeline_name), + "CRTC:%d-%s", crtc->base.id, crtc->name); + crtc->base.properties = &crtc->properties; list_add_tail(&crtc->head, &config->crtc_list); diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index f78d5aaf7e911..33b17d0b127e7 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -43,6 +43,8 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc, int drm_crtc_register_all(struct drm_device *dev); void drm_crtc_unregister_all(struct drm_device *dev); +extern const struct dma_fence_ops drm_crtc_fence_ops; + /* IOCTLs */ int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index bcc1a4d1d1a67..946672f97e1e1 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -731,6 +731,35 @@ struct drm_crtc { */ struct drm_crtc_crc crc; #endif + + /** + * @fence_context: + * + * timeline context used for fence operations. + */ + unsigned int fence_context; + + /** + * @fence_lock: + * + * spinlock to protect the fences in the fence_context. + */ + + spinlock_t fence_lock; + /** + * @fence_seqno: + * + * Seqno variable used as monotonic counter for the fences + * created on the CRTC's timeline. + */ + unsigned long fence_seqno; + + /** + * @timeline_name: + * + * The name of the CRTC's fence timeline. + */ + char timeline_name[32]; }; /** From beaf5af48034c9e2ebb8b2b1fb12dc4d8aeba99e Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Wed, 16 Nov 2016 22:00:21 +0900 Subject: [PATCH 51/51] drm/fence: add out-fences support Support DRM out-fences by creating a sync_file with a fence for each CRTC that sets the OUT_FENCE_PTR property. We use the out_fence pointer received in the OUT_FENCE_PTR prop to send the sync_file fd back to userspace. The sync_file and fd are allocated/created before commit, but the fd_install operation only happens after we know that commit succeed. v2: Comment by Rob Clark: - Squash commit that adds DRM_MODE_ATOMIC_OUT_FENCE flag here. Comment by Daniel Vetter: - Add clean up code for out_fences v3: Comments by Daniel Vetter: - create DRM_MODE_ATOMIC_EVENT_MASK - userspace should fill out_fences_ptr with the crtc_ids for which it wants fences back. v4: Create OUT_FENCE_PTR properties and remove old approach. v5: Comments by Brian Starkey: - Remove extra fence_get() in atomic_ioctl() - Check ret before iterating on the crtc_state - check ret before fd_install - set fence_state to NULL at the beginning - check fence_state->out_fence_ptr before put_user() - change order of fput() and put_unused_fd() on failure - Add access_ok() check to the out_fence_ptr received - Rebase after fence -> dma_fence rename - Store out_fence_ptr in the drm_atomic_state - Split crtc_setup_out_fence() - return -1 as out_fence with TEST_ONLY flag v6: Comments by Daniel Vetter - Add prepare/unprepare_crtc_signaling() - move struct drm_out_fence_state to drm_atomic.c - mark get_crtc_fence() as static Comments by Brian Starkey - proper set fence_ptr fence_state array - isolate fence_idx increment - improve error handling v7: Comments by Daniel Vetter - remove prefix from internal functions - make out_fence_ptr an s64 pointer - degrade DRM_INFO to DRM_DEBUG_ATOMIC when put_user fail - fix doc issues - filter out OUT_FENCE_PTR == NULL and do not fail in this case - add complete_crtc_signalling() - krealloc fence_state on demand Comment by Brian Starkey - remove unused crtc_state arg from get_out_fence() v8: Comment by Brian Starkey - cancel events before check for !fence_state - convert a few lefovers u64 types for out_fence_ptr - fix memleak by assign fence_state earlier after realloc - proper accout num_fences in case of error v9: Comment by Brian Starkey - memset last position of fence_state after krealloc Comments by Sean Paul - pass install_fds in complete_crtc_signaling() instead of ret - put_user(-1, fence_ptr) when decoding props v10: Comment by Brian Starkey - remove unneeded num_fences increment on error path - kfree fence_state after installing fences fd v11: rebase against latest drm-misc v12: rebase again against latest drm-misc Signed-off-by: Gustavo Padovan Reviewed-by: Brian Starkey (v10) Reviewed-by: Sean Paul Tested-by: Robert Foss (v10) [danvet: Appease checkpatch.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1479301221-13056-1-git-send-email-gustavo@padovan.org --- drivers/gpu/drm/drm_atomic.c | 241 ++++++++++++++++++++++++------ drivers/gpu/drm/drm_crtc.c | 2 + drivers/gpu/drm/drm_mode_config.c | 6 + include/drm/drm_atomic.h | 1 + include/drm/drm_mode_config.h | 6 + 5 files changed, 211 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3ad780ad24f9a..b476ec5855472 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -290,6 +290,23 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_atomic_get_crtc_state); +static void set_out_fence_for_crtc(struct drm_atomic_state *state, + struct drm_crtc *crtc, s64 __user *fence_ptr) +{ + state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr; +} + +static s64 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, + struct drm_crtc *crtc) +{ + s64 __user *fence_ptr; + + fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr; + state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL; + + return fence_ptr; +} + /** * drm_atomic_set_mode_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update @@ -494,6 +511,16 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, &replaced); state->color_mgmt_changed |= replaced; return ret; + } else if (property == config->prop_out_fence_ptr) { + s64 __user *fence_ptr = u64_to_user_ptr(val); + + if (!fence_ptr) + return 0; + + if (put_user(-1, fence_ptr)) + return -EFAULT; + + set_out_fence_for_crtc(state->state, crtc, fence_ptr); } else if (crtc->funcs->atomic_set_property) return crtc->funcs->atomic_set_property(crtc, state, property, val); else @@ -536,6 +563,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, *val = (state->ctm) ? state->ctm->base.id : 0; else if (property == config->gamma_lut_property) *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; + else if (property == config->prop_out_fence_ptr) + *val = 0; else if (crtc->funcs->atomic_get_property) return crtc->funcs->atomic_get_property(crtc, state, property, val); else @@ -1664,11 +1693,9 @@ int drm_atomic_debugfs_init(struct drm_minor *minor) */ static struct drm_pending_vblank_event *create_vblank_event( - struct drm_device *dev, struct drm_file *file_priv, - struct dma_fence *fence, uint64_t user_data) + struct drm_device *dev, uint64_t user_data) { struct drm_pending_vblank_event *e = NULL; - int ret; e = kzalloc(sizeof *e, GFP_KERNEL); if (!e) @@ -1678,17 +1705,6 @@ static struct drm_pending_vblank_event *create_vblank_event( e->event.base.length = sizeof(e->event); e->event.user_data = user_data; - if (file_priv) { - ret = drm_event_reserve_init(dev, file_priv, &e->base, - &e->event.base); - if (ret) { - kfree(e); - return NULL; - } - } - - e->base.fence = fence; - return e; } @@ -1793,6 +1809,165 @@ void drm_atomic_clean_old_fb(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_clean_old_fb); +static struct dma_fence *get_crtc_fence(struct drm_crtc *crtc) +{ + struct dma_fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return NULL; + + dma_fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock, + crtc->fence_context, ++crtc->fence_seqno); + + return fence; +} + +struct drm_out_fence_state { + s64 __user *out_fence_ptr; + struct sync_file *sync_file; + int fd; +}; + +static int setup_out_fence(struct drm_out_fence_state *fence_state, + struct dma_fence *fence) +{ + fence_state->fd = get_unused_fd_flags(O_CLOEXEC); + if (fence_state->fd < 0) + return fence_state->fd; + + if (put_user(fence_state->fd, fence_state->out_fence_ptr)) + return -EFAULT; + + fence_state->sync_file = sync_file_create(fence); + if (!fence_state->sync_file) + return -ENOMEM; + + return 0; +} + +static int prepare_crtc_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_mode_atomic *arg, + struct drm_file *file_priv, + struct drm_out_fence_state **fence_state, + unsigned int *num_fences) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, ret; + + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) + return 0; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + u64 __user *fence_ptr; + + fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) { + struct drm_pending_vblank_event *e; + + e = create_vblank_event(dev, arg->user_data); + if (!e) + return -ENOMEM; + + crtc_state->event = e; + } + + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + struct drm_pending_vblank_event *e = crtc_state->event; + + if (!file_priv) + continue; + + ret = drm_event_reserve_init(dev, file_priv, &e->base, + &e->event.base); + if (ret) { + kfree(e); + crtc_state->event = NULL; + return ret; + } + } + + if (fence_ptr) { + struct dma_fence *fence; + struct drm_out_fence_state *f; + + f = krealloc(*fence_state, sizeof(**fence_state) * + (*num_fences + 1), GFP_KERNEL); + if (!f) + return -ENOMEM; + + memset(&f[*num_fences], 0, sizeof(*f)); + + f[*num_fences].out_fence_ptr = fence_ptr; + *fence_state = f; + + fence = get_crtc_fence(crtc); + if (!fence) + return -ENOMEM; + + ret = setup_out_fence(&f[(*num_fences)++], fence); + if (ret) { + dma_fence_put(fence); + return ret; + } + + crtc_state->event->base.fence = fence; + } + } + + return 0; +} + +static void complete_crtc_signaling(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_out_fence_state *fence_state, + unsigned int num_fences, + bool install_fds) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + if (install_fds) { + for (i = 0; i < num_fences; i++) + fd_install(fence_state[i].fd, + fence_state[i].sync_file->file); + + kfree(fence_state); + return; + } + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + /* + * TEST_ONLY and PAGE_FLIP_EVENT are mutually + * exclusive, if they weren't, this code should be + * called on success for TEST_ONLY too. + */ + if (crtc_state->event) + drm_event_cancel_free(dev, &crtc_state->event->base); + } + + if (!fence_state) + return; + + for (i = 0; i < num_fences; i++) { + if (fence_state[i].sync_file) + fput(fence_state[i].sync_file->file); + if (fence_state[i].fd >= 0) + put_unused_fd(fence_state[i].fd); + + /* If this fails log error to the user */ + if (fence_state[i].out_fence_ptr && + put_user(-1, fence_state[i].out_fence_ptr)) + DRM_DEBUG_ATOMIC("Couldn't clear out_fence_ptr\n"); + } + + kfree(fence_state); +} + int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1805,11 +1980,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_atomic_state *state; struct drm_modeset_acquire_ctx ctx; struct drm_plane *plane; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; + struct drm_out_fence_state *fence_state = NULL; unsigned plane_mask; int ret = 0; - unsigned int i, j; + unsigned int i, j, num_fences = 0; /* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) @@ -1924,20 +2098,10 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, drm_mode_object_unreference(obj); } - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - for_each_crtc_in_state(state, crtc, crtc_state, i) { - struct drm_pending_vblank_event *e; - - e = create_vblank_event(dev, file_priv, NULL, - arg->user_data); - if (!e) { - ret = -ENOMEM; - goto out; - } - - crtc_state->event = e; - } - } + ret = prepare_crtc_signaling(dev, state, arg, file_priv, &fence_state, + &num_fences); + if (ret) + goto out; if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { /* @@ -1957,20 +2121,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, out: drm_atomic_clean_old_fb(dev, plane_mask, ret); - if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - /* - * TEST_ONLY and PAGE_FLIP_EVENT are mutually exclusive, - * if they weren't, this code should be called on success - * for TEST_ONLY too. - */ - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->event) - continue; - - drm_event_cancel_free(dev, &crtc_state->event->base); - } - } + complete_crtc_signaling(dev, state, fence_state, num_fences, !ret); if (ret == -EDEADLK) { drm_atomic_state_clear(state); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index dbfae422241e0..90931e0397313 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -267,6 +267,8 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, if (drm_core_check_feature(dev, DRIVER_ATOMIC)) { drm_object_attach_property(&crtc->base, config->prop_active, 0); drm_object_attach_property(&crtc->base, config->prop_mode_id, 0); + drm_object_attach_property(&crtc->base, + config->prop_out_fence_ptr, 0); } return 0; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 8bee2addf7b4e..2735a5847ffad 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -314,6 +314,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return -ENOMEM; dev->mode_config.prop_in_fence_fd = prop; + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "OUT_FENCE_PTR", 0, U64_MAX); + if (!prop) + return -ENOMEM; + dev->mode_config.prop_out_fence_ptr = prop; + prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, "CRTC_ID", DRM_MODE_OBJECT_CRTC); if (!prop) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 331bb100b7185..c0eaec70a2030 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -144,6 +144,7 @@ struct __drm_crtcs_state { struct drm_crtc *ptr; struct drm_crtc_state *state; struct drm_crtc_commit *commit; + s64 __user *out_fence_ptr; }; struct __drm_connnectors_state { diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index c6754ccefe2b6..bf9991b20611a 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -485,6 +485,12 @@ struct drm_mode_config { * for a Plane. */ struct drm_property *prop_in_fence_fd; + /** + * @prop_out_fence_ptr: Sync File fd pointer representing the + * outgoing fences for a CRTC. Userspace should provide a pointer to a + * value of type s64, and then cast that pointer to u64. + */ + struct drm_property *prop_out_fence_ptr; /** * @prop_crtc_id: Default atomic plane property to specify the * &drm_crtc.