From eea54ed46edd42cf703be752d21731567142aa28 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 21 Mar 2017 16:59:55 +0800 Subject: [PATCH 01/63] drm: zte: remove leftover 'inf' from struct zx_hdmi There is a leftover 'inf' field in struct zx_hdmi from commit '831a8d5e0bef ("drm: zte: move struct vou_inf into zx_vou driver")'. Remove it. Signed-off-by: Shawn Guo Reviewed-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1490086795-17925-1-git-send-email-shawnguo@kernel.org --- drivers/gpu/drm/zte/zx_hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c index c47b9cbfe270..0df7366e594b 100644 --- a/drivers/gpu/drm/zte/zx_hdmi.c +++ b/drivers/gpu/drm/zte/zx_hdmi.c @@ -50,7 +50,6 @@ struct zx_hdmi { struct clk *xclk; bool sink_is_hdmi; bool sink_has_audio; - const struct vou_inf *inf; struct platform_device *audio_pdev; }; From 568c5e453666fd8e0a8b11b440291f59e4da28c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Mar 2017 20:12:14 +0200 Subject: [PATCH 02/63] drm: Share the code to compute color plane dimesions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit framebuffer_check() has some hand rolled code to compute the color plane dimensions based on the subsampled information. Let's share the code between framebuffer_check() and drm_framebuffer_plane_{width,height}(). Cc: Ben Widawsky Cc: Jason Ekstrand Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-2-ville.syrjala@linux.intel.com Reviewed-by: Ben Widawsky --- drivers/gpu/drm/drm_framebuffer.c | 32 +++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index e4909aef75d7..1138f90a7d5d 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -126,6 +126,24 @@ int drm_mode_addfb(struct drm_device *dev, return 0; } +static int fb_plane_width(int width, + const struct drm_format_info *format, int plane) +{ + if (plane == 0) + return width; + + return width / format->hsub; +} + +static int fb_plane_height(int height, + const struct drm_format_info *format, int plane) +{ + if (plane == 0) + return height; + + return height / format->vsub; +} + static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) { const struct drm_format_info *info; @@ -151,8 +169,8 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) } for (i = 0; i < info->num_planes; i++) { - unsigned int width = r->width / (i != 0 ? info->hsub : 1); - unsigned int height = r->height / (i != 0 ? info->vsub : 1); + unsigned int width = fb_plane_width(r->width, info, i); + unsigned int height = fb_plane_height(r->height, info, i); unsigned int cpp = info->cpp[i]; if (!r->handles[i]) { @@ -816,10 +834,7 @@ int drm_framebuffer_plane_width(int width, if (plane >= fb->format->num_planes) return 0; - if (plane == 0) - return width; - - return width / fb->format->hsub; + return fb_plane_width(width, fb->format, plane); } EXPORT_SYMBOL(drm_framebuffer_plane_width); @@ -838,9 +853,6 @@ int drm_framebuffer_plane_height(int height, if (plane >= fb->format->num_planes) return 0; - if (plane == 0) - return height; - - return height / fb->format->vsub; + return fb_plane_height(height, fb->format, plane); } EXPORT_SYMBOL(drm_framebuffer_plane_height); From 33f673aa55e96ee37bb85200a24e4da12ba4d3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Mar 2017 20:12:15 +0200 Subject: [PATCH 03/63] drm: Remove fb hsub/vsub alignment requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow framebuffers dimesions to be misaligned w.r.t. the subsampling factors. No real reason the core should have to enforce this, and it definitely starts to cause us issues with the i915 CCS support. So let's just lift the restriction. Let's start to round up when computing the color plane dimesions so that we'll not end up with too low an estimate for the memory requirements and whatnot. Cc: Ben Widawsky Cc: Jason Ekstrand Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-3-ville.syrjala@linux.intel.com Reviewed-by: Ben Widawsky --- drivers/gpu/drm/drm_framebuffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 1138f90a7d5d..69e4c1487420 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -132,7 +132,7 @@ static int fb_plane_width(int width, if (plane == 0) return width; - return width / format->hsub; + return DIV_ROUND_UP(width, format->hsub); } static int fb_plane_height(int height, @@ -141,7 +141,7 @@ static int fb_plane_height(int height, if (plane == 0) return height; - return height / format->vsub; + return DIV_ROUND_UP(height, format->vsub); } static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) @@ -158,12 +158,12 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) return -EINVAL; } - if (r->width == 0 || r->width % info->hsub) { + if (r->width == 0) { DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); return -EINVAL; } - if (r->height == 0 || r->height % info->vsub) { + if (r->height == 0) { DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height); return -EINVAL; } From 6a0f9ebfc5e753bb948c13353615324462d73795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 21 Mar 2017 20:12:16 +0200 Subject: [PATCH 04/63] drm: Add mode_config .get_format_info() hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow drivers to return a custom drm_format_info structure for special fb layouts. We'll use this for the compression control surface in i915. v2: Fix drm_get_format_info() kernel doc (Laurent) Don't pass 'dev' to the new hook (Laurent) v3: s/compresssion/compression/ (Ben) Cc: Laurent Pinchart Cc: Ben Widawsky Cc: Jason Ekstrand Signed-off-by: Ville Syrjälä Reviewed-by: Ben Widawsky Link: http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-4-ville.syrjala@linux.intel.com --- drivers/gpu/drm/drm_fb_cma_helper.c | 2 +- drivers/gpu/drm/drm_fourcc.c | 25 +++++++++++++++++++++++++ drivers/gpu/drm/drm_framebuffer.c | 9 +++++++-- drivers/gpu/drm/drm_modeset_helper.c | 2 +- include/drm/drm_fourcc.h | 6 ++++++ include/drm/drm_mode_config.h | 14 ++++++++++++++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 74cd393a6407..50abd1faf38f 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -177,7 +177,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, int ret; int i; - info = drm_format_info(mode_cmd->pixel_format); + info = drm_get_format_info(dev, mode_cmd); if (!info) return ERR_PTR(-EINVAL); diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 90d2cc8da8eb..f9b6445e846a 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -198,6 +198,31 @@ const struct drm_format_info *drm_format_info(u32 format) } EXPORT_SYMBOL(drm_format_info); +/** + * drm_get_format_info - query information for a given framebuffer configuration + * @dev: DRM device + * @mode_cmd: metadata from the userspace fb creation request + * + * Returns: + * The instance of struct drm_format_info that describes the pixel format, or + * NULL if the format is unsupported. + */ +const struct drm_format_info * +drm_get_format_info(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + const struct drm_format_info *info = NULL; + + if (dev->mode_config.funcs->get_format_info) + info = dev->mode_config.funcs->get_format_info(mode_cmd); + + if (!info) + info = drm_format_info(mode_cmd->pixel_format); + + return info; +} +EXPORT_SYMBOL(drm_get_format_info); + /** * drm_format_num_planes - get the number of planes for format * @format: pixel format (DRM_FORMAT_*) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 69e4c1487420..e8f9c13a0afd 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -144,11 +144,13 @@ static int fb_plane_height(int height, return DIV_ROUND_UP(height, format->vsub); } -static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) +static int framebuffer_check(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *r) { const struct drm_format_info *info; int i; + /* check if the format is supported at all */ info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN); if (!info) { struct drm_format_name_buf format_name; @@ -158,6 +160,9 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) return -EINVAL; } + /* now let the driver pick its own format info */ + info = drm_get_format_info(dev, r); + if (r->width == 0) { DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width); return -EINVAL; @@ -281,7 +286,7 @@ drm_internal_framebuffer_create(struct drm_device *dev, return ERR_PTR(-EINVAL); } - ret = framebuffer_check(r); + ret = framebuffer_check(dev, r); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c index cc44a9a4b004..2b33825f2f93 100644 --- a/drivers/gpu/drm/drm_modeset_helper.c +++ b/drivers/gpu/drm/drm_modeset_helper.c @@ -78,7 +78,7 @@ void drm_helper_mode_fill_fb_struct(struct drm_device *dev, int i; fb->dev = dev; - fb->format = drm_format_info(mode_cmd->pixel_format); + fb->format = drm_get_format_info(dev, mode_cmd); fb->width = mode_cmd->width; fb->height = mode_cmd->height; for (i = 0; i < 4; i++) { diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index fcc08da850c8..6942e84b6edd 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -25,6 +25,9 @@ #include #include +struct drm_device; +struct drm_mode_fb_cmd2; + /** * struct drm_format_info - information about a DRM format * @format: 4CC format identifier (DRM_FORMAT_*) @@ -55,6 +58,9 @@ struct drm_format_name_buf { const struct drm_format_info *__drm_format_info(u32 format); const struct drm_format_info *drm_format_info(u32 format); +const struct drm_format_info * +drm_get_format_info(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd); uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); int drm_format_num_planes(uint32_t format); int drm_format_plane_cpp(uint32_t format, int plane); diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index ea169a90b3c4..579070ff06ef 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -34,6 +34,7 @@ struct drm_file; struct drm_device; struct drm_atomic_state; struct drm_mode_fb_cmd2; +struct drm_format_info; /** * struct drm_mode_config_funcs - basic driver provided mode setting functions @@ -69,6 +70,19 @@ struct drm_mode_config_funcs { struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd); + /** + * @get_format_info: + * + * Allows a driver to return custom format information for special + * fb layouts (eg. ones with auxiliary compression control planes). + * + * RETURNS: + * + * The format information specific to the given fb metadata, or + * NULL if none is found. + */ + const struct drm_format_info *(*get_format_info)(const struct drm_mode_fb_cmd2 *mode_cmd); + /** * @output_poll_changed: * From eadf71cd8c6d837828b4e95e9130f666ab7b4c61 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 Mar 2017 16:52:28 +0100 Subject: [PATCH 05/63] drm/doc: Document feature merge deadlines The discussion pretty much concluded without objections, let's document what we agreed on. Cc'ing linux-doc for the new tag in Documentation/process/index.rst. Acked-by: Dave Airlie Reviewed-by: Sean Paul Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Dave Airlie Cc: Sean Paul Cc: Jani Nikula Cc: Alex Deucher Cc: Lukas Wunner Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170321155228.30287-1-daniel.vetter@ffwll.ch --- Documentation/gpu/introduction.rst | 25 +++++++++++++++++++++++++ Documentation/process/index.rst | 1 + 2 files changed, 26 insertions(+) diff --git a/Documentation/gpu/introduction.rst b/Documentation/gpu/introduction.rst index 1f8bd5ef5f9d..05a82bdfbca4 100644 --- a/Documentation/gpu/introduction.rst +++ b/Documentation/gpu/introduction.rst @@ -60,3 +60,28 @@ checkpatch or sparse. We welcome such contributions. Anyone looking to kick it up a notch can find a list of janitorial tasks on the :ref:`TODO list `. + +Contribution Process +==================== + +Mostly the DRM subsystem works like any other kernel subsystem, see :ref:`the +main process guidelines and documentation ` for how things work. +Here we just document some of the specialities of the GPU subsystem. + +Feature Merge Deadlines +----------------------- + +All feature work must be in the linux-next tree by the -rc6 release of the +current release cycle, otherwise they must be postponed and can't reach the next +merge window. All patches must have landed in the drm-next tree by latest -rc7, +but if your branch is not in linux-next then this must have happened by -rc6 +already. + +After that point only bugfixes (like after the upstream merge window has closed +with the -rc1 release) are allowed. No new platform enabling or new drivers are +allowed. + +This means that there's a blackout-period of about one month where feature work +can't be merged. The recommended way to deal with that is having a -next tree +that's always open, but making sure to not feed it into linux-next during the +blackout period. As an example, drm-misc works like that. diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index 10aa6920709a..82fc399fcd33 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -3,6 +3,7 @@ \renewcommand\thesection* \renewcommand\thesubsection* +.. _process_index: Working with the kernel development community ============================================= From a538d6137dffc5dc8082b9ebe9819c4106fa3f83 Mon Sep 17 00:00:00 2001 From: "Pandiyan, Dhinakaran" Date: Thu, 16 Mar 2017 00:10:24 -0700 Subject: [PATCH 06/63] drm/dp: Kill total_pbn and total_slots in struct drm_dp_mst_topology_mgr The total vcpi time slots is always 63 and does not depend on the link BW, remove total_slots from MST topology manager struct. The next change is to remove total_pbn which is hardcoded to 2560. The total PBN that the topology manager allocates from depends on the link rate and is not a constant. So, fix this by removing the total_pbn member itself. Cc: Daniel Vetter Cc: Archit Taneja Cc: Maarten Lankhorst Cc: Chris Wilson Cc: Harry Wentland Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1489648231-30700-2-git-send-email-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 5 ++--- include/drm/drm_dp_mst_helper.h | 9 +-------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index f2cc375907d0..66a611afa82a 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2042,9 +2042,8 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms goto out_unlock; } - mgr->total_pbn = 2560; - mgr->total_slots = DIV_ROUND_UP(mgr->total_pbn, mgr->pbn_div); - mgr->avail_slots = mgr->total_slots; + /* max. time slots - one slot for MTP header */ + mgr->avail_slots = 63; /* add initial branch device at LCT 1 */ mstb = drm_dp_add_mst_branch_device(1, NULL); diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index f4b4d154b98e..1a7e0f41d6fe 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -479,18 +479,11 @@ struct drm_dp_mst_topology_mgr { * @pbn_div: PBN to slots divisor. */ int pbn_div; - /** - * @total_slots: Total slots that can be allocated. - */ - int total_slots; + /** * @avail_slots: Still available slots that can be allocated. */ int avail_slots; - /** - * @total_pbn: Total PBN count. - */ - int total_pbn; /** * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and From feb2c3bc331576ed4e0bf9608966351b1bb9b622 Mon Sep 17 00:00:00 2001 From: "Pandiyan, Dhinakaran" Date: Thu, 16 Mar 2017 00:10:25 -0700 Subject: [PATCH 07/63] drm/dp: Kill unused MST vcpi slot availability tracking The avail_slots member in the MST topology manager is never updated to reflect the available vcpi slots. The check is effectively against total slots, 63. So, let's make that check obvious and remove avail_slots. While at it, make debug messages more descriptive. Cc: Daniel Vetter Cc: Archit Taneja Cc: Maarten Lankhorst Cc: Chris Wilson Cc: Harry Wentland Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1489648231-30700-3-git-send-email-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 15 ++++++++------- include/drm/drm_dp_mst_helper.h | 5 ----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 66a611afa82a..2e2af13f70d5 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2042,9 +2042,6 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms goto out_unlock; } - /* max. time slots - one slot for MTP header */ - mgr->avail_slots = 63; - /* add initial branch device at LCT 1 */ mstb = drm_dp_add_mst_branch_device(1, NULL); if (mstb == NULL) { @@ -2474,7 +2471,8 @@ int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - if (num_slots > mgr->avail_slots) + /* max. time slots - one slot for MTP header */ + if (num_slots > 63) return -ENOSPC; return num_slots; } @@ -2488,7 +2486,8 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - if (num_slots > mgr->avail_slots) + /* max. time slots - one slot for MTP header */ + if (num_slots > 63) return -ENOSPC; vcpi->pbn = pbn; @@ -2527,10 +2526,12 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn); if (ret) { - DRM_DEBUG_KMS("failed to init vcpi %d %d %d\n", DIV_ROUND_UP(pbn, mgr->pbn_div), mgr->avail_slots, ret); + DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", + DIV_ROUND_UP(pbn, mgr->pbn_div), ret); goto out; } - DRM_DEBUG_KMS("initing vcpi for %d %d\n", pbn, port->vcpi.num_slots); + DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", + pbn, port->vcpi.num_slots); *slots = port->vcpi.num_slots; drm_dp_put_port(port); diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 1a7e0f41d6fe..d8365110eb23 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -480,11 +480,6 @@ struct drm_dp_mst_topology_mgr { */ int pbn_div; - /** - * @avail_slots: Still available slots that can be allocated. - */ - int avail_slots; - /** * @qlock: protects @tx_msg_downq, the &drm_dp_mst_branch.txslost and * &drm_dp_sideband_msg_tx.state once they are queued From 1e797f556c616a42f1e039b1ff1d3c58f61b6104 Mon Sep 17 00:00:00 2001 From: "Pandiyan, Dhinakaran" Date: Thu, 16 Mar 2017 00:10:26 -0700 Subject: [PATCH 08/63] drm/dp: Split drm_dp_mst_allocate_vcpi drm_dp_mst_allocate_vcpi() apart from setting up the vcpi structure, also finds if there are enough slots available. This check is a duplicate of that implemented in drm_dp_mst_find_vcpi_slots(). Let's move this check out and reuse the existing drm_dp_mst_find_vcpi_slots() function to check if there are enough vcpi slots before allocating them. This brings the check to one place. Additionally drivers that will use MST state tracking for atomic modesets can use the atomic version of find_vcpi_slots() and reuse drm_dp_mst_allocate_vcpi() Signed-off-by: Dhinakaran Pandiyan Reviewed-by: Dave Airlie Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1489648231-30700-4-git-send-email-dhinakaran.pandiyan@intel.com --- drivers/gpu/drm/drm_dp_mst_topology.c | 21 ++++++++++----------- drivers/gpu/drm/i915/intel_dp_mst.c | 4 ++-- drivers/gpu/drm/nouveau/nv50_display.c | 3 ++- drivers/gpu/drm/radeon/radeon_dp_mst.c | 4 +++- include/drm/drm_dp_mst_helper.h | 3 ++- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 2e2af13f70d5..d3fc7e4e85b7 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2479,20 +2479,17 @@ int drm_dp_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, EXPORT_SYMBOL(drm_dp_find_vcpi_slots); static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_vcpi *vcpi, int pbn) + struct drm_dp_vcpi *vcpi, int pbn, int slots) { - int num_slots; int ret; - num_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - /* max. time slots - one slot for MTP header */ - if (num_slots > 63) + if (slots > 63) return -ENOSPC; vcpi->pbn = pbn; - vcpi->aligned_pbn = num_slots * mgr->pbn_div; - vcpi->num_slots = num_slots; + vcpi->aligned_pbn = slots * mgr->pbn_div; + vcpi->num_slots = slots; ret = drm_dp_mst_assign_payload_id(mgr, vcpi); if (ret < 0) @@ -2507,7 +2504,8 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, * @pbn: payload bandwidth number to request * @slots: returned number of slots for this PBN. */ -bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots) +bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn, int slots) { int ret; @@ -2515,16 +2513,18 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp if (!port) return false; + if (slots < 0) + return false; + if (port->vcpi.vcpi > 0) { DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); if (pbn == port->vcpi.pbn) { - *slots = port->vcpi.num_slots; drm_dp_put_port(port); return true; } } - ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn); + ret = drm_dp_init_vcpi(mgr, &port->vcpi, pbn, slots); if (ret) { DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n", DIV_ROUND_UP(pbn, mgr->pbn_div), ret); @@ -2532,7 +2532,6 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp } DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n", pbn, port->vcpi.num_slots); - *slots = port->vcpi.num_slots; drm_dp_put_port(port); return true; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 38e3ca2f6f18..f51574f7f160 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -147,7 +147,6 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, to_intel_connector(conn_state->connector); int ret; uint32_t temp; - int slots; /* MST encoders are bound to a crtc, not to a connector, * force the mapping here for get_hw_state. @@ -177,7 +176,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder, ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, connector->port, - pipe_config->pbn, &slots); + pipe_config->pbn, + pipe_config->dp_m_n.tu); if (ret == false) { DRM_ERROR("failed to allocate vcpi\n"); return; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 16915c29ec52..a58c53639c18 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2895,7 +2895,8 @@ nv50_msto_enable(struct drm_encoder *encoder) if (WARN_ON(!mstc)) return; - r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, &slots); + slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); + r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots); WARN_ON(!r); if (mstm->outp->dcb->sorconf.link & 1) diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 7d5ada3980dc..6598306dca9b 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -453,9 +453,11 @@ radeon_mst_encoder_dpms(struct drm_encoder *encoder, int mode) DRM_DEBUG_KMS("dig encoder is %d %d %d\n", dig_enc->dig_encoder, dig_enc->linkb, radeon_crtc->crtc_id); + slots = drm_dp_find_vcpi_slots(&radeon_connector->mst_port->mst_mgr, + mst_enc->pbn); ret = drm_dp_mst_allocate_vcpi(&radeon_connector->mst_port->mst_mgr, radeon_connector->port, - mst_enc->pbn, &slots); + mst_enc->pbn, slots); ret = drm_dp_update_payload_part1(&radeon_connector->mst_port->mst_mgr); radeon_dp_mst_set_be_cntl(primary, mst_enc, diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index d8365110eb23..5b024764666c 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -567,7 +567,8 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_ int drm_dp_calc_pbn_mode(int clock, int bpp); -bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn, int *slots); +bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn, int slots); int drm_dp_mst_get_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); From e448054b5c63b834bba874453d1f2da4e7d39461 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 22 Mar 2017 16:33:38 +0200 Subject: [PATCH 09/63] drm/scdc: declare drm_scdc_get_scrambling_status Fix sparse warning: drivers/gpu/drm/drm_scdc_helper.c:138:6: warning: symbol 'drm_scdc_get_scrambling_status' was not declared. Should it be static? Fixes: 62c58af32c93 ("drm/edid: detect SCDC support in HF-VSDB") Cc: Shashank Sharma Reviewed-by: Shashank Sharma Signed-off-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1490193218-24806-1-git-send-email-jani.nikula@intel.com --- include/drm/drm_scdc_helper.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_scdc_helper.h b/include/drm/drm_scdc_helper.h index ab6bcfbceba9..c25122bb490a 100644 --- a/include/drm/drm_scdc_helper.h +++ b/include/drm/drm_scdc_helper.h @@ -129,6 +129,8 @@ static inline int drm_scdc_writeb(struct i2c_adapter *adapter, u8 offset, return drm_scdc_write(adapter, offset, &value, sizeof(value)); } +bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter); + /** * drm_scdc_set_scrambling - enable scrambling * @adapter: I2C adapter for DDC channel From 91faa0478b5921c638853db54c89a3859c742556 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 09:36:02 +0100 Subject: [PATCH 10/63] drm: drop extern from function decls It's the default storage class for functions, entirely redundant. And a lot of these headers are a bit inconsistent due to organically grown. Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322083617.13361-2-daniel.vetter@ffwll.ch --- include/drm/drm_crtc_helper.h | 38 +++++++++++++++++------------------ include/drm/drm_drv.h | 4 ++-- include/drm/drm_global.h | 8 ++++---- include/drm/drm_hashtab.h | 20 +++++++++--------- include/drm/drm_of.h | 24 +++++++++++----------- include/drm/drm_pci.h | 22 ++++++++++---------- include/drm/drm_plane.h | 20 +++++++++--------- include/drm/drm_prime.h | 30 +++++++++++++-------------- include/drm/drm_sysfs.h | 4 ++-- 9 files changed, 85 insertions(+), 85 deletions(-) diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index d026f5017c33..7506a60df8b1 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -43,18 +43,18 @@ #include #include -extern void drm_helper_disable_unused_functions(struct drm_device *dev); -extern int drm_crtc_helper_set_config(struct drm_mode_set *set); -extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode, - int x, int y, - struct drm_framebuffer *old_fb); -extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); -extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); +void drm_helper_disable_unused_functions(struct drm_device *dev); +int drm_crtc_helper_set_config(struct drm_mode_set *set); +bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, + struct drm_framebuffer *old_fb); +bool drm_helper_crtc_in_use(struct drm_crtc *crtc); +bool drm_helper_encoder_in_use(struct drm_encoder *encoder); -extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode); +int drm_helper_connector_dpms(struct drm_connector *connector, int mode); -extern void drm_helper_resume_force_mode(struct drm_device *dev); +void drm_helper_resume_force_mode(struct drm_device *dev); int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, @@ -63,15 +63,15 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); /* drm_probe_helper.c */ -extern int drm_helper_probe_single_connector_modes(struct drm_connector - *connector, uint32_t maxX, - uint32_t maxY); -extern void drm_kms_helper_poll_init(struct drm_device *dev); -extern void drm_kms_helper_poll_fini(struct drm_device *dev); -extern bool drm_helper_hpd_irq_event(struct drm_device *dev); -extern void drm_kms_helper_hotplug_event(struct drm_device *dev); +int drm_helper_probe_single_connector_modes(struct drm_connector + *connector, uint32_t maxX, + uint32_t maxY); +void drm_kms_helper_poll_init(struct drm_device *dev); +void drm_kms_helper_poll_fini(struct drm_device *dev); +bool drm_helper_hpd_irq_event(struct drm_device *dev); +void drm_kms_helper_hotplug_event(struct drm_device *dev); -extern void drm_kms_helper_poll_disable(struct drm_device *dev); -extern void drm_kms_helper_poll_enable(struct drm_device *dev); +void drm_kms_helper_poll_disable(struct drm_device *dev); +void drm_kms_helper_poll_enable(struct drm_device *dev); #endif diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index 8f900fb30275..53b98321df9b 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -522,11 +522,11 @@ struct drm_driver { int dev_priv_size; }; -extern __printf(6, 7) +__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) +__printf(3, 4) void drm_printk(const char *level, unsigned int category, const char *format, ...); extern unsigned int drm_debug; diff --git a/include/drm/drm_global.h b/include/drm/drm_global.h index a06805eaf649..3a830602a2e4 100644 --- a/include/drm/drm_global.h +++ b/include/drm/drm_global.h @@ -45,9 +45,9 @@ struct drm_global_reference { void (*release) (struct drm_global_reference *); }; -extern void drm_global_init(void); -extern void drm_global_release(void); -extern int drm_global_item_ref(struct drm_global_reference *ref); -extern void drm_global_item_unref(struct drm_global_reference *ref); +void drm_global_init(void); +void drm_global_release(void); +int drm_global_item_ref(struct drm_global_reference *ref); +void drm_global_item_unref(struct drm_global_reference *ref); #endif diff --git a/include/drm/drm_hashtab.h b/include/drm/drm_hashtab.h index fce2ef3fdfff..bb95ff011baf 100644 --- a/include/drm/drm_hashtab.h +++ b/include/drm/drm_hashtab.h @@ -49,17 +49,17 @@ struct drm_open_hash { u8 order; }; -extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order); -extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); -extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add); -extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); +int drm_ht_create(struct drm_open_hash *ht, unsigned int order); +int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); +int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, + unsigned long seed, int bits, int shift, + unsigned long add); +int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); -extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); -extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); -extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); -extern void drm_ht_remove(struct drm_open_hash *ht); +void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); +int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); +int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); +void drm_ht_remove(struct drm_open_hash *ht); /* * RCU-safe interface diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h index 26a64805cc15..d1fc563f068a 100644 --- a/include/drm/drm_of.h +++ b/include/drm/drm_of.h @@ -11,18 +11,18 @@ struct drm_encoder; struct device_node; #ifdef CONFIG_OF -extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, - struct device_node *port); -extern void drm_of_component_match_add(struct device *master, - struct component_match **matchptr, - int (*compare)(struct device *, void *), - struct device_node *node); -extern int drm_of_component_probe(struct device *dev, - int (*compare_of)(struct device *, void *), - const struct component_master_ops *m_ops); -extern int drm_of_encoder_active_endpoint(struct device_node *node, - struct drm_encoder *encoder, - struct of_endpoint *endpoint); +uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, + struct device_node *port); +void drm_of_component_match_add(struct device *master, + struct component_match **matchptr, + int (*compare)(struct device *, void *), + struct device_node *node); +int drm_of_component_probe(struct device *dev, + int (*compare_of)(struct device *, void *), + const struct component_master_ops *m_ops); +int drm_of_encoder_active_endpoint(struct device_node *node, + struct drm_encoder *encoder, + struct of_endpoint *endpoint); #else static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port) diff --git a/include/drm/drm_pci.h b/include/drm/drm_pci.h index f5ebfcaf69e0..4579fac1080c 100644 --- a/include/drm/drm_pci.h +++ b/include/drm/drm_pci.h @@ -39,17 +39,17 @@ struct drm_device; struct drm_driver; struct drm_master; -extern struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, - size_t align); -extern void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); +struct drm_dma_handle *drm_pci_alloc(struct drm_device *dev, size_t size, + size_t align); +void drm_pci_free(struct drm_device *dev, struct drm_dma_handle * dmah); -extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); -extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); +int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); +void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); #ifdef CONFIG_PCI -extern int drm_get_pci_dev(struct pci_dev *pdev, - const struct pci_device_id *ent, - struct drm_driver *driver); -extern int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); +int drm_get_pci_dev(struct pci_dev *pdev, + const struct pci_device_id *ent, + struct drm_driver *driver); +int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); #else static inline int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, @@ -69,7 +69,7 @@ static inline int drm_pci_set_busid(struct drm_device *dev, #define DRM_PCIE_SPEED_50 2 #define DRM_PCIE_SPEED_80 4 -extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); -extern int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); +int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); +int drm_pcie_get_max_link_width(struct drm_device *dev, u32 *mlw); #endif /* _DRM_PCI_H_ */ diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 20867b4371ab..31da9f0c4ad2 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -510,7 +510,7 @@ struct drm_plane { #define obj_to_plane(x) container_of(x, struct drm_plane, base) -extern __printf(8, 9) +__printf(8, 9) int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, uint32_t possible_crtcs, @@ -519,13 +519,13 @@ int drm_universal_plane_init(struct drm_device *dev, unsigned int format_count, enum drm_plane_type type, const char *name, ...); -extern int drm_plane_init(struct drm_device *dev, - struct drm_plane *plane, - uint32_t possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, unsigned int format_count, - bool is_primary); -extern void drm_plane_cleanup(struct drm_plane *plane); +int drm_plane_init(struct drm_device *dev, + struct drm_plane *plane, + uint32_t possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + bool is_primary); +void drm_plane_cleanup(struct drm_plane *plane); /** * drm_plane_index - find the index of a registered plane @@ -538,8 +538,8 @@ static inline unsigned int drm_plane_index(struct drm_plane *plane) { return plane->index; } -extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); -extern void drm_plane_force_disable(struct drm_plane *plane); +struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); +void drm_plane_force_disable(struct drm_plane *plane); int drm_mode_plane_set_obj_prop(struct drm_plane *plane, struct drm_property *property, diff --git a/include/drm/drm_prime.h b/include/drm/drm_prime.h index d09563ecc4b7..0b2a235c4be0 100644 --- a/include/drm/drm_prime.h +++ b/include/drm/drm_prime.h @@ -57,24 +57,24 @@ struct drm_device; struct drm_gem_object; struct drm_file; -extern struct dma_buf *drm_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags); -extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, - struct drm_file *file_priv, uint32_t handle, uint32_t flags, - int *prime_fd); -extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, - struct dma_buf *dma_buf); -extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, - struct drm_file *file_priv, int prime_fd, uint32_t *handle); +struct dma_buf *drm_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, + int flags); +int drm_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, uint32_t flags, + int *prime_fd); +struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); +int drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, uint32_t *handle); struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev, struct dma_buf_export_info *exp_info); -extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf); +void drm_gem_dmabuf_release(struct dma_buf *dma_buf); -extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, - dma_addr_t *addrs, int max_pages); -extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); -extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); +int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages, + dma_addr_t *addrs, int max_pages); +struct sg_table *drm_prime_pages_to_sg(struct page **pages, unsigned int nr_pages); +void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); #endif /* __DRM_PRIME_H__ */ diff --git a/include/drm/drm_sysfs.h b/include/drm/drm_sysfs.h index 1d8e033fde67..23418c1f10d1 100644 --- a/include/drm/drm_sysfs.h +++ b/include/drm/drm_sysfs.h @@ -6,7 +6,7 @@ * don't want to include the full drmP.h file. */ -extern int drm_class_device_register(struct device *dev); -extern void drm_class_device_unregister(struct device *dev); +int drm_class_device_register(struct device *dev); +void drm_class_device_unregister(struct device *dev); #endif From 4834442d70befd57a5a7420944f42899df2cf807 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 21:53:36 +0100 Subject: [PATCH 11/63] drm: Extract drm_debugfs.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doc polish will follow in the next patch. v2: Put the include guard #endif at the end (Ville). Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322205336.24549-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_debugfs.c | 5 ++- include/drm/drmP.h | 44 +------------------- include/drm/drm_debugfs.h | 77 +++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 include/drm/drm_debugfs.h diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 1d2d18d82d2e..4b02f4230562 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -34,9 +34,12 @@ #include #include #include -#include + +#include #include #include +#include + #include "drm_internal.h" #include "drm_crtc_internal.h" diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0e383438f793..60f3255c43a8 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -78,6 +78,7 @@ #include #include #include +#include struct module; @@ -370,27 +371,6 @@ struct drm_ioctl_desc { #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) #define DRM_SCANOUTPOS_ACCURATE (1 << 2) -/** - * Info file list entry. This structure represents a debugfs or proc file to - * be created by the drm core - */ -struct drm_info_list { - const char *name; /** file name */ - int (*show)(struct seq_file*, void*); /** show callback */ - u32 driver_features; /**< Required driver features for this entry */ - void *data; -}; - -/** - * debugfs node structure. This structure represents a debugfs file. - */ -struct drm_info_node { - struct list_head list; - struct drm_minor *minor; - const struct drm_info_list *info_ent; - struct dentry *dent; -}; - /** * DRM device structure. This structure represent a complete card that * may contain multiple heads. @@ -592,28 +572,6 @@ int drm_invalid_op(struct drm_device *dev, void *data, * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. */ - /* Debugfs support */ -#if defined(CONFIG_DEBUG_FS) -extern int drm_debugfs_create_files(const struct drm_info_list *files, - int count, struct dentry *root, - struct drm_minor *minor); -extern int drm_debugfs_remove_files(const struct drm_info_list *files, - int count, struct drm_minor *minor); -#else -static inline int drm_debugfs_create_files(const struct drm_info_list *files, - int count, struct dentry *root, - struct drm_minor *minor) -{ - return 0; -} - -static inline int drm_debugfs_remove_files(const struct drm_info_list *files, - int count, struct drm_minor *minor) -{ - return 0; -} -#endif - /* sysfs support (drm_sysfs.c) */ extern void drm_sysfs_hotplug_event(struct drm_device *dev); diff --git a/include/drm/drm_debugfs.h b/include/drm/drm_debugfs.h new file mode 100644 index 000000000000..56924196d08d --- /dev/null +++ b/include/drm/drm_debugfs.h @@ -0,0 +1,77 @@ +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * + * Author: Rickard E. (Rik) Faith + * Author: Gareth Hughes + * + * 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_DEBUGFS_H_ +#define _DRM_DEBUGFS_H_ + +/** + * Info file list entry. This structure represents a debugfs or proc file to + * be created by the drm core + */ +struct drm_info_list { + const char *name; /** file name */ + int (*show)(struct seq_file*, void*); /** show callback */ + u32 driver_features; /**< Required driver features for this entry */ + void *data; +}; + +/** + * debugfs node structure. This structure represents a debugfs file. + */ +struct drm_info_node { + struct list_head list; + struct drm_minor *minor; + const struct drm_info_list *info_ent; + struct dentry *dent; +}; + +#if defined(CONFIG_DEBUG_FS) +int drm_debugfs_create_files(const struct drm_info_list *files, + int count, struct dentry *root, + struct drm_minor *minor); +int drm_debugfs_remove_files(const struct drm_info_list *files, + int count, struct drm_minor *minor); +#else +static inline int drm_debugfs_create_files(const struct drm_info_list *files, + int count, struct dentry *root, + struct drm_minor *minor) +{ + return 0; +} + +static inline int drm_debugfs_remove_files(const struct drm_info_list *files, + int count, struct drm_minor *minor) +{ + return 0; +} +#endif + +#endif /* _DRM_DEBUGFS_H_ */ From 760f71e72eb5c64b12d85d4e6dc79d28a708e09e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 09:36:04 +0100 Subject: [PATCH 12/63] drm: document driver interface for CRC capturing This was missed in Tomeu's patch. Also remove the kerneldoc for the internal function, we don't document that in general. While at it word-smith the docs slightly for more clarity. Cc: Tomeu Vizoso Reviewed-by: Tomeu Vizoso Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322083617.13361-4-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-uapi.rst | 3 +++ drivers/gpu/drm/drm_debugfs_crc.c | 17 ++++++----------- include/drm/drm_crtc.h | 5 ++++- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 352652810dab..369e8ca12b8e 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -207,6 +207,9 @@ Display CRC Support .. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c :doc: CRC ABI +.. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c + :export: + VBlank event handling ===================== diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c index 96891c4a6e23..1722d8f21449 100644 --- a/drivers/gpu/drm/drm_debugfs_crc.c +++ b/drivers/gpu/drm/drm_debugfs_crc.c @@ -36,7 +36,7 @@ * DOC: CRC ABI * * DRM device drivers can provide to userspace CRC information of each frame as - * it reached a given hardware component (a "source"). + * it reached a given hardware component (a CRC sampling "source"). * * Userspace can control generation of CRCs in a given CRTC by writing to the * file dri/0/crtc-N/crc/control in debugfs, with N being the index of the CRTC. @@ -57,6 +57,11 @@ * rely on being able to generate matching CRC values for the frame contents that * it submits. In this general case, the maximum userspace can do is to compare * the reported CRCs of frames that should have the same contents. + * + * On the driver side the implementation effort is minimal, drivers only need to + * implement &drm_crtc_funcs.set_crc_source. The debugfs files are automatically + * set up if that vfunc is set. CRC samples need to be captured in the driver by + * calling drm_crtc_add_crc_entry(). */ static int crc_control_show(struct seq_file *m, void *data) @@ -280,16 +285,6 @@ static const struct file_operations drm_crtc_crc_data_fops = { .release = crtc_crc_release, }; -/** - * drm_debugfs_crtc_crc_add - Add files to debugfs for capture of frame CRCs - * @crtc: CRTC to whom the frames will belong - * - * Adds files to debugfs directory that allows userspace to control the - * generation of frame CRCs and to read them. - * - * Returns: - * Zero on success, error code on failure. - */ int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc) { struct dentry *crc_ent, *ent; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 6ef59da3fd8e..24dcb121bad4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -590,9 +590,12 @@ struct drm_crtc_funcs { * When CRC generation is enabled, the driver should call * drm_crtc_add_crc_entry() at each frame, providing any information * that characterizes the frame contents in the crcN arguments, as - * provided from the configured source. Drivers must accept a "auto" + * provided from the configured source. Drivers must accept an "auto" * source name that will select a default source for this CRTC. * + * Note that "auto" can depend upon the current modeset configuration, + * e.g. it could pick an encoder or output specific CRC sampling point. + * * This callback is optional if the driver does not support any CRC * generation functionality. * From 0cad7f71b5be7f3c6b63cfccb881e65a3c09404d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 21:54:01 +0100 Subject: [PATCH 13/63] drm/debugfs: Add kerneldoc I've decided to not document drm_debugfs_remove_files, it's on the way out. The biggest part is a huge todo.rst entry with what all should be improved. v2: Nits from Gabriel. Cc: Gabriel Krisman Bertazi Reviewed-by: Gabriel Krisman Bertazi Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322205401.24897-1-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-uapi.rst | 9 ++++++ Documentation/gpu/todo.rst | 26 +++++++++++++++++ drivers/gpu/drm/drm_debugfs.c | 51 +++++----------------------------- drivers/gpu/drm/drm_internal.h | 2 +- include/drm/drm_debugfs.h | 38 ++++++++++++++++++++----- 5 files changed, 74 insertions(+), 52 deletions(-) diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 369e8ca12b8e..76356c86e358 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -210,6 +210,15 @@ Display CRC Support .. kernel-doc:: drivers/gpu/drm/drm_debugfs_crc.c :export: +Debugfs Support +--------------- + +.. kernel-doc:: include/drm/drm_debugfs.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_debugfs.c + :export: + VBlank event handling ===================== diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 64e9d16170ce..0cdaddad2b9b 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -272,6 +272,32 @@ This is a really varied tasks with lots of little bits and pieces: Contact: Daniel Vetter +Clean up the debugfs support +---------------------------- + +There's a bunch of issues with it: + +- The drm_info_list ->show() function doesn't even bother to cast to the drm + structure for you. This is lazy. + +- We probably want to have some support for debugfs files on crtc/connectors and + maybe other kms objects directly in core. There's even drm_print support in + the funcs for these objects to dump kms state, so it's all there. And then the + ->show() functions should obviously give you a pointer to the right object. + +- The drm_info_list stuff is centered on drm_minor instead of drm_device. For + anything we want to print drm_device (or maybe drm_file) is the right thing. + +- The drm_driver->debugfs_init hooks we have is just an artifact of the old + midlayered load sequence. DRM debugfs should work more like sysfs, where you + can create properties/files for an object anytime you want, and the core + takes care of publishing/unpuplishing all the files at register/unregister + time. Drivers shouldn't need to worry about these technicalities, and fixing + this (together with the drm_minor->drm_device move) would allow us to remove + debugfs_init. + +Contact: Daniel Vetter + Better Testing ============== diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 4b02f4230562..c1807d5754b2 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -1,10 +1,3 @@ -/** - * \file drm_debugfs.c - * debugfs support for DRM - * - * \author Ben Gamari - */ - /* * Created: Sun Dec 21 13:08:50 2008 by bgamari@gmail.com * @@ -75,16 +68,15 @@ static const struct file_operations drm_debugfs_fops = { /** - * Initialize a given set of debugfs files for a device - * - * \param files The array of files to create - * \param count The number of files given - * \param root DRI debugfs dir entry. - * \param minor device minor number - * \return Zero on success, non-zero on failure + * drm_debugfs_create_files - Initialize a given set of debugfs files for DRM + * minor + * @files: The array of files to create + * @count: The number of files given + * @root: DRI debugfs dir entry. + * @minor: device minor number * * Create a given set of debugfs files represented by an array of - * &drm_info_list in the given root directory. These files will be removed + * &struct drm_info_list in the given root directory. These files will be removed * automatically on drm_debugfs_cleanup(). */ int drm_debugfs_create_files(const struct drm_info_list *files, int count, @@ -133,17 +125,6 @@ fail: } EXPORT_SYMBOL(drm_debugfs_create_files); -/** - * Initialize the DRI debugfs filesystem for a device - * - * \param dev DRM device - * \param minor device minor number - * \param root DRI debugfs dir entry. - * - * Create the DRI debugfs root entry "/sys/kernel/debug/dri", the device debugfs root entry - * "/sys/kernel/debug/dri/%minor%/", and each entry in debugfs_list as - * "/sys/kernel/debug/dri/%minor%/%name%". - */ int drm_debugfs_init(struct drm_minor *minor, int minor_id, struct dentry *root) { @@ -189,16 +170,6 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, } -/** - * Remove a list of debugfs files - * - * \param files The list of files - * \param count The number of files - * \param minor The minor of which we should remove the files - * \return always zero. - * - * Remove all debugfs entries created by debugfs_init(). - */ int drm_debugfs_remove_files(const struct drm_info_list *files, int count, struct drm_minor *minor) { @@ -235,14 +206,6 @@ static void drm_debugfs_remove_all_files(struct drm_minor *minor) mutex_unlock(&minor->debugfs_lock); } -/** - * Cleanup the debugfs filesystem resources. - * - * \param minor device minor number. - * \return always zero. - * - * Remove all debugfs entries created by debugfs_init(). - */ int drm_debugfs_cleanup(struct drm_minor *minor) { if (!minor->debugfs_root) diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 92ff4b9393b1..3d8e8f878924 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -100,7 +100,7 @@ int drm_gem_open_ioctl(struct drm_device *dev, void *data, void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); -/* drm_debugfs.c */ +/* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) int drm_debugfs_init(struct drm_minor *minor, int minor_id, struct dentry *root); diff --git a/include/drm/drm_debugfs.h b/include/drm/drm_debugfs.h index 56924196d08d..ac0f75df1ac9 100644 --- a/include/drm/drm_debugfs.h +++ b/include/drm/drm_debugfs.h @@ -33,23 +33,47 @@ #define _DRM_DEBUGFS_H_ /** - * Info file list entry. This structure represents a debugfs or proc file to - * be created by the drm core + * struct drm_info_list - debugfs info list entry + * + * This structure represents a debugfs file to be created by the drm + * core. */ struct drm_info_list { - const char *name; /** file name */ - int (*show)(struct seq_file*, void*); /** show callback */ - u32 driver_features; /**< Required driver features for this entry */ + /** @name: file name */ + const char *name; + /** + * @show: + * + * Show callback. &seq_file->private will be set to the &struct + * drm_info_node corresponding to the instance of this info on a given + * &struct drm_minor. + */ + int (*show)(struct seq_file*, void*); + /** @driver_features: Required driver features for this entry */ + u32 driver_features; + /** @data: Driver-private data, should not be device-specific. */ void *data; }; /** - * debugfs node structure. This structure represents a debugfs file. + * struct drm_info_node - Per-minor debugfs node structure + * + * This structure represents a debugfs file, as an instantiation of a &struct + * drm_info_list on a &struct drm_minor. + * + * FIXME: + * + * No it doesn't make a hole lot of sense that we duplicate debugfs entries for + * both the render and the primary nodes, but that's how this has organically + * grown. It should probably be fixed, with a compatibility link, if needed. */ struct drm_info_node { - struct list_head list; + /** @minor: &struct drm_minor for this node. */ struct drm_minor *minor; + /** @info_ent: template for this node. */ const struct drm_info_list *info_ent; + /* private: */ + struct list_head list; struct dentry *dent; }; From 8820b68bd378db1821b23b93dbb5a1a06cbbdfdd Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Wed, 22 Mar 2017 11:21:20 +0800 Subject: [PATCH 14/63] drm/rockchip: Refactor the component match logic. Currently we are adding all components from the dts, if one of their drivers been disabled, we would not be able to bring up others. Refactor component match logic, follow exynos drm. Signed-off-by: Jeffy Chen Reviewed-by: Andrzej Hajda Acked-by: Mark Yao Tested-by: Heiko Stuebner Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1490152880-21855-1-git-send-email-jeffy.chen@rock-chips.com --- drivers/gpu/drm/rockchip/Kconfig | 10 +- drivers/gpu/drm/rockchip/Makefile | 16 +- .../gpu/drm/rockchip/analogix_dp-rockchip.c | 9 +- drivers/gpu/drm/rockchip/cdn-dp-core.c | 8 +- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 8 +- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 10 +- drivers/gpu/drm/rockchip/inno_hdmi.c | 10 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 141 ++++++++++++------ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 6 + drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 8 +- 10 files changed, 118 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 0e4eb845cbb0..50c41c0a50ef 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -13,7 +13,7 @@ config DRM_ROCKCHIP IP found on the SoC. config ROCKCHIP_ANALOGIX_DP - tristate "Rockchip specific extensions for Analogix DP driver" + bool "Rockchip specific extensions for Analogix DP driver" depends on DRM_ROCKCHIP select DRM_ANALOGIX_DP help @@ -22,7 +22,7 @@ config ROCKCHIP_ANALOGIX_DP on RK3288 based SoC, you should selet this option. config ROCKCHIP_CDN_DP - tristate "Rockchip cdn DP" + bool "Rockchip cdn DP" depends on DRM_ROCKCHIP depends on EXTCON select SND_SOC_HDMI_CODEC if SND_SOC @@ -33,7 +33,7 @@ config ROCKCHIP_CDN_DP option. config ROCKCHIP_DW_HDMI - tristate "Rockchip specific extensions for Synopsys DW HDMI" + bool "Rockchip specific extensions for Synopsys DW HDMI" depends on DRM_ROCKCHIP select DRM_DW_HDMI help @@ -43,7 +43,7 @@ config ROCKCHIP_DW_HDMI option. config ROCKCHIP_DW_MIPI_DSI - tristate "Rockchip specific extensions for Synopsys DW MIPI DSI" + bool "Rockchip specific extensions for Synopsys DW MIPI DSI" depends on DRM_ROCKCHIP select DRM_MIPI_DSI help @@ -53,7 +53,7 @@ config ROCKCHIP_DW_MIPI_DSI option. config ROCKCHIP_INNO_HDMI - tristate "Rockchip specific extensions for Innosilicon HDMI" + bool "Rockchip specific extensions for Innosilicon HDMI" depends on DRM_ROCKCHIP help This selects support for Rockchip SoC specific extensions diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index c931e2a7d8de..fa8dc9d9aac2 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -3,14 +3,14 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchip_drm_gem.o rockchip_drm_psr.o rockchip_drm_vop.o + rockchip_drm_gem.o rockchip_drm_psr.o \ + rockchip_drm_vop.o rockchip_vop_reg.o rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o -obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o -obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp.o -cdn-dp-objs := cdn-dp-core.o cdn-dp-reg.o -obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o -obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o -obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o +rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o +rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o +rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o +rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o +rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o -obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_vop_reg.o +obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 8548e8271639..91ebe5c2c7a0 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -507,7 +507,7 @@ static const struct of_device_id rockchip_dp_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids); -static struct platform_driver rockchip_dp_driver = { +struct platform_driver rockchip_dp_driver = { .probe = rockchip_dp_probe, .remove = rockchip_dp_remove, .driver = { @@ -516,10 +516,3 @@ static struct platform_driver rockchip_dp_driver = { .of_match_table = of_match_ptr(rockchip_dp_dt_ids), }, }; - -module_platform_driver(rockchip_dp_driver); - -MODULE_AUTHOR("Yakir Yang "); -MODULE_AUTHOR("Jeff chen "); -MODULE_DESCRIPTION("Rockchip Specific Analogix-DP Driver Extension"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 9edb8dc1ea14..4e55d63c3ef3 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1244,7 +1244,7 @@ static const struct dev_pm_ops cdn_dp_pm_ops = { cdn_dp_resume) }; -static struct platform_driver cdn_dp_driver = { +struct platform_driver cdn_dp_driver = { .probe = cdn_dp_probe, .remove = cdn_dp_remove, .shutdown = cdn_dp_shutdown, @@ -1255,9 +1255,3 @@ static struct platform_driver cdn_dp_driver = { .pm = &cdn_dp_pm_ops, }, }; - -module_platform_driver(cdn_dp_driver); - -MODULE_AUTHOR("Chris Zhong "); -MODULE_DESCRIPTION("cdn DP Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index f84f9ae2fd35..9360250777ba 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -1304,7 +1304,7 @@ static int dw_mipi_dsi_remove(struct platform_device *pdev) return 0; } -static struct platform_driver dw_mipi_dsi_driver = { +struct platform_driver dw_mipi_dsi_driver = { .probe = dw_mipi_dsi_probe, .remove = dw_mipi_dsi_remove, .driver = { @@ -1312,9 +1312,3 @@ static struct platform_driver dw_mipi_dsi_driver = { .name = DRIVER_NAME, }, }; -module_platform_driver(dw_mipi_dsi_driver); - -MODULE_DESCRIPTION("ROCKCHIP MIPI DSI host controller driver"); -MODULE_AUTHOR("Chris Zhong "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d53827413996..63dab6f1b191 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -325,7 +325,7 @@ static int dw_hdmi_rockchip_remove(struct platform_device *pdev) return 0; } -static struct platform_driver dw_hdmi_rockchip_pltfm_driver = { +struct platform_driver dw_hdmi_rockchip_pltfm_driver = { .probe = dw_hdmi_rockchip_probe, .remove = dw_hdmi_rockchip_remove, .driver = { @@ -333,11 +333,3 @@ static struct platform_driver dw_hdmi_rockchip_pltfm_driver = { .of_match_table = dw_hdmi_rockchip_dt_ids, }, }; - -module_platform_driver(dw_hdmi_rockchip_pltfm_driver); - -MODULE_AUTHOR("Andy Yan "); -MODULE_AUTHOR("Yakir Yang "); -MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:dwhdmi-rockchip"); diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 006260de9dbd..7d9b75eb6c44 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -923,7 +923,7 @@ static const struct of_device_id inno_hdmi_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); -static struct platform_driver inno_hdmi_driver = { +struct platform_driver inno_hdmi_driver = { .probe = inno_hdmi_probe, .remove = inno_hdmi_remove, .driver = { @@ -931,11 +931,3 @@ static struct platform_driver inno_hdmi_driver = { .of_match_table = inno_hdmi_dt_ids, }, }; - -module_platform_driver(inno_hdmi_driver); - -MODULE_AUTHOR("Zheng Yang "); -MODULE_AUTHOR("Yakir Yang "); -MODULE_DESCRIPTION("Rockchip Specific INNO-HDMI Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:innohdmi-rockchip"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index ccf456938792..cd7d02e1f758 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -304,34 +304,37 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = { rockchip_drm_sys_resume) }; -static int compare_of(struct device *dev, void *data) -{ - struct device_node *np = data; +#define MAX_ROCKCHIP_SUB_DRIVERS 16 +static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; +static int num_rockchip_sub_drivers; - return dev->of_node == np; +static int compare_dev(struct device *dev, void *data) +{ + return dev == (struct device *)data; } -static void rockchip_add_endpoints(struct device *dev, - struct component_match **match, - struct device_node *port) +static struct component_match *rockchip_drm_match_add(struct device *dev) { - struct device_node *ep, *remote; + struct component_match *match = NULL; + int i; - for_each_child_of_node(port, ep) { - remote = of_graph_get_remote_port_parent(ep); - if (!remote || !of_device_is_available(remote)) { - of_node_put(remote); - continue; - } else if (!of_device_is_available(remote->parent)) { - dev_warn(dev, "parent device of %s is not available\n", - remote->full_name); - of_node_put(remote); - continue; - } + for (i = 0; i < num_rockchip_sub_drivers; i++) { + struct platform_driver *drv = rockchip_sub_drivers[i]; + struct device *p = NULL, *d; - drm_of_component_match_add(dev, match, compare_of, remote); - of_node_put(remote); + do { + d = bus_find_device(&platform_bus_type, p, &drv->driver, + (void *)platform_bus_type.match); + put_device(p); + p = d; + + if (!d) + break; + component_match_add(dev, &match, compare_dev, d); + } while (true); } + + return match ?: ERR_PTR(-ENODEV); } static const struct component_master_ops rockchip_drm_ops = { @@ -339,21 +342,16 @@ static const struct component_master_ops rockchip_drm_ops = { .unbind = rockchip_drm_unbind, }; -static int rockchip_drm_platform_probe(struct platform_device *pdev) +static int rockchip_drm_platform_of_probe(struct device *dev) { - struct device *dev = &pdev->dev; - struct component_match *match = NULL; struct device_node *np = dev->of_node; struct device_node *port; + bool found = false; int i; if (!np) return -ENODEV; - /* - * Bind the crtc ports first, so that - * drm_of_find_possible_crtcs called from encoder .bind callbacks - * works as expected. - */ + for (i = 0;; i++) { struct device_node *iommu; @@ -377,9 +375,9 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) is_support_iommu = false; } + found = true; + of_node_put(iommu); - drm_of_component_match_add(dev, &match, compare_of, - port->parent); of_node_put(port); } @@ -388,27 +386,27 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) return -ENODEV; } - if (!match) { + if (!found) { dev_err(dev, "No available vop found for display-subsystem.\n"); return -ENODEV; } - /* - * For each bound crtc, bind the encoders attached to its - * remote endpoint. - */ - for (i = 0;; i++) { - port = of_parse_phandle(np, "ports", i); - if (!port) - break; - if (!of_device_is_available(port->parent)) { - of_node_put(port); - continue; - } + return 0; +} - rockchip_add_endpoints(dev, &match, port); - of_node_put(port); - } +static int rockchip_drm_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct component_match *match = NULL; + int ret; + + ret = rockchip_drm_platform_of_probe(dev); + if (ret) + return ret; + + match = rockchip_drm_match_add(dev); + if (IS_ERR(match)) + return PTR_ERR(match); return component_master_add_with_match(dev, &rockchip_drm_ops, match); } @@ -436,7 +434,54 @@ static struct platform_driver rockchip_drm_platform_driver = { }, }; -module_platform_driver(rockchip_drm_platform_driver); +#define ADD_ROCKCHIP_SUB_DRIVER(drv, cond) { \ + if (IS_ENABLED(cond) && \ + !WARN_ON(num_rockchip_sub_drivers >= MAX_ROCKCHIP_SUB_DRIVERS)) \ + rockchip_sub_drivers[num_rockchip_sub_drivers++] = &drv; \ +} + +static int __init rockchip_drm_init(void) +{ + int ret; + + num_rockchip_sub_drivers = 0; + ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_DRM_ROCKCHIP); + ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver, + CONFIG_ROCKCHIP_ANALOGIX_DP); + ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); + ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, + CONFIG_ROCKCHIP_DW_HDMI); + ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver, + CONFIG_ROCKCHIP_DW_MIPI_DSI); + ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); + + ret = platform_register_drivers(rockchip_sub_drivers, + num_rockchip_sub_drivers); + if (ret) + return ret; + + ret = platform_driver_register(&rockchip_drm_platform_driver); + if (ret) + goto err_unreg_drivers; + + return 0; + +err_unreg_drivers: + platform_unregister_drivers(rockchip_sub_drivers, + num_rockchip_sub_drivers); + return ret; +} + +static void __exit rockchip_drm_fini(void) +{ + platform_driver_unregister(&rockchip_drm_platform_driver); + + platform_unregister_drivers(rockchip_sub_drivers, + num_rockchip_sub_drivers); +} + +module_init(rockchip_drm_init); +module_exit(rockchip_drm_fini); MODULE_AUTHOR("Mark Yao "); MODULE_DESCRIPTION("ROCKCHIP DRM Driver"); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 8aca219ec4c8..a48fcce3f5f6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -65,4 +65,10 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, int rockchip_drm_wait_line_flag(struct drm_crtc *crtc, unsigned int line_num, unsigned int mstimeout); +extern struct platform_driver cdn_dp_driver; +extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; +extern struct platform_driver dw_mipi_dsi_driver; +extern struct platform_driver inno_hdmi_driver; +extern struct platform_driver rockchip_dp_driver; +extern struct platform_driver vop_platform_driver; #endif /* _ROCKCHIP_DRM_DRV_H_ */ diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 91fbc7b52147..0da44442aab0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -404,7 +404,7 @@ static int vop_remove(struct platform_device *pdev) return 0; } -static struct platform_driver vop_platform_driver = { +struct platform_driver vop_platform_driver = { .probe = vop_probe, .remove = vop_remove, .driver = { @@ -412,9 +412,3 @@ static struct platform_driver vop_platform_driver = { .of_match_table = of_match_ptr(vop_driver_dt_match), }, }; - -module_platform_driver(vop_platform_driver); - -MODULE_AUTHOR("Mark Yao "); -MODULE_DESCRIPTION("ROCKCHIP VOP Driver"); -MODULE_LICENSE("GPL v2"); From 25f0b120727e0f191f6a4f6b4476a2191c22497a Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 22 Mar 2017 09:54:48 +0800 Subject: [PATCH 15/63] drm/rockchip/dsi: check phy_cfg_clk only for RK3399 For RK3399, the phy_cfg_clk is a required clock, if phy_cfg_clk is disabled, MIPI phy can not work. Let's return a error if there is no phy_cfg_clk in dts property, when the pdata match RK3399. Signed-off-by: Chris Zhong Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1490147691-4489-2-git-send-email-zyw@rock-chips.com --- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 9360250777ba..ccfb86a1c501 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -251,6 +251,8 @@ #define THS_PRE_PROGRAM_EN BIT(7) #define THS_ZERO_PROGRAM_EN BIT(6) +#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) + enum { BANDGAP_97_07, BANDGAP_98_05, @@ -279,6 +281,7 @@ struct dw_mipi_dsi_plat_data { u32 grf_switch_reg; u32 grf_dsi0_mode; u32 grf_dsi0_mode_reg; + unsigned int flags; unsigned int max_data_lanes; }; @@ -1136,6 +1139,7 @@ static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { .grf_switch_reg = RK3399_GRF_SOC_CON19, .grf_dsi0_mode = RK3399_GRF_DSI_MODE, .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22, + .flags = DW_MIPI_NEEDS_PHY_CFG_CLK, .max_data_lanes = 4, }; @@ -1227,15 +1231,13 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, clk_disable_unprepare(dsi->pclk); } - dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); - if (IS_ERR(dsi->phy_cfg_clk)) { - ret = PTR_ERR(dsi->phy_cfg_clk); - if (ret != -ENOENT) { + if (pdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) { + dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); + if (IS_ERR(dsi->phy_cfg_clk)) { + ret = PTR_ERR(dsi->phy_cfg_clk); dev_err(dev, "Unable to get phy_cfg_clk: %d\n", ret); return ret; } - dsi->phy_cfg_clk = NULL; - dev_dbg(dev, "have not phy_cfg_clk\n"); } ret = clk_prepare_enable(dsi->pllref_clk); From d3dffdc260d79026f385d6b52d2ec7b6cda559fc Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 22 Mar 2017 09:54:49 +0800 Subject: [PATCH 16/63] dt-bindings: add the grf clock for dw-mipi-dsi For RK3399, the grf clock should be controlled by dw-mipi-dsi driver, add the description for this clock. Acked-by: Rob Herring Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1490147691-4489-3-git-send-email-zyw@rock-chips.com --- .../bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt index 188f6f7403e6..1d722f5055ab 100644 --- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt +++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -10,7 +10,7 @@ Required properties: - interrupts: Represent the controller's interrupt to the CPU(s). - clocks, clock-names: Phandles to the controller's pll reference clock(ref) and APB clock(pclk). For RK3399, a phy config clock - (phy_cfg) is additional required. As described in [1]. + (phy_cfg) and a grf clock(grf) are required. As described in [1]. - rockchip,grf: this soc should set GRF regs to mux vopl/vopb. - ports: contain a port node with endpoint definitions as defined in [2]. For vopb,set the reg = <0> and set the reg = <1> for vopl. From 5bc07b1569022b403be2f92777430345dbbe39e4 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 22 Mar 2017 09:54:50 +0800 Subject: [PATCH 17/63] drm/rockchip/dsi: enable the grf clk before writing grf registers For RK3399, the grf clk should be enabled before writing grf registers, otherwise the register value can not be changed. Signed-off-by: Chris Zhong Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1490147691-4489-4-git-send-email-zyw@rock-chips.com --- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index ccfb86a1c501..6a017be99557 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -252,6 +252,7 @@ #define THS_ZERO_PROGRAM_EN BIT(6) #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) +#define DW_MIPI_NEEDS_GRF_CLK BIT(1) enum { BANDGAP_97_07, @@ -294,6 +295,7 @@ struct dw_mipi_dsi { struct regmap *grf_regmap; void __iomem *base; + struct clk *grf_clk; struct clk *pllref_clk; struct clk *pclk; struct clk *phy_cfg_clk; @@ -982,6 +984,17 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) dw_mipi_dsi_dphy_interface_config(dsi); dw_mipi_dsi_clear_err(dsi); + /* + * For the RK3399, the clk of grf must be enabled before writing grf + * register. And for RK3288 or other soc, this grf_clk must be NULL, + * the clk_prepare_enable return true directly. + */ + ret = clk_prepare_enable(dsi->grf_clk); + if (ret) { + dev_err(dsi->dev, "Failed to enable grf_clk: %d\n", ret); + return; + } + if (pdata->grf_dsi0_mode_reg) regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg, pdata->grf_dsi0_mode); @@ -1006,6 +1019,8 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder) regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val); dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG"); dsi->dpms_mode = DRM_MODE_DPMS_ON; + + clk_disable_unprepare(dsi->grf_clk); } static int @@ -1139,7 +1154,7 @@ static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { .grf_switch_reg = RK3399_GRF_SOC_CON19, .grf_dsi0_mode = RK3399_GRF_DSI_MODE, .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22, - .flags = DW_MIPI_NEEDS_PHY_CFG_CLK, + .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, .max_data_lanes = 4, }; @@ -1240,6 +1255,15 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, } } + if (pdata->flags & DW_MIPI_NEEDS_GRF_CLK) { + dsi->grf_clk = devm_clk_get(dev, "grf"); + if (IS_ERR(dsi->grf_clk)) { + ret = PTR_ERR(dsi->grf_clk); + dev_err(dev, "Unable to get grf_clk: %d\n", ret); + return ret; + } + } + ret = clk_prepare_enable(dsi->pllref_clk); if (ret) { dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); From 395eaaae1ddd4c6ad0c88bdff65184ef3c861647 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 22 Mar 2017 09:54:51 +0800 Subject: [PATCH 18/63] drm/rockchip/dsi: correct the grf_switch_reg name For the RK3399, the grf_switch_reg name should be RK3399_GRF_SOC_CON20, not RK3399_GRF_SOC_CON19. Signed-off-by: Chris Zhong Reviewed-by: Brian Norris Reviewed-by: Sean Paul Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1490147691-4489-5-git-send-email-zyw@rock-chips.com --- drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index 6a017be99557..21b9737662ae 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -34,7 +34,7 @@ #define RK3288_DSI0_SEL_VOP_LIT BIT(6) #define RK3288_DSI1_SEL_VOP_LIT BIT(9) -#define RK3399_GRF_SOC_CON19 0x6250 +#define RK3399_GRF_SOC_CON20 0x6250 #define RK3399_DSI0_SEL_VOP_LIT BIT(0) #define RK3399_DSI1_SEL_VOP_LIT BIT(4) @@ -1151,7 +1151,7 @@ static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = { .dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT, .dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT, - .grf_switch_reg = RK3399_GRF_SOC_CON19, + .grf_switch_reg = RK3399_GRF_SOC_CON20, .grf_dsi0_mode = RK3399_GRF_DSI_MODE, .grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22, .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, From 33e5b6677fd1d39058286224a8700e49c85c0a02 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:47 +0100 Subject: [PATCH 19/63] drm/tilcdc: Drop calls to modeset_lock_crtc Again this is an internal helper, not the official way to lock a crtc. Cc: Jyri Sarha Cc: Tomi Valkeinen Reviewed-by: Tomi Valkeinen Acked-by: Jyri Sarha Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-9-daniel.vetter@ffwll.ch --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index c92faa8f7560..afd2a7b2aff7 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -579,7 +579,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work) dev_info(crtc->dev->dev, "%s: Reset CRTC", __func__); - drm_modeset_lock_crtc(crtc, NULL); + drm_modeset_lock(&crtc->mutex, NULL); if (!tilcdc_crtc_is_on(crtc)) goto out; @@ -587,7 +587,7 @@ static void tilcdc_crtc_recover_work(struct work_struct *work) tilcdc_crtc_disable(crtc); tilcdc_crtc_enable(crtc); out: - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); } static void tilcdc_crtc_destroy(struct drm_crtc *crtc) @@ -595,9 +595,9 @@ static void tilcdc_crtc_destroy(struct drm_crtc *crtc) struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct tilcdc_drm_private *priv = crtc->dev->dev_private; - drm_modeset_lock_crtc(crtc, NULL); + drm_modeset_lock(&crtc->mutex, NULL); tilcdc_crtc_disable(crtc); - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); flush_workqueue(priv->wq); @@ -856,7 +856,7 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); - drm_modeset_lock_crtc(crtc, NULL); + drm_modeset_lock(&crtc->mutex, NULL); if (tilcdc_crtc->lcd_fck_rate != clk_get_rate(priv->clk)) { if (tilcdc_crtc_is_on(crtc)) { pm_runtime_get_sync(dev->dev); @@ -868,7 +868,7 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) pm_runtime_put_sync(dev->dev); } } - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); } #define SYNC_LOST_COUNT_LIMIT 50 From 7cfdf711ffb02b45a4c84fdc4e7272320ec9fd2e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 21:54:47 +0100 Subject: [PATCH 20/63] drm: Extract drm_ioctl.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To match the drm_ioctl.c we already have. v2: Remove spurious space (Ville). Cc: Ville Syrjälä Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioctl.c | 1 + include/drm/drmP.h | 61 +-------------------- include/drm/drm_ioctl.h | 102 ++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 60 deletions(-) create mode 100644 include/drm/drm_ioctl.h diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index a7c61c23685a..7d6deaa91281 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -28,6 +28,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include "drm_legacy.h" diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 60f3255c43a8..ec8d882b364c 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -79,6 +79,7 @@ #include #include #include +#include struct module; @@ -317,49 +318,6 @@ struct pci_controller; #define DRM_IF_VERSION(maj, min) (maj << 16 | min) -/** - * Ioctl function type. - * - * \param inode device inode. - * \param file_priv DRM file private pointer. - * \param cmd command. - * \param arg argument. - */ -typedef int drm_ioctl_t(struct drm_device *dev, void *data, - struct drm_file *file_priv); - -typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, - unsigned long arg); - -#define DRM_IOCTL_NR(n) _IOC_NR(n) -#define DRM_MAJOR 226 - -#define DRM_AUTH 0x1 -#define DRM_MASTER 0x2 -#define DRM_ROOT_ONLY 0x4 -#define DRM_CONTROL_ALLOW 0x8 -#define DRM_UNLOCKED 0x10 -#define DRM_RENDER_ALLOW 0x20 - -struct drm_ioctl_desc { - unsigned int cmd; - int flags; - drm_ioctl_t *func; - const char *name; -}; - -/** - * Creates a driver or general drm_ioctl_desc array entry for the given - * ioctl, for use by drm_ioctl(). - */ - -#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ - [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ - .cmd = DRM_IOCTL_##ioctl, \ - .func = _func, \ - .flags = _flags, \ - .name = #ioctl \ - } /* Flags and return codes for get_vblank_timestamp() driver function. */ #define DRM_CALLED_FROM_VBLIRQ 1 @@ -549,23 +507,6 @@ static inline int drm_device_is_unplugged(struct drm_device *dev) /*@{*/ /* Driver support (drm_drv.h) */ -extern int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); -extern long drm_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -extern long drm_compat_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg); -#else -/* Let drm_compat_ioctl be assigned to .compat_ioctl unconditionally */ -#define drm_compat_ioctl NULL -#endif -extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); - -/* Misc. IOCTL support (drm_ioctl.c) */ -int drm_noop(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_invalid_op(struct drm_device *dev, void *data, - struct drm_file *file_priv); /* * These are exported to drivers so that they can implement fencing using diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h new file mode 100644 index 000000000000..f17ee077f649 --- /dev/null +++ b/include/drm/drm_ioctl.h @@ -0,0 +1,102 @@ +/* + * Internal Header for the Direct Rendering Manager + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright (c) 2009-2010, Code Aurora Forum. + * All rights reserved. + * + * Author: Rickard E. (Rik) Faith + * Author: Gareth Hughes + * + * 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_IOCTL_H_ +#define _DRM_IOCTL_H_ + +#include + +#include + +struct drm_device; +struct drm_file; +struct file; + +/** + * Ioctl function type. + * + * \param inode device inode. + * \param file_priv DRM file private pointer. + * \param cmd command. + * \param arg argument. + */ +typedef int drm_ioctl_t(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, + unsigned long arg); + +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_MAJOR 226 + +#define DRM_AUTH 0x1 +#define DRM_MASTER 0x2 +#define DRM_ROOT_ONLY 0x4 +#define DRM_CONTROL_ALLOW 0x8 +#define DRM_UNLOCKED 0x10 +#define DRM_RENDER_ALLOW 0x20 + +struct drm_ioctl_desc { + unsigned int cmd; + int flags; + drm_ioctl_t *func; + const char *name; +}; + +/** + * Creates a driver or general drm_ioctl_desc array entry for the given + * ioctl, for use by drm_ioctl(). + */ + +#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(DRM_IOCTL_##ioctl) - DRM_COMMAND_BASE] = { \ + .cmd = DRM_IOCTL_##ioctl, \ + .func = _func, \ + .flags = _flags, \ + .name = #ioctl \ + } + +int drm_ioctl_permit(u32 flags, struct drm_file *file_priv); +long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#else +/* Let drm_compat_ioctl be assigned to .compat_ioctl unconditionally */ +#define drm_compat_ioctl NULL +#endif +bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); + +int drm_noop(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_invalid_op(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +#endif /* _DRM_IOCTL_H_ */ From f217f554b2a283c33da26d79fa4611d53fd0b977 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 09:36:10 +0100 Subject: [PATCH 21/63] drm/todo: Add tinydrm refactoring ideas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discussed with Noralf on the list a bit. An open question is tinydrm vs. drm_panel, but until we have a clear idea what's really needed in that space, I think it's best to just move forward with what we have. Cc: Noralf Trønnes Acked-by: Noralf Trønnes Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322083617.13361-10-daniel.vetter@ffwll.ch --- Documentation/gpu/todo.rst | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 0cdaddad2b9b..e255b36b34a3 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -99,6 +99,30 @@ events for atomic commits correctly. But fixing these bugs is good anyway. Contact: Daniel Vetter, respective driver maintainers +Better manual-upload support for atomic +--------------------------------------- + +This would be especially useful for tinydrm: + +- Add a struct drm_rect dirty_clip to drm_crtc_state. When duplicating the + crtc state, clear that to the max values, x/y = 0 and w/h = MAX_INT, in + __drm_atomic_helper_crtc_duplicate_state(). + +- Move tinydrm_merge_clips into drm_framebuffer.c, dropping the tinydrm_ + prefix ofc and using drm_fb_. drm_framebuffer.c makes sense since this + is a function useful to implement the fb->dirty function. + +- Create a new drm_fb_dirty function which does essentially what e.g. + mipi_dbi_fb_dirty does. You can use e.g. drm_atomic_helper_update_plane as the + template. But instead of doing a simple full-screen plane update, this new + helper also sets crtc_state->dirty_clip to the right coordinates. And of + course it needs to check whether the fb is actually active (and maybe where), + so there's some book-keeping involved. There's also some good fun involved in + scaling things appropriately. For that case we might simply give up and + declare the entire area covered by the plane as dirty. + +Contact: Noralf Trønnes, Daniel Vetter + Fallout from atomic KMS ----------------------- @@ -336,6 +360,52 @@ Contact: Daniel Vetter Driver Specific =============== +tinydrm +------- + +Tinydrm is the helper driver for really simple fb drivers. The goal is to make +those drivers as simple as possible, so lots of room for refactoring: + +- backlight helpers, probably best to put them into a new drm_backlight.c. + This is because drivers/video is de-facto unmaintained. We could also + move drivers/video/backlight to drivers/gpu/backlight and take it all + over within drm-misc, but that's more work. + +- spi helpers, probably best put into spi core/helper code. Thierry said + the spi maintainer is fast&reactive, so shouldn't be a big issue. + +- extract the mipi-dbi helper (well, the non-tinydrm specific parts at + least) into a separate helper, like we have for mipi-dsi already. Or follow + one of the ideas for having a shared dsi/dbi helper, abstracting away the + transport details more. + +- tinydrm_lastclose could be drm_fb_helper_lastclose. Only thing we need + for that is to store the drm_fb_helper pointer somewhere in + drm_device->mode_config. And then we could roll that out to all the + drivers. + +- tinydrm_gem_cma_prime_import_sg_table should probably go into the cma + helpers, as a _vmapped variant (since not every driver needs the vmap). + And tinydrm_gem_cma_free_object could the be merged into + drm_gem_cma_free_object(). + +- tinydrm_fb_create we could move into drm_simple_pipe, only need to add + the fb_create hook to drm_simple_pipe_funcs, which would again simplify a + bunch of things (since it gives you a one-stop vfunc for simple drivers). + +- Quick aside: The unregister devm stuff is kinda getting the lifetimes of + a drm_device wrong. Doesn't matter, since everyone else gets it wrong + too :-) + +- With the fbdev pointer in dev->mode_config we could also make + suspend/resume helpers entirely generic, at least if we add a + dev->mode_config.suspend_state. We could even provide a generic pm_ops + structure with those. + +- also rework the drm_framebuffer_funcs->dirty hook wire-up, see above. + +Contact: Noralf Trønnes, Daniel Vetter + Outside DRM =========== From f19aee7f27929be0352b13ca9f2699fe46affbfe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 09:36:11 +0100 Subject: [PATCH 22/63] drm/vblank: Remove DRM_VBLANKTIME_IN_VBLANK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The core code doesn't care at all about this, it's entirely dead. Cc: Mario Kleiner Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322083617.13361-11-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_irq.c | 8 -------- include/drm/drmP.h | 1 - 2 files changed, 9 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 53a526c7b24d..4b0c7475ed13 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -810,14 +810,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, /* Return upper bound of timestamp precision error. */ *max_error = duration_ns; - /* Check if in vblank area: - * vpos is >=0 in video scanout area, but negative - * within vblank area, counting down the number of lines until - * start of scanout. - */ - if (vbl_status & DRM_SCANOUTPOS_IN_VBLANK) - ret |= DRM_VBLANKTIME_IN_VBLANK; - /* Convert scanout position into elapsed time at raw_time query * since start of scanout at first display scanline. delta_ns * can be negative if start of scanout hasn't happened yet. diff --git a/include/drm/drmP.h b/include/drm/drmP.h index ec8d882b364c..3bfafcdb8710 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -322,7 +322,6 @@ struct pci_controller; /* Flags and return codes for get_vblank_timestamp() driver function. */ #define DRM_CALLED_FROM_VBLIRQ 1 #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) -#define DRM_VBLANKTIME_IN_VBLANK (1 << 1) /* get_scanout_position() return flags */ #define DRM_SCANOUTPOS_VALID (1 << 0) From 187697a4544c20d4b77193275a7e10f85506d14d Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Mon, 27 Mar 2017 11:45:07 +0530 Subject: [PATCH 23/63] drm: dw_hdmi: Don't rely on the status of the bridge for updating HPD Currently, the irq handler that monitors changes for HPD and RX_SENSE relies on the status of the bridge for updating the status of the HPD. The update is done only when the bridge is enabled. However, on Rockchip platforms we have found use cases where it could be a problem. When HDMI is being used, turning off/on the screen or unplugging/re-plugging the cable, the following simplified code path will happen: - dw_hdmi_irq() will be triggered by an HPD event, as the bridge is on hdmi->disabled is false, then the handler will update the rxsense flag accordingly. - dw_hdmi_update_power() will be invoked with the mode DRM_FORCE_UNSPECIFIED and rxsense == 1, so dw_hdmi_poweroff() will be called and the PHY will be desactivated (its pixel clocks and TMDS) [...] - dw_hdmi_bridge_disable() will be invoked, the bridge will be marked as disabled. - dw_hdmi_irq() will be triggered by an HPD event, as the bridge is currently disabled the HPD status won't be updated, so hdmi->rxsense won't be changed. Even if the data part of the PHY is disabled, this information coming from the HDMI Transmitter is correct and should be saved. [...] - dw_hdmi_bridge_enable() will be invoked, the bridge will be marked as enabled. - dw_hdmi_update_power() will be called. When hdmi->force is equal to DRM_FORCE_UNSPECIFIED the function will rely on hdmi->rxsense. If this field has not been updated by the irq handler, it will be false and DRM_FORCE_ON won't be put to hdmi->force. Consequently, most of the time dw_hdmi_poweron() won't be called in this use case, TMDS won't be re-enabled the PHY won't be re-initialized, resulting in a "Signal not found". This commit fixes the issue by removing the check for "!hdmi->disabled". As already explained, even if the PHY is partially disabled, information coming from HDMI Transmitter about HPD should be saved for a later use. Signed-off-by: Romain Perier Signed-off-by: Archit Taneja Link: https://patchwork.freedesktop.org/patch/143602/ --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index af93f7a20697..32f02e92e0b9 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -1916,7 +1916,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) if (intr_stat & (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) { mutex_lock(&hdmi->mutex); - if (!hdmi->disabled && !hdmi->force) { + if (!hdmi->force) { /* * If the RX sense status indicates we're disconnected, * clear the software rxsense status. From 79b85d2b7e5e61659deca3ec064e8c0245250a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= Date: Sun, 26 Mar 2017 16:25:29 +0200 Subject: [PATCH 24/63] drm/tinydrm: Fix drm_driver.fops.owner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_driver.fops can't be shared since the owner then becomes tinydrm.ko. Move the fops declaration to the driver. v2: Use DEFINE_DRM_GEM_CMA_FOPS Reported-by: Daniel Vetter Signed-off-by: Noralf Trønnes Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170326142529.16938-1-noralf@tronnes.org --- drivers/gpu/drm/tinydrm/core/tinydrm-core.c | 15 --------------- drivers/gpu/drm/tinydrm/mi0283qt.c | 3 +++ include/drm/tinydrm/tinydrm.h | 4 +--- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index 6a257dd08ee0..fd25c7e534ee 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c @@ -122,21 +122,6 @@ void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj) } EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object); -const struct file_operations tinydrm_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = drm_compat_ioctl, -#endif - .poll = drm_poll, - .read = drm_read, - .llseek = no_llseek, - .mmap = drm_gem_cma_mmap, -}; -EXPORT_SYMBOL(tinydrm_fops); - static struct drm_framebuffer * tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) diff --git a/drivers/gpu/drm/tinydrm/mi0283qt.c b/drivers/gpu/drm/tinydrm/mi0283qt.c index b29fe86158f7..482ff1c3db61 100644 --- a/drivers/gpu/drm/tinydrm/mi0283qt.c +++ b/drivers/gpu/drm/tinydrm/mi0283qt.c @@ -132,9 +132,12 @@ static const struct drm_display_mode mi0283qt_mode = { TINYDRM_MODE(320, 240, 58, 43), }; +DEFINE_DRM_GEM_CMA_FOPS(mi0283qt_fops); + static struct drm_driver mi0283qt_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, + .fops = &mi0283qt_fops, TINYDRM_GEM_DRIVER_OPS, .lastclose = tinydrm_lastclose, .debugfs_init = mipi_dbi_debugfs_init, diff --git a/include/drm/tinydrm/tinydrm.h b/include/drm/tinydrm/tinydrm.h index cf9ca207b8b1..00b800df4d1b 100644 --- a/include/drm/tinydrm/tinydrm.h +++ b/include/drm/tinydrm/tinydrm.h @@ -58,8 +58,7 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe) .gem_prime_mmap = drm_gem_cma_prime_mmap, \ .dumb_create = drm_gem_cma_dumb_create, \ .dumb_map_offset = drm_gem_cma_dumb_map_offset, \ - .dumb_destroy = drm_gem_dumb_destroy, \ - .fops = &tinydrm_fops + .dumb_destroy = drm_gem_dumb_destroy /** * TINYDRM_MODE - tinydrm display mode @@ -84,7 +83,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe) .type = DRM_MODE_TYPE_DRIVER, \ .clock = 1 /* pass validation */ -extern const struct file_operations tinydrm_fops; void tinydrm_lastclose(struct drm_device *drm); void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj); struct drm_gem_object * From 18dddadc78c91a91b546acc48506c24f5f840c4f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 21 Mar 2017 17:41:49 +0100 Subject: [PATCH 25/63] drm/atomic: Introduce drm_atomic_helper_shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The trouble here is that it does multiple atomic commits under one drm_modeset_lock_all, which breaks the behind-the-scenes acquire context magic that function pulls off. It's much better to have one overall atomic commit. That we still have multiple atomic commits prevents us from adding some pretty useful debug checks to the atomic machinery. Hence it is really a bad idea to call the legacy drm_crtc_force_disable_all() function. There's 2 atomic drivers using this still, nouveau and tinydrm. To fix this, introduce a new drm_atomic_helper_shutdown() by extracting the code from i915. While at it improve kernel-doc and catch future offenders by sprinkling a WARN_ON into the legacy function. We should probably move those into the legacy modeset helpers, too ... v2: Make it compile on arm drivers too (Noralf). v3: Correct kerneldoc to point at _disable_all(). Reviewed-by: Maarten Lankhorst Acked-by: Noralf Trønnes Cc: Maarten Lankhorst Cc: Noralf Trønnes Cc: Ben Skeggs Tested-by: Tomi Valkeinen Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170321164149.31531-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 42 ++++++++++++++++++++- drivers/gpu/drm/drm_crtc.c | 7 ++++ drivers/gpu/drm/i915/i915_drv.c | 20 +--------- drivers/gpu/drm/nouveau/nouveau_display.c | 8 +++- drivers/gpu/drm/tinydrm/core/tinydrm-core.c | 4 +- include/drm/drm_atomic_helper.h | 1 + 6 files changed, 57 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 4e26b73bb0d5..c3ace44e1c8e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2443,7 +2443,8 @@ commit: * that they are connected to. * * This is used for example in suspend/resume to disable all currently active - * functions when suspending. + * functions when suspending. If you just want to shut down everything at e.g. + * driver unload, look at drm_atomic_helper_shutdown(). * * Note that if callers haven't already acquired all modeset locks this might * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). @@ -2452,7 +2453,8 @@ commit: * 0 on success or a negative error code on failure. * * See also: - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() and + * drm_atomic_helper_shutdown(). */ int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx) @@ -2516,6 +2518,42 @@ free: EXPORT_SYMBOL(drm_atomic_helper_disable_all); +/** + * drm_atomic_helper_shutdown - shutdown all CRTC + * @dev: DRM device + * + * This shuts down all CRTC, which is useful for driver unloading. Shutdown on + * suspend should instead be handled with drm_atomic_helper_suspend(), since + * that also takes a snapshot of the modeset state to be restored on resume. + * + * This is just a convenience wrapper around drm_atomic_helper_disable_all(), + * and it is the atomic version of drm_crtc_force_disable_all(). + */ +void drm_atomic_helper_shutdown(struct drm_device *dev) +{ + struct drm_modeset_acquire_ctx ctx; + int ret; + + drm_modeset_acquire_init(&ctx, 0); + while (1) { + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (!ret) + ret = drm_atomic_helper_disable_all(dev, &ctx); + + if (ret != -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + if (ret) + DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} +EXPORT_SYMBOL(drm_atomic_helper_shutdown); + /** * drm_atomic_helper_suspend - subsystem-level suspend helper * @dev: DRM device diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e2974d3c92e7..660b4c8715de 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -94,6 +94,8 @@ EXPORT_SYMBOL(drm_crtc_from_index); * drm_crtc_force_disable - Forcibly turn off a CRTC * @crtc: CRTC to turn off * + * Note: This should only be used by non-atomic legacy drivers. + * * Returns: * Zero on success, error code on failure. */ @@ -103,6 +105,8 @@ int drm_crtc_force_disable(struct drm_crtc *crtc) .crtc = crtc, }; + WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev)); + return drm_mode_set_config_internal(&set); } EXPORT_SYMBOL(drm_crtc_force_disable); @@ -114,6 +118,9 @@ EXPORT_SYMBOL(drm_crtc_force_disable); * Drivers may want to call this on unload to ensure that all displays are * unlit and the GPU is in a consistent, low power state. Takes modeset locks. * + * Note: This should only be used by non-atomic legacy drivers. For an atomic + * version look at drm_atomic_helper_shutdown(). + * * Returns: * Zero on success, error code on failure. */ diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 03d9e45694c9..98b17070a123 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1307,8 +1307,6 @@ void i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = dev_priv->drm.pdev; - struct drm_modeset_acquire_ctx ctx; - int ret; intel_fbdev_fini(dev); @@ -1317,23 +1315,7 @@ void i915_driver_unload(struct drm_device *dev) intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); - drm_modeset_acquire_init(&ctx, 0); - while (1) { - ret = drm_modeset_lock_all_ctx(dev, &ctx); - if (!ret) - ret = drm_atomic_helper_disable_all(dev, &ctx); - - if (ret != -EDEADLK) - break; - - drm_modeset_backoff(&ctx); - } - - if (ret) - DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret); - - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); + drm_atomic_helper_shutdown(dev); intel_gvt_cleanup(dev_priv); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 33269c7df30f..c014bae7c5e7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -436,8 +436,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) struct drm_connector *connector; struct drm_crtc *crtc; - if (!suspend) - drm_crtc_force_disable_all(dev); + if (!suspend) { + if (drm_drv_uses_atomic_modeset(dev)) + drm_atomic_helper_shutdown(dev); + else + drm_crtc_force_disable_all(dev); + } /* Make sure that drm and hw vblank irqs get properly disabled. */ drm_for_each_crtc(crtc, dev) diff --git a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c index fd25c7e534ee..551709e6b114 100644 --- a/drivers/gpu/drm/tinydrm/core/tinydrm-core.c +++ b/drivers/gpu/drm/tinydrm/core/tinydrm-core.c @@ -236,7 +236,7 @@ static void tinydrm_unregister(struct tinydrm_device *tdev) { struct drm_fbdev_cma *fbdev_cma = tdev->fbdev_cma; - drm_crtc_force_disable_all(tdev->drm); + drm_atomic_helper_shutdown(tdev->drm); /* don't restore fbdev in lastclose, keep pipeline disabled */ tdev->fbdev_cma = NULL; drm_dev_unregister(tdev->drm); @@ -287,7 +287,7 @@ EXPORT_SYMBOL(devm_tinydrm_register); */ void tinydrm_shutdown(struct tinydrm_device *tdev) { - drm_crtc_force_disable_all(tdev->drm); + drm_atomic_helper_shutdown(tdev->drm); } EXPORT_SYMBOL(tinydrm_shutdown); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index dc16274987c7..969f7237f1fc 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -104,6 +104,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); +void drm_atomic_helper_shutdown(struct drm_device *dev); struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, struct drm_modeset_acquire_ctx *ctx); From c0411316ab93e35a671aafcab82d1eefed449a4f Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Fri, 24 Mar 2017 01:54:44 -0300 Subject: [PATCH 26/63] drm: bochs: Prevent double-free of fb helper If fbdev registration fails for whatever reason, the error path of bochs_fbdev_init() will call bochs_fbdev_fini(), but since an fbdev initialization error is not fatal to the probe function, a subsequent device removal will try to call bochs_fbdev_fini() again, hitting the Oops below. This was detected by 0-day with a failing framebuffer registration and CONFIG_DEBUG_TEST_DRIVER_REMOVE=y. This reproduces the scenario I mentioned above at insmod time, because the test attempts to remove the device right after probing. root@debian:~# insmod bochs-drm.ko [ 17.609635] [drm] Found bochs VGA, ID 0xb0c0. [ 17.612974] [drm] Framebuffer size 16384 kB @ 0xfa000000, mmio @ 0xfebf2000. [ 17.613938] [TTM] Zone kernel: Available graphics memory: 1022244 kiB [ 17.614701] [TTM] Initializing pool allocator [ 17.615427] [TTM] Initializing DMA pool allocator [ 17.619143] fbcon: bochsdrmfb (fb0) is primary device [ 17.619428] Console: switching to colour frame buffer device 128x48 [ 17.621047] bochs-drm 0000:00:02.0: fb0: bochsdrmfb frame buffer device [ 17.641111] [drm] Initialized bochs-drm 1.0.0 20130925 for 0000:00:02.0 on minor 0 [ 17.642380] general protection fault: 0000 [#1] SMP [ 17.642985] Modules linked in: bochs_drm(+) [ 17.643259] CPU: 4 PID: 3279 Comm: insmod Tainted: G W 4.11.0-rc1+ #119 [ 17.643259] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.9.3-20161025_171302-gandalf 04/01/2014 [ 17.643259] task: ffff88007af35e00 task.stack: ffffc90000d84000 [ 17.643259] RIP: 0010:drm_fb_helper_fini+0x8e/0x110 [ 17.643259] RSP: 0018:ffffc90000d87ad0 EFLAGS: 00010202 [ 17.643259] RAX: dead000000000200 RBX: ffff8800790d5770 RCX: 0000000000000000 [ 17.652101] RDX: dead000000000100 RSI: 000000007fffffff RDI: ffffffff81eaf820 [ 17.652101] RBP: ffffc90000d87ae0 R08: 0000000000000000 R09: ffff88007271d918 [ 17.652101] R10: ffffc90000d87a88 R11: 0000000000000000 R12: 0000000000000000 [ 17.652101] R13: ffff8800790d56d0 R14: 0000000000000000 R15: 0000000000000000 [ 17.652101] FS: 00007f9285995700(0000) GS:ffff88007cf00000(0000) knlGS:0000000000000000 [ 17.652101] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 17.652101] CR2: 0000564f1cf9f1e8 CR3: 0000000079686000 CR4: 00000000000006e0 [ 17.652101] Call Trace: [ 17.652101] bochs_fbdev_fini+0x24/0x90 [bochs_drm] [ 17.652101] bochs_unload+0x16/0x50 [bochs_drm] [ 17.652101] drm_dev_unregister+0x37/0xd0 [ 17.652101] drm_put_dev+0x31/0x60 [ 17.652101] bochs_pci_remove+0x10/0x20 [bochs_drm] [ 17.652101] pci_device_remove+0x34/0xb0 [ 17.652101] driver_probe_device+0xd0/0x370 [ 17.652101] __driver_attach+0x96/0xa0 [ 17.652101] ? driver_probe_device+0x370/0x370 [ 17.652101] bus_for_each_dev+0x5b/0x90 [ 17.652101] driver_attach+0x19/0x20 [ 17.652101] bus_add_driver+0x11c/0x220 [ 17.652101] driver_register+0x5b/0xd0 [ 17.652101] ? 0xffffffffa0006000 [ 17.652101] __pci_register_driver+0x47/0x50 [ 17.652101] drm_pci_init+0xe1/0xf0 [ 17.652101] ? 0xffffffffa0006000 [ 17.652101] bochs_init+0x3c/0x1000 [bochs_drm] [ 17.652101] do_one_initcall+0x3e/0x180 [ 17.652101] ? kmem_cache_alloc_trace+0x33/0x150 [ 17.652101] do_init_module+0x5a/0x1eb [ 17.652101] load_module+0x1ea0/0x2650 [ 17.652101] ? __symbol_put+0x40/0x40 [ 17.652101] ? kernel_read_file+0x19e/0x1c0 [ 17.652101] ? kernel_read_file_from_fd+0x44/0x70 [ 17.652101] SYSC_finit_module+0xba/0xc0 [ 17.652101] SyS_finit_module+0x9/0x10 [ 17.652101] entry_SYSCALL_64_fastpath+0x1a/0xa9 [ 17.652101] RIP: 0033:0x7f92854da119 [ 17.652101] RSP: 002b:00007ffcd0390498 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 17.652101] RAX: ffffffffffffffda RBX: 00007f928578eb58 RCX: 00007f92854da119 [ 17.652101] RDX: 0000000000000000 RSI: 0000564f1c8bd638 RDI: 0000000000000003 [ 17.652101] RBP: 000000000000270e R08: 0000000000000000 R09: 00007f9285790ea0 [ 17.652101] R10: 0000000000000003 R11: 0000000000000246 R12: 00007f928578eb58 [ 17.652101] R13: 0000000000001020 R14: 0000564f1cf9e1c0 R15: 00007f928578eb00 [ 17.652101] Code: c7 20 f8 ea 81 e8 b3 3e 50 00 48 8b 83 d0 00 00 00 48 8d 93 d0 00 00 00 48 39 c2 74 46 48 8b 83 d8 00 00 00 48 8b 93 d0 00 00 00 <48> 89 42 08 48 89 10 48 b8 00 01 00 00 0000 ad de 48 89 83 d0 [ 17.652101] RIP: drm_fb_helper_fini+0x8e/0x110 RSP: ffffc90000d87ad0 [ 17.653331] ---[ end trace 542fd75a2e60a6a4 ]--- Signed-off-by: Gabriel Krisman Bertazi Link: http://patchwork.freedesktop.org/patch/msgid/20170324045444.11912-1-krisman@collabora.co.uk Signed-off-by: Gerd Hoffmann --- drivers/gpu/drm/bochs/bochs_fbdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 471bd588550b..c38deffa14de 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -192,6 +192,8 @@ void bochs_fbdev_fini(struct bochs_device *bochs) if (bochs->fb.initialized) bochs_fbdev_destroy(bochs); - drm_fb_helper_fini(&bochs->fb.helper); + if (bochs->fb.helper.fbdev) + drm_fb_helper_fini(&bochs->fb.helper); + bochs->fb.initialized = false; } From 99612b27763f819e53d5d892ce81a4b042a1de11 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:46 +0100 Subject: [PATCH 27/63] drm/tegra: Don't use modeset_lock_crtc Yes the help text is unhelpful, but atomic drivers should never use this. Just grab the lock without context or anything. Also an aside: Checking ->active like this doesn't protect against nonblocking commits, this is rather bogus. Cc: Thierry Reding Acked-by: Thierry Reding Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-8-daniel.vetter@ffwll.ch --- drivers/gpu/drm/tegra/dc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 0db5d5a8d3b9..95b373f739f2 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1382,7 +1382,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data) struct tegra_dc *dc = node->info_ent->data; int err = 0; - drm_modeset_lock_crtc(&dc->base, NULL); + drm_modeset_lock(&dc->base.mutex, NULL); if (!dc->base.state->active) { err = -EBUSY; @@ -1609,7 +1609,7 @@ static int tegra_dc_show_regs(struct seq_file *s, void *data) #undef DUMP_REG unlock: - drm_modeset_unlock_crtc(&dc->base); + drm_modeset_unlock(&dc->base.mutex); return err; } @@ -1620,7 +1620,7 @@ static int tegra_dc_show_crc(struct seq_file *s, void *data) int err = 0; u32 value; - drm_modeset_lock_crtc(&dc->base, NULL); + drm_modeset_lock(&dc->base.mutex, NULL); if (!dc->base.state->active) { err = -EBUSY; @@ -1640,7 +1640,7 @@ static int tegra_dc_show_crc(struct seq_file *s, void *data) tegra_dc_writel(dc, 0, DC_COM_CRC_CONTROL); unlock: - drm_modeset_unlock_crtc(&dc->base); + drm_modeset_unlock(&dc->base.mutex); return err; } From 86cc921cb4aa8fb213dfbe68540a8a6c02f54840 Mon Sep 17 00:00:00 2001 From: Shashank Sharma Date: Tue, 28 Mar 2017 10:06:19 +0300 Subject: [PATCH 28/63] drm: Add description for scdc variable This patch adds description about 'scdc' variable in drm_hdmi_info structure, to fix this warning during doc-build. "drm_connector.h:140: warning: No description found for parameter 'scdc'" V2: Rebase V3: Added extra * V4: Removed merged conflict V5: Removed extra line at start of structure (Daniel) V6: Make description single line (Daniel) Cc: Daniel Vetter Signed-off-by: Shashank Sharma Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1490684779-21633-1-git-send-email-shashank.sharma@intel.com --- include/drm/drm_connector.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index f8b766d70a46..6d3f7ba1c797 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -133,6 +133,7 @@ struct drm_scdc { * This information is available in CEA-861-F extension blocks (like HF-VSDB). */ struct drm_hdmi_info { + /** @scdc: sink's scdc support and capabilities */ struct drm_scdc scdc; }; From 75b94cd96f311a8459720d01da698b6bc2ab88f4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Mar 2017 17:53:47 +0200 Subject: [PATCH 29/63] drm/doc: remove standard connector props from the csv file They're properly documented in drm_connector.c now, and this csv file is a horrible mess. Better to remove it. Reviewed-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170328155349.5972-1-daniel.vetter@ffwll.ch --- Documentation/gpu/kms-properties.csv | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv index 981873a05d14..927b65e14219 100644 --- a/Documentation/gpu/kms-properties.csv +++ b/Documentation/gpu/kms-properties.csv @@ -1,10 +1,5 @@ Owner Module/Drivers,Group,Property Name,Type,Property Values,Object attached,Description/Restrictions ,,“scaling mode”,ENUM,"{ ""None"", ""Full"", ""Center"", ""Full aspect"" }",Connector,"Supported by: amdgpu, gma500, i915, nouveau and radeon." -,Connector,“EDID”,BLOB | IMMUTABLE,0,Connector,Contains id of edid blob ptr object. -,,“DPMS”,ENUM,"{ “On”, “Standby”, “Suspend”, “Off” }",Connector,Contains DPMS operation mode value. -,,“PATH”,BLOB | IMMUTABLE,0,Connector,Contains topology path to a connector. -,,“TILE”,BLOB | IMMUTABLE,0,Connector,Contains tiling information for a connector. -,,“CRTC_ID”,OBJECT,DRM_MODE_OBJECT_CRTC,Connector,CRTC that connector is attached to (atomic) ,DVI-I,“subconnector”,ENUM,"{ “Unknown”, “DVI-D”, “DVI-A” }",Connector,TBD ,,“select subconnector”,ENUM,"{ “Automatic”, “DVI-D”, “DVI-A” }",Connector,TBD ,TV,“subconnector”,ENUM,"{ ""Unknown"", ""Composite"", ""SVIDEO"", ""Component"", ""SCART"" }",Connector,TBD From c9e42b72b44acc67ede9726e6434b12ba153d901 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Mar 2017 17:53:48 +0200 Subject: [PATCH 30/63] drm: Document kms locking a bit better The rules are getting real hard, better to dump my brain into text a bit. This is by far not complete, but I think I reasonable start at least. Some of the older kms structures would need a full doc review anyway ... Cc: Harry Wentland Reviewed-by: Harry Wentland Reviewed-by: Alex Deucher Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170328155349.5972-2-daniel.vetter@ffwll.ch --- include/drm/drm_connector.h | 16 +++- include/drm/drm_crtc.h | 14 +++- include/drm/drm_mode_config.h | 140 ++++++++++++++++++++++++++-------- include/drm/drm_plane.h | 16 +++- 4 files changed, 152 insertions(+), 34 deletions(-) diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6d3f7ba1c797..941f57f311aa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -656,7 +656,6 @@ struct drm_cmdline_mode { * @bad_edid_counter: track sinks that give us an EDID with invalid checksum * @edid_corrupt: indicates whether the last read EDID was corrupt * @debugfs_entry: debugfs directory for this connector - * @state: current atomic state for this connector * @has_tile: is this connector connected to a tiled monitor * @tile_group: tile group for the connected monitor * @tile_is_single_monitor: whether the tile is one monitor housing @@ -824,6 +823,21 @@ struct drm_connector { struct dentry *debugfs_entry; + /** + * @state: + * + * Current atomic state for this connector. + * + * This is protected by @drm_mode_config.connection_mutex. Note that + * nonblocking atomic commits access the current connector state without + * taking locks. Either by going through the &struct drm_atomic_state + * pointers, see for_each_connector_in_state(), + * for_each_oldnew_connector_in_state(), + * for_each_old_connector_in_state() and + * for_each_new_connector_in_state(). Or through careful ordering of + * atomic commit operations as implemented in the atomic helpers, see + * &struct drm_crtc_commit. + */ struct drm_connector_state *state; /* DisplayID bits */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 24dcb121bad4..c1a75a9c81c2 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -699,10 +699,12 @@ struct drm_crtc { /** * @mutex: * - * This provides a read lock for the overall crtc state (mode, dpms + * This provides a read lock for the overall CRTC state (mode, dpms * state, ...) and a write lock for everything which can be update - * without a full modeset (fb, cursor data, crtc properties ...). A full + * without a full modeset (fb, cursor data, CRTC properties ...). A full * modeset also need to grab &drm_mode_config.connection_mutex. + * + * For atomic drivers specifically this protects @state. */ struct drm_modeset_lock mutex; @@ -748,6 +750,14 @@ struct drm_crtc { * @state: * * Current atomic state for this CRTC. + * + * This is protected by @mutex. Note that nonblocking atomic commits + * access the current CRTC state without taking locks. Either by going + * through the &struct drm_atomic_state pointers, see + * for_each_crtc_in_state(), for_each_oldnew_crtc_in_state(), + * for_each_old_crtc_in_state() and for_each_new_crtc_in_state(). Or + * through careful ordering of atomic commit operations as implemented + * in the atomic helpers, see &struct drm_crtc_commit. */ struct drm_crtc_state *state; diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 579070ff06ef..42981711189b 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -307,21 +307,6 @@ struct drm_mode_config_funcs { /** * 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 @@ -332,9 +317,6 @@ struct drm_mode_config_funcs { * @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 @@ -346,9 +328,37 @@ struct drm_mode_config_funcs { * 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() */ + /** + * @mutex: + * + * This is the big scary modeset BKL which protects everything that + * isn't protect otherwise. Scope is unclear and fuzzy, try to remove + * anything from under it's protection and move it into more well-scoped + * locks. + * + * The one important thing this protects is the use of @acquire_ctx. + */ + struct mutex mutex; + + /** + * @connection_mutex: + * + * This protects connector state and the connector to encoder to CRTC + * routing chain. + * + * For atomic drivers specifically this protects &drm_connector.state. + */ + struct drm_modeset_lock connection_mutex; + + /** + * @acquire_ctx: + * + * Global implicit acquire context used by atomic drivers for legacy + * IOCTLs. Deprecated, since implicit locking contexts make it + * impossible to use driver-private &struct drm_modeset_lock. Users of + * this must hold @mutex. + */ + struct drm_modeset_acquire_ctx *acquire_ctx; /** * @idr_mutex: @@ -374,8 +384,11 @@ struct drm_mode_config { */ struct idr tile_idr; - struct mutex fb_lock; /* proctects global and per-file fb lists */ + /** @fb_lock: Mutex to protect fb the global @fb_list and @num_fb. */ + struct mutex fb_lock; + /** @num_fb: Number of entries on @fb_list. */ int num_fb; + /** @fb_list: List of all &struct drm_framebuffer. */ struct list_head fb_list; /** @@ -393,27 +406,80 @@ struct drm_mode_config { */ struct ida connector_ida; /** - * @connector_list: List of connector objects. Protected by - * @connector_list_lock. Only use drm_for_each_connector_iter() and + * @connector_list: + * + * List of connector objects linked with &drm_connector.head. Protected + * by @connector_list_lock. Only use drm_for_each_connector_iter() and * &struct drm_connector_list_iter to walk this list. */ struct list_head connector_list; + /** + * @num_encoder: + * + * Number of encoders on this device. This is invariant over the + * lifetime of a device and hence doesn't need any locks. + */ int num_encoder; + /** + * @encoder_list: + * + * List of encoder objects linked with &drm_encoder.head. This is + * invariant over the lifetime of a device and hence doesn't need any + * locks. + */ 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. + /** + * @num_overlay_plane: + * + * Number of overlay planes on this device, excluding primary and cursor + * planes. + * + * Track number of overlay planes separately from number 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. This is invariant over the lifetime of a + * device and hence doesn't need any locks. */ int num_overlay_plane; + /** + * @num_total_plane: + * + * Number of universal (i.e. with primary/curso) planes on this device. + * This is invariant over the lifetime of a device and hence doesn't + * need any locks. + */ int num_total_plane; + /** + * @plane_list: + * + * List of plane objects linked with &drm_plane.head. This is invariant + * over the lifetime of a device and hence doesn't need any locks. + */ struct list_head plane_list; + /** + * @num_crtc: + * + * Number of CRTCs on this device linked with &drm_crtc.head. This is invariant over the lifetime + * of a device and hence doesn't need any locks. + */ int num_crtc; + /** + * @crtc_list: + * + * List of CRTC objects linked with &drm_crtc.head. This is invariant + * over the lifetime of a device and hence doesn't need any locks. + */ struct list_head crtc_list; + /** + * @property_list: + * + * List of property type objects linked with &drm_property.head. This is + * invariant over the lifetime of a device and hence doesn't need any + * locks. + */ struct list_head property_list; int min_width, min_height; @@ -427,10 +493,24 @@ struct drm_mode_config { bool delayed_event; struct delayed_work output_poll_work; + /** + * @blob_lock: + * + * Mutex for blob property allocation and management, protects + * @property_blob_list and &drm_file.blobs. + */ struct mutex blob_lock; - /* pointers to standard properties */ + /** + * @property_blob_list: + * + * List of all the blob property objects linked with + * &drm_property_blob.head. Protected by @blob_lock. + */ struct list_head property_blob_list; + + /* pointers to standard properties */ + /** * @edid_property: Default connector property to hold the EDID of the * currently connected sink, if any. diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 31da9f0c4ad2..7aedbf34f3a6 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -456,7 +456,6 @@ enum drm_plane_type { * @funcs: helper functions * @properties: property tracking for this plane * @type: type of plane (overlay, primary, cursor) - * @state: current atomic state for this plane * @zpos_property: zpos property for this plane * @rotation_property: rotation property for this plane * @helper_private: mid-layer private data @@ -473,6 +472,8 @@ struct drm_plane { * Protects modeset plane state, together with the &drm_crtc.mutex of * CRTC this plane is linked to (when active, getting activated or * getting disabled). + * + * For atomic drivers specifically this protects @state. */ struct drm_modeset_lock mutex; @@ -502,6 +503,19 @@ struct drm_plane { const struct drm_plane_helper_funcs *helper_private; + /** + * @state: + * + * Current atomic state for this plane. + * + * This is protected by @mutex. Note that nonblocking atomic commits + * access the current plane state without taking locks. Either by going + * through the &struct drm_atomic_state pointers, see + * for_each_plane_in_state(), for_each_oldnew_plane_in_state(), + * for_each_old_plane_in_state() and for_each_new_plane_in_state(). Or + * through careful ordering of atomic commit operations as implemented + * in the atomic helpers, see &struct drm_crtc_commit. + */ struct drm_plane_state *state; struct drm_property *zpos_property; From f9a769555db4c5c384a1d92b471461ef95923feb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Mar 2017 17:53:49 +0200 Subject: [PATCH 31/63] drm: document the all the atomic iterators Mostly because I want the links from the newly-added @state functions to work. But I think explaining when they're useful and that the implicit one is deprecated is good either way. Slightly repetitive unfortunately. Cc: Harry Wentland Cc: Maarten Lankhorst Reviewed-by: Alex Deucher Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170328155349.5972-3-daniel.vetter@ffwll.ch --- include/drm/drm_atomic.h | 159 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 0147a047878d..fd33ed5eaeb4 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -498,6 +498,23 @@ int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); void drm_state_dump(struct drm_device *dev, struct drm_printer *p); +/** + * for_each_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @connector_state: &struct drm_connector_state iteration cursor + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update. Note that before the + * software state is committed (by calling drm_atomic_helper_swap_state(), this + * points to the new state, while afterwards it points to the old state. Due to + * this tricky confusion this macro is deprecated. + * + * FIXME: + * + * Replace all usage of this with one of the explicit iterators below and then + * remove this macro. + */ #define for_each_connector_in_state(__state, connector, connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -506,6 +523,20 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_oldnew_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @old_connector_state: &struct drm_connector_state iteration cursor for the + * old state + * @new_connector_state: &struct drm_connector_state iteration cursor for the + * new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update, tracking both old and + * new state. This is useful in places where the state delta needs to be + * considered, for example in atomic check functions. + */ #define for_each_oldnew_connector_in_state(__state, connector, old_connector_state, new_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -515,6 +546,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_old_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @old_connector_state: &struct drm_connector_state iteration cursor for the + * old state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update, tracking only the old + * state. This is useful in disable functions, where we need the old state the + * hardware is still in. + */ #define for_each_old_connector_in_state(__state, connector, old_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -523,6 +566,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_new_connector_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @connector: &struct drm_connector iteration cursor + * @new_connector_state: &struct drm_connector_state iteration cursor for the + * new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all connectors in an atomic update, tracking only the new + * state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ #define for_each_new_connector_in_state(__state, connector, new_connector_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->num_connector && \ @@ -531,6 +586,23 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (connector) +/** + * for_each_crtc_in_state - iterate over all connectors in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @crtc_state: &struct drm_crtc_state iteration cursor + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update. Note that before the + * software state is committed (by calling drm_atomic_helper_swap_state(), this + * points to the new state, while afterwards it points to the old state. Due to + * this tricky confusion this macro is deprecated. + * + * FIXME: + * + * Replace all usage of this with one of the explicit iterators below and then + * remove this macro. + */ #define for_each_crtc_in_state(__state, crtc, crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -539,6 +611,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc_state) +/** + * for_each_oldnew_crtc_in_state - iterate over all CRTCs in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @old_crtc_state: &struct drm_crtc_state iteration cursor for the old state + * @new_crtc_state: &struct drm_crtc_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update, tracking both old and + * new state. This is useful in places where the state delta needs to be + * considered, for example in atomic check functions. + */ #define for_each_oldnew_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -548,6 +632,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc) +/** + * for_each_old_crtc_in_state - iterate over all CRTCs in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @old_crtc_state: &struct drm_crtc_state iteration cursor for the old state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update, tracking only the old + * state. This is useful in disable functions, where we need the old state the + * hardware is still in. + */ #define for_each_old_crtc_in_state(__state, crtc, old_crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -556,6 +651,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc) +/** + * for_each_new_crtc_in_state - iterate over all CRTCs in an atomic update + * @__state: &struct drm_atomic_state pointer + * @crtc: &struct drm_crtc iteration cursor + * @new_crtc_state: &struct drm_crtc_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all CRTCs in an atomic update, tracking only the new + * state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ #define for_each_new_crtc_in_state(__state, crtc, new_crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -564,6 +670,23 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc) +/** + * for_each_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @plane_state: &struct drm_plane_state iteration cursor + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update. Note that before the + * software state is committed (by calling drm_atomic_helper_swap_state(), this + * points to the new state, while afterwards it points to the old state. Due to + * this tricky confusion this macro is deprecated. + * + * FIXME: + * + * Replace all usage of this with one of the explicit iterators below and then + * remove this macro. + */ #define for_each_plane_in_state(__state, plane, plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -572,6 +695,18 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (plane_state) +/** + * for_each_oldnew_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @old_plane_state: &struct drm_plane_state iteration cursor for the old state + * @new_plane_state: &struct drm_plane_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update, tracking both old and + * new state. This is useful in places where the state delta needs to be + * considered, for example in atomic check functions. + */ #define for_each_oldnew_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -581,6 +716,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (plane) +/** + * for_each_old_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @old_plane_state: &struct drm_plane_state iteration cursor for the old state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update, tracking only the old + * state. This is useful in disable functions, where we need the old state the + * hardware is still in. + */ #define for_each_old_plane_in_state(__state, plane, old_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -589,6 +735,17 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (plane) +/** + * for_each_new_plane_in_state - iterate over all planes in an atomic update + * @__state: &struct drm_atomic_state pointer + * @plane: &struct drm_plane iteration cursor + * @new_plane_state: &struct drm_plane_state iteration cursor for the new state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all planes in an atomic update, tracking only the new + * state. This is useful in enable functions, where we need the new state the + * hardware should be in when the atomic commit operation has completed. + */ #define for_each_new_plane_in_state(__state, plane, new_plane_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -603,7 +760,7 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); * * To give drivers flexibility &struct drm_crtc_state has 3 booleans to track * whether the state CRTC changed enough to need a full modeset cycle: - * connectors_changed, mode_changed and active_changed. This helper simply + * planes_changed, mode_changed and active_changed. This helper simply * combines these three to compute the overall need for a modeset for @state. * * The atomic helper code sets these booleans, but drivers can and should From 232e8f703b96968cd4116d20597068f15aca3e6e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:40 +0100 Subject: [PATCH 32/63] drm: Wire up proper acquire ctx for plane functions This is just prep work to get an acquire ctx into every place where we call ->update_plane or ->disable_plane. v2: Keep the hidden acquire_ctx pointers valid while transitioning. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-2-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane.c | 52 ++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index a22e76837065..0d04888172a7 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -457,7 +457,8 @@ static int __setplane_internal(struct drm_plane *plane, uint32_t crtc_w, uint32_t crtc_h, /* src_{x,y,w,h} values are 16.16 fixed point */ uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { int ret = 0; @@ -537,13 +538,26 @@ static int setplane_internal(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { + struct drm_modeset_acquire_ctx ctx; int ret; - drm_modeset_lock_all(plane->dev); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); + if (ret) + goto fail; + plane->dev->mode_config.acquire_ctx = &ctx; ret = __setplane_internal(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - drm_modeset_unlock_all(plane->dev); + src_x, src_y, src_w, src_h, &ctx); + +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } @@ -613,11 +627,22 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, int32_t crtc_x, crtc_y; uint32_t crtc_w = 0, crtc_h = 0; uint32_t src_w = 0, src_h = 0; + struct drm_modeset_acquire_ctx ctx; int ret = 0; BUG_ON(!crtc->cursor); WARN_ON(crtc->cursor->crtc != crtc && crtc->cursor->crtc != NULL); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto fail; + ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + if (ret) + goto fail; + crtc->acquire_ctx = &ctx; + /* * Obtain fb we'll be using (either new or existing) and take an extra * reference to it if fb != null. setplane will take care of dropping @@ -662,7 +687,7 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, */ ret = __setplane_internal(crtc->cursor, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - 0, 0, src_w, src_h); + 0, 0, src_w, src_h, &ctx); /* Update successful; save new cursor position, if necessary */ if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) { @@ -670,6 +695,15 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, crtc->cursor_y = req->y; } +fail: + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } @@ -696,12 +730,10 @@ static int drm_mode_cursor_common(struct drm_device *dev, * If this crtc has a universal cursor plane, call that plane's update * handler rather than using legacy cursor handlers. */ - drm_modeset_lock_crtc(crtc, crtc->cursor); - if (crtc->cursor) { - ret = drm_mode_cursor_universal(crtc, req, file_priv); - goto out; - } + if (crtc->cursor) + return drm_mode_cursor_universal(crtc, req, file_priv); + drm_modeset_lock_crtc(crtc, crtc->cursor); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { ret = -ENXIO; From 34a2ab5e0689e5174dd50e4a96e73c1c00539fdb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:41 +0100 Subject: [PATCH 33/63] drm: Add acquire ctx parameter to ->update_plane Just rolling it out, no code change here. Cc: Ben Skeggs Cc: Russell King Cc: Rob Clark Cc: Laurent Pinchart Cc: Eric Anholt Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-3-daniel.vetter@ffwll.ch --- drivers/gpu/drm/armada/armada_overlay.c | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 4 +++- drivers/gpu/drm/drm_plane.c | 2 +- drivers/gpu/drm/drm_plane_helper.c | 4 +++- drivers/gpu/drm/i915/intel_display.c | 5 +++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c | 8 +++++--- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 6 ++++-- drivers/gpu/drm/shmobile/shmob_drm_plane.c | 3 ++- drivers/gpu/drm/vc4/vc4_plane.c | 6 ++++-- include/drm/drm_atomic_helper.h | 3 ++- include/drm/drm_plane.h | 4 +++- include/drm/drm_plane_helper.h | 3 ++- 12 files changed, 34 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index 34cb73d0db77..b54fd8cbd3a6 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -94,7 +94,8 @@ static int armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h, - uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) + uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c3ace44e1c8e..e552687dcac6 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2077,6 +2077,7 @@ EXPORT_SYMBOL(drm_atomic_helper_swap_state); * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb * @src_h: height of source rectangle in @fb + * @ctx: lock acquire context * * Provides a default plane update handler using the atomic driver interface. * @@ -2089,7 +2090,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_state *state; struct drm_plane_state *plane_state; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 0d04888172a7..8a4e75929810 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -510,7 +510,7 @@ static int __setplane_internal(struct drm_plane *plane, plane->old_fb = plane->fb; ret = plane->funcs->update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); if (!ret) { plane->crtc = crtc; plane->fb = fb; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index de1ac5e08f4d..2339879f775d 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -275,6 +275,7 @@ EXPORT_SYMBOL(drm_plane_helper_check_update); * @src_y: y offset of @fb for panning * @src_w: width of source rectangle in @fb * @src_h: height of source rectangle in @fb + * @ctx: lock acquire context, not used here * * Provides a default plane update handler for primary planes. This is handler * is called in response to a userspace SetPlane operation on the plane with a @@ -303,7 +304,8 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_mode_set set = { .crtc = crtc, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 010e5ddb198a..e27ea89efd67 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13426,7 +13426,8 @@ intel_legacy_cursor_update(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_i915_private *dev_priv = to_i915(crtc->dev); int ret; @@ -13539,7 +13540,7 @@ out_free: slow: return drm_atomic_helper_update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); } static const struct drm_plane_funcs intel_cursor_plane_funcs = { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 0ffb8affef35..60a5451ae0b9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -37,7 +37,8 @@ static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); static void set_scanout_locked(struct drm_plane *plane, struct drm_framebuffer *fb); @@ -886,7 +887,8 @@ static int mdp5_update_cursor_plane_legacy(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane_state *plane_state, *new_plane_state; struct mdp5_plane_state *mdp5_pstate; @@ -954,7 +956,7 @@ slow_free: slow: return drm_atomic_helper_update_plane(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); + src_x, src_y, src_w, src_h, ctx); } enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 5319f2a7f24d..2d90e7898ec8 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -94,7 +94,8 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct nouveau_drm *drm = nouveau_drm(plane->dev); struct nvif_object *dev = &drm->client.device.object; @@ -345,7 +346,8 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; struct nouveau_plane *nv_plane = diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 2023a93cee2b..9a3c8ddfe198 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -177,7 +177,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct shmob_drm_plane *splane = to_shmob_plane(plane); struct shmob_drm_device *sdev = plane->dev->dev_private; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 0f4564beb017..d34cd5393a9b 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -756,7 +756,8 @@ vc4_update_plane(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane_state *plane_state; struct vc4_plane_state *vc4_state; @@ -817,7 +818,8 @@ out: crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, - src_w, src_h); + src_w, src_h, + ctx); } static const struct drm_plane_funcs vc4_plane_funcs = { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 969f7237f1fc..62ac6053721d 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -94,7 +94,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); int drm_atomic_helper_disable_plane(struct drm_plane *plane); int __drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_plane_state *plane_state); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 7aedbf34f3a6..ab3bdfb897c4 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -29,6 +29,7 @@ struct drm_crtc; struct drm_printer; +struct drm_modeset_acquire_ctx; /** * struct drm_plane_state - mutable plane state @@ -184,7 +185,8 @@ struct drm_plane_funcs { int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); /** * @disable_plane: diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index c18959685c06..ea219423d72b 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -61,7 +61,8 @@ int drm_primary_helper_update(struct drm_plane *plane, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); + uint32_t src_w, uint32_t src_h, + struct drm_modeset_acquire_ctx *ctx); int drm_primary_helper_disable(struct drm_plane *plane); void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; From 5fbef3ee4a28f968e9d0ea97c6dc80388287122b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:42 +0100 Subject: [PATCH 34/63] drm: drm_plane_force_disable is not for atomic drivers This way I can explain why it'll be fine to pass a NULL acquire ctx here in the next patch. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-4-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 8a4e75929810..67119332c441 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -277,6 +277,12 @@ EXPORT_SYMBOL(drm_plane_from_index); * * Used when the plane's current framebuffer is destroyed, * and when restoring fbdev mode. + * + * Note that this function is not suitable for atomic drivers, since it doesn't + * wire through the lock acquisition context properly and hence can't handle + * retries or driver private locks. You probably want to use + * drm_atomic_helper_disable_plane() or + * drm_atomic_helper_disable_planes_on_crtc() instead. */ void drm_plane_force_disable(struct drm_plane *plane) { @@ -285,6 +291,8 @@ void drm_plane_force_disable(struct drm_plane *plane) if (!plane->fb) return; + WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); + plane->old_fb = plane->fb; ret = plane->funcs->disable_plane(plane); if (ret) { From 1931529448bca3e0e77fb526baad20935c9cabaf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:43 +0100 Subject: [PATCH 35/63] drm: Add acquire ctx parameter to ->plane_disable Nouveau had a few direct calls to ->disable_plane, I replaced those with drm_plane_force_disable. Same story for shmob. Otherwise no code changes. Cc: Ben Skeggs Cc: Russell King Cc: Laurent Pinchart Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-5-daniel.vetter@ffwll.ch --- drivers/gpu/drm/armada/armada_overlay.c | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 4 +++- drivers/gpu/drm/drm_plane.c | 4 ++-- drivers/gpu/drm/drm_plane_helper.c | 5 +++-- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 12 +++++++----- drivers/gpu/drm/shmobile/shmob_drm_plane.c | 5 +++-- include/drm/drm_atomic_helper.h | 3 ++- include/drm/drm_plane.h | 3 ++- include/drm/drm_plane_helper.h | 3 ++- 9 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index b54fd8cbd3a6..424e465ff407 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -258,7 +258,8 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, return 0; } -static int armada_ovl_plane_disable(struct drm_plane *plane) +static int armada_ovl_plane_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); struct drm_framebuffer *fb; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e552687dcac6..6096233a740c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2151,13 +2151,15 @@ EXPORT_SYMBOL(drm_atomic_helper_update_plane); /** * drm_atomic_helper_disable_plane - Helper for primary plane disable using * atomic * @plane: plane to disable + * @ctx: lock acquire context * * Provides a default plane disable handler using the atomic driver interface. * * RETURNS: * Zero on success, error code on failure */ -int drm_atomic_helper_disable_plane(struct drm_plane *plane) +int drm_atomic_helper_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_state *state; struct drm_plane_state *plane_state; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 67119332c441..526e74b548b2 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -294,7 +294,7 @@ void drm_plane_force_disable(struct drm_plane *plane) WARN_ON(drm_drv_uses_atomic_modeset(plane->dev)); plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); + ret = plane->funcs->disable_plane(plane, NULL); if (ret) { DRM_ERROR("failed to disable plane with busy fb\n"); plane->old_fb = NULL; @@ -473,7 +473,7 @@ static int __setplane_internal(struct drm_plane *plane, /* No fb means shut it down */ if (!fb) { plane->old_fb = plane->fb; - ret = plane->funcs->disable_plane(plane); + ret = plane->funcs->disable_plane(plane, ctx); if (!ret) { plane->crtc = NULL; plane->fb = NULL; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 2339879f775d..775e94c30368 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -349,7 +349,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, * provides their own disable function, this will just * wind up returning -EINVAL to userspace. */ - return plane->funcs->disable_plane(plane); + return plane->funcs->disable_plane(plane, ctx); /* Find current connectors for CRTC */ num_connectors = get_connectors_for_crtc(crtc, NULL, 0); @@ -398,7 +398,8 @@ EXPORT_SYMBOL(drm_primary_helper_update); * RETURNS: * Unconditionally returns -EINVAL. */ -int drm_primary_helper_disable(struct drm_plane *plane) +int drm_primary_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 2d90e7898ec8..e54944d23268 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -173,7 +173,8 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static int -nv10_disable_plane(struct drm_plane *plane) +nv10_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; struct nouveau_plane *nv_plane = @@ -191,7 +192,7 @@ nv10_disable_plane(struct drm_plane *plane) static void nv_destroy_plane(struct drm_plane *plane) { - plane->funcs->disable_plane(plane); + drm_plane_force_disable(plane); drm_plane_cleanup(plane); kfree(plane); } @@ -332,7 +333,7 @@ nv10_overlay_init(struct drm_device *device) plane->set_params = nv10_set_params; nv10_set_params(plane); - nv10_disable_plane(&plane->base); + drm_plane_force_disable(&plane->base); return; cleanup: drm_plane_cleanup(&plane->base); @@ -427,7 +428,8 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static int -nv04_disable_plane(struct drm_plane *plane) +nv04_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct nvif_object *dev = &nouveau_drm(plane->dev)->client.device.object; struct nouveau_plane *nv_plane = @@ -485,7 +487,7 @@ nv04_overlay_init(struct drm_device *device) drm_object_attach_property(&plane->base.base, plane->props.brightness, plane->brightness); - nv04_disable_plane(&plane->base); + drm_plane_force_disable(&plane->base); return; cleanup: drm_plane_cleanup(&plane->base); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 9a3c8ddfe198..97f6e4a3eb0d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -209,7 +209,8 @@ shmob_drm_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, return 0; } -static int shmob_drm_plane_disable(struct drm_plane *plane) +static int shmob_drm_plane_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx) { struct shmob_drm_plane *splane = to_shmob_plane(plane); struct shmob_drm_device *sdev = plane->dev->dev_private; @@ -222,7 +223,7 @@ static int shmob_drm_plane_disable(struct drm_plane *plane) static void shmob_drm_plane_destroy(struct drm_plane *plane) { - shmob_drm_plane_disable(plane); + drm_plane_force_disable(plane); drm_plane_cleanup(plane); } diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 62ac6053721d..73554fff086a 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -96,7 +96,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, struct drm_modeset_acquire_ctx *ctx); -int drm_atomic_helper_disable_plane(struct drm_plane *plane); +int drm_atomic_helper_disable_plane(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); int __drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_plane_state *plane_state); int drm_atomic_helper_set_config(struct drm_mode_set *set); diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index ab3bdfb897c4..9ab3e7044812 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -203,7 +203,8 @@ struct drm_plane_funcs { * * 0 on success or a negative error code on failure. */ - int (*disable_plane)(struct drm_plane *plane); + int (*disable_plane)(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); /** * @destroy: diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h index ea219423d72b..7c8a00ceadb7 100644 --- a/include/drm/drm_plane_helper.h +++ b/include/drm/drm_plane_helper.h @@ -63,7 +63,8 @@ int drm_primary_helper_update(struct drm_plane *plane, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h, struct drm_modeset_acquire_ctx *ctx); -int drm_primary_helper_disable(struct drm_plane *plane); +int drm_primary_helper_disable(struct drm_plane *plane, + struct drm_modeset_acquire_ctx *ctx); void drm_primary_helper_destroy(struct drm_plane *plane); extern const struct drm_plane_funcs drm_primary_helper_funcs; From d26f96c74dd027caf14713ae736b4d174535412d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:44 +0100 Subject: [PATCH 36/63] drm/atomic-helper: remove backoff hack from disable/update_plane We can now properly retry at the top level, yay! v2: Also remove the temporary acquire_ctx hack again, no longer needed! Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-6-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 49 ++--------------------------- drivers/gpu/drm/drm_plane.c | 2 -- 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 6096233a740c..cc6e2772b32f 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2101,8 +2101,7 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); -retry: + state->acquire_ctx = ctx; plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { ret = PTR_ERR(plane_state); @@ -2127,24 +2126,8 @@ retry: ret = drm_atomic_commit(state); fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_update_plane); @@ -2165,23 +2148,11 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_plane_state *plane_state; int ret = 0; - /* - * FIXME: Without plane->crtc set we can't get at the implicit legacy - * acquire context. The real fix will be to wire the acquire ctx through - * everywhere we need it, but meanwhile prevent chaos by just skipping - * this noop. The critical case is the cursor ioctls which a) only grab - * crtc/cursor-plane locks (so we need the crtc to get at the right - * acquire context) and b) can try to disable the plane multiple times. - */ - if (!plane->crtc) - return 0; - state = drm_atomic_state_alloc(plane->dev); if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(plane->crtc); -retry: + state->acquire_ctx = ctx; plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { ret = PTR_ERR(plane_state); @@ -2197,24 +2168,8 @@ retry: ret = drm_atomic_commit(state); fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_disable_plane); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 526e74b548b2..8535dc17db7e 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -554,7 +554,6 @@ retry: ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); if (ret) goto fail; - plane->dev->mode_config.acquire_ctx = &ctx; ret = __setplane_internal(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, &ctx); @@ -649,7 +648,6 @@ retry: ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); if (ret) goto fail; - crtc->acquire_ctx = &ctx; /* * Obtain fb we'll be using (either new or existing) and take an extra From 29dc0d1de18239cf3ef8bab578b8321ed340d81c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:49 +0100 Subject: [PATCH 37/63] drm: Roll out acquire context for the page_flip ioctl Again just prep work. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-11-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 8535dc17db7e..62e833ffeffd 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -803,6 +803,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, struct drm_framebuffer *fb = NULL; struct drm_pending_vblank_event *e = NULL; u32 target_vblank = page_flip->sequence; + struct drm_modeset_acquire_ctx ctx; int ret = -EINVAL; if (!drm_core_check_feature(dev, DRIVER_MODESET)) @@ -866,7 +867,16 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, return -EINVAL; } - drm_modeset_lock_crtc(crtc, crtc->primary); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock(&crtc->mutex, &ctx); + if (ret) + goto out; + ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + if (ret) + goto out; + crtc->acquire_ctx = &ctx; + if (crtc->primary->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not @@ -944,7 +954,14 @@ out: if (crtc->primary->old_fb) drm_framebuffer_put(crtc->primary->old_fb); crtc->primary->old_fb = NULL; - drm_modeset_unlock_crtc(crtc); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); return ret; } From 41292b1fa13a894c1108d4a1c7f8a59fbb307aa6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:50 +0100 Subject: [PATCH 38/63] drm: Add acquire ctx parameter to ->page_flip(_target) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Again just going through the motions, no functional changes in here. Cc: Gerd Hoffmann Cc: Ben Skeggs Cc: Russell King Cc: Laurent Pinchart Cc: Eric Anholt Cc: Alex Deucher Cc: Christian König Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter t Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-12-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 3 ++- drivers/gpu/drm/armada/armada_crtc.c | 3 ++- drivers/gpu/drm/bochs/bochs_kms.c | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++++-- drivers/gpu/drm/drm_plane.c | 6 ++++-- drivers/gpu/drm/nouveau/nouveau_display.c | 3 ++- drivers/gpu/drm/nouveau/nouveau_display.h | 3 ++- drivers/gpu/drm/radeon/radeon_display.c | 3 ++- drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 3 ++- drivers/gpu/drm/udl/udl_modeset.c | 3 ++- drivers/gpu/drm/vc4/vc4_crtc.c | 5 +++-- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 3 ++- include/drm/drm_atomic_helper.h | 6 ++++-- include/drm/drm_crtc.h | 6 ++++-- 16 files changed, 43 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 39fc388f222a..7b4fe91d3aec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -311,7 +311,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, - uint32_t target) + uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct amdgpu_bo *new_abo; struct amdgpu_flip_work *work; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index c12497bd3889..8573a818323f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -594,7 +594,8 @@ int amdgpu_crtc_set_config(struct drm_mode_set *set); int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags, uint32_t target); + uint32_t page_flip_flags, uint32_t target, + struct drm_modeset_acquire_ctx *ctx); void amdgpu_crtc_cleanup_flip_ctx(struct amdgpu_flip_work *work, struct amdgpu_bo *new_abo); int amdgpu_crtc_prepare_flip(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 1341e0b9368a..4fe19fde84f9 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1027,7 +1027,8 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc) * and a mode_set. */ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags) + struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); struct armada_frame_work *work; diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index d5e63eff357b..6a91e62da2f4 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -96,7 +96,8 @@ static void bochs_crtc_commit(struct drm_crtc *crtc) static int bochs_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct bochs_device *bochs = container_of(crtc, struct bochs_device, crtc); diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index cc6e2772b32f..96561ecf736f 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2859,6 +2859,7 @@ static int page_flip_common( * @fb: DRM framebuffer * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates + * @ctx: lock acquisition context * * Provides a default &drm_crtc_funcs.page_flip implementation * using the atomic driver interface. @@ -2872,7 +2873,8 @@ static int page_flip_common( int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane *plane = crtc->primary; struct drm_atomic_state *state; @@ -2920,6 +2922,7 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); * @event: optional DRM event to signal upon completion * @flags: flip flags for non-vblank sync'ed updates * @target: specifying the target vblank period when the flip to take effect + * @ctx: lock acquisition context * * Provides a default &drm_crtc_funcs.page_flip_target implementation. * Similar to drm_atomic_helper_page_flip() with extra parameter to specify @@ -2933,7 +2936,8 @@ int drm_atomic_helper_page_flip_target( struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, - uint32_t target) + uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct drm_plane *plane = crtc->primary; struct drm_atomic_state *state; diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 62e833ffeffd..373e980d698d 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -932,9 +932,11 @@ retry: if (crtc->funcs->page_flip_target) ret = crtc->funcs->page_flip_target(crtc, fb, e, page_flip->flags, - target_vblank); + target_vblank, + &ctx); else - ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); + ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags, + &ctx); if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) drm_event_cancel_free(dev, &e->base); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index c014bae7c5e7..6104f61b00fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -792,7 +792,8 @@ fail: int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, u32 flags) + struct drm_pending_vblank_event *event, u32 flags, + struct drm_modeset_acquire_ctx *ctx) { const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 4a75df06c139..8b33e1db247e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -76,7 +76,8 @@ int nouveau_display_vblstamp(struct drm_device *, unsigned int, int *, int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags); + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx); int nouveau_finish_page_flip(struct nouveau_channel *, struct nouveau_page_flip_state *); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index aea8b62835a4..31020db573d5 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -485,7 +485,8 @@ static int radeon_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, - uint32_t target) + uint32_t target, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 5fcabc04f307..e7738939a86d 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -449,7 +449,8 @@ void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc) static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); struct drm_device *dev = scrtc->crtc.dev; diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index f2b2481cad52..5bcae7649795 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -361,7 +361,8 @@ static void udl_crtc_destroy(struct drm_crtc *crtc) static int udl_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) + uint32_t page_flip_flags, + struct drm_modeset_acquire_ctx *ctx) { struct udl_framebuffer *ufb = to_udl_fb(fb); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 24edd0c22cc9..865e9f494bcc 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -807,12 +807,13 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, static int vc4_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { if (flags & DRM_MODE_PAGE_FLIP_ASYNC) return vc4_async_page_flip(crtc, fb, event, flags); else - return drm_atomic_helper_page_flip(crtc, fb, event, flags); + return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx); } static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index d4268efc37d2..53cf3be7a902 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -395,7 +395,8 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct drm_framebuffer *old_fb = crtc->primary->fb; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index b27cd18ee66a..85e12309cb71 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -649,7 +649,8 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *new_fb, struct drm_pending_vblank_event *event, - uint32_t flags) + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 73554fff086a..9675cacb72a3 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -125,13 +125,15 @@ int drm_atomic_helper_connector_set_property(struct drm_connector *connector, int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags); + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx); int drm_atomic_helper_page_flip_target( struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, - uint32_t target); + uint32_t target, + struct drm_modeset_acquire_ctx *ctx); int drm_atomic_helper_connector_dpms(struct drm_connector *connector, int mode); struct drm_encoder * diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c1a75a9c81c2..1a525ce66468 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -405,7 +405,8 @@ struct drm_crtc_funcs { int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags); + uint32_t flags, + struct drm_modeset_acquire_ctx *ctx); /** * @page_flip_target: @@ -423,7 +424,8 @@ struct drm_crtc_funcs { int (*page_flip_target)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, - uint32_t flags, uint32_t target); + uint32_t flags, uint32_t target, + struct drm_modeset_acquire_ctx *ctx); /** * @set_property: From 043e7fb6e6c3a3fc6d5a3a434ad555e5ff79da3b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:51 +0100 Subject: [PATCH 39/63] drm/atomic-helper: remove backoff hack from page_flip Yay, we can now properly retry in case of deadlocks or whatever! Also don't forget to remove the transitional crtc->acquire_ctx assignment again. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-13-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 40 ++--------------------------- drivers/gpu/drm/drm_plane.c | 1 - 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 96561ecf736f..5771def4cef0 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2884,34 +2884,16 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = ctx; -retry: ret = page_flip_common(state, crtc, fb, event, flags); if (ret != 0) goto fail; ret = drm_atomic_nonblocking_commit(state); - fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_page_flip); @@ -2948,9 +2930,8 @@ int drm_atomic_helper_page_flip_target( if (!state) return -ENOMEM; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + state->acquire_ctx = ctx; -retry: ret = page_flip_common(state, crtc, fb, event, flags); if (ret != 0) goto fail; @@ -2963,26 +2944,9 @@ retry: crtc_state->target_vblank = target; ret = drm_atomic_nonblocking_commit(state); - fail: - if (ret == -EDEADLK) - goto backoff; - drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - plane->old_fb = plane->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 373e980d698d..ec3e2e757800 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -875,7 +875,6 @@ retry: ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); if (ret) goto out; - crtc->acquire_ctx = &ctx; if (crtc->primary->fb == NULL) { /* The framebuffer is currently unbound, presumably From 2c77bb29d3985e73f8c780cfd20fdb2f491943ee Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Mar 2017 09:01:45 +0200 Subject: [PATCH 40/63] drm: simplify the locking in the GETCRTC ioctl No need to grab both plane and crtc locks at the same time, we can do them one after the other. If userspace races it'll get what it deserves either way. This removes another user of drm_modeset_lock_crtc. There's only one left. v2: Make sure all access to primary->state is properly protected (Harry). Cc: Harry Wentland Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170328070145.21520-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 11 ++++++++--- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 660b4c8715de..55b3da2e2a82 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -406,9 +406,9 @@ int drm_mode_getcrtc(struct drm_device *dev, if (!crtc) return -ENOENT; - drm_modeset_lock_crtc(crtc, crtc->primary); crtc_resp->gamma_size = crtc->gamma_size; + drm_modeset_lock(&crtc->primary->mutex, NULL); if (crtc->primary->state && crtc->primary->state->fb) crtc_resp->fb_id = crtc->primary->state->fb->base.id; else if (!crtc->primary->state && crtc->primary->fb) @@ -416,9 +416,14 @@ int drm_mode_getcrtc(struct drm_device *dev, else crtc_resp->fb_id = 0; - if (crtc->state) { + if (crtc->primary->state) { crtc_resp->x = crtc->primary->state->src_x >> 16; crtc_resp->y = crtc->primary->state->src_y >> 16; + } + drm_modeset_unlock(&crtc->primary->mutex); + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state) { if (crtc->state->enable) { drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode); crtc_resp->mode_valid = 1; @@ -437,7 +442,7 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->mode_valid = 0; } } - drm_modeset_unlock_crtc(crtc); + drm_modeset_unlock(&crtc->mutex); return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e27ea89efd67..78994fdc00a4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12468,6 +12468,11 @@ static int intel_atomic_check(struct drm_device *dev, ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; + /* enocder->atomic_check might upgrade some crtc to a full modeset */ + ret = drm_atomic_helper_check_modeset(dev, state); + if (ret) + return ret; + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) { struct intel_crtc_state *pipe_config = From d49473a53aec5bff366c607bd2a0388554b112f5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:55 +0100 Subject: [PATCH 41/63] drm: Restrict drm_mode_set_config_internal to non-atomic drivers This is another case where we really can't reconstruct a acquire ctx in any useful fashion because all the callers are legacy drivers. So like drm_plane_force_disable simply restrict it to non-atomic drivers so that it's clear we're ok with passing a NULL ctx. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-17-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 55b3da2e2a82..685bf146a482 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -447,18 +447,7 @@ int drm_mode_getcrtc(struct drm_device *dev, return 0; } -/** - * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config - * @set: modeset config to set - * - * This is a little helper to wrap internal calls to the - * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is - * correct refcounting dance. - * - * Returns: - * Zero on success, negative errno on failure. - */ -int drm_mode_set_config_internal(struct drm_mode_set *set) +static int __drm_mode_set_config_internal(struct drm_mode_set *set) { struct drm_crtc *crtc = set->crtc; struct drm_framebuffer *fb; @@ -491,6 +480,25 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) return ret; } +/** + * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config + * @set: modeset config to set + * + * This is a little helper to wrap internal calls to the + * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is + * correct refcounting dance. + * + * This should only be used by non-atomic legacy drivers. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_mode_set_config_internal(struct drm_mode_set *set) +{ + WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev)); + + return __drm_mode_set_config_internal(set); +} EXPORT_SYMBOL(drm_mode_set_config_internal); /** @@ -688,7 +696,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = drm_mode_set_config_internal(&set); + ret = __drm_mode_set_config_internal(&set); out: if (fb) From 2ceb585a956c10c7daf22938c77c48e3a62e0f6d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:56 +0100 Subject: [PATCH 42/63] drm: Add explicit acquire ctx handling around ->set_config Just the groundwork to have something to feed into ->set_config. Again we need a temporary hack to still fill out the legacy ctx in mode_config.acquire_ctx. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-18-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_crtc.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 685bf146a482..3553d8232649 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -447,7 +447,8 @@ int drm_mode_getcrtc(struct drm_device *dev, return 0; } -static int __drm_mode_set_config_internal(struct drm_mode_set *set) +static int __drm_mode_set_config_internal(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_crtc *crtc = set->crtc; struct drm_framebuffer *fb; @@ -497,7 +498,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) { WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev)); - return __drm_mode_set_config_internal(set); + return __drm_mode_set_config_internal(set, NULL); } EXPORT_SYMBOL(drm_mode_set_config_internal); @@ -554,6 +555,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_display_mode *mode = NULL; struct drm_mode_set set; uint32_t __user *set_connectors_ptr; + struct drm_modeset_acquire_ctx ctx; int ret; int i; @@ -567,15 +569,19 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000) return -ERANGE; - drm_modeset_lock_all(dev); crtc = drm_crtc_find(dev, crtc_req->crtc_id); if (!crtc) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); - ret = -ENOENT; - goto out; + return -ENOENT; } DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name); + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); + if (ret) + goto out; + dev->mode_config.acquire_ctx = &ctx; if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ @@ -696,7 +702,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, set.connectors = connector_set; set.num_connectors = crtc_req->count_connectors; set.fb = fb; - ret = __drm_mode_set_config_internal(&set); + ret = __drm_mode_set_config_internal(&set, &ctx); out: if (fb) @@ -710,7 +716,13 @@ out: } kfree(connector_set); drm_mode_destroy(dev, mode); - drm_modeset_unlock_all(dev); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } From a4eff9aa6db8eb3d1864118f3558214b26f630b4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:57 +0100 Subject: [PATCH 43/63] drm: Add acquire ctx parameter to ->set_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surprisingly a lot of legacy drivers roll their own, for runtime pm and because vmwgfx. Also make nouveau's set_config static while at it. Cc: Sinclair Yeh Cc: Thomas Hellstrom Cc: Ben Skeggs Cc: Patrik Jakobsson Cc: Alex Deucher Cc: Christian König Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-19-daniel.vetter@ffwll.ch --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 5 +++-- drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h | 3 ++- drivers/gpu/drm/drm_atomic_helper.c | 4 +++- drivers/gpu/drm/drm_crtc.c | 2 +- drivers/gpu/drm/drm_crtc_helper.c | 4 +++- drivers/gpu/drm/drm_plane_helper.c | 2 +- drivers/gpu/drm/gma500/gma_display.c | 7 ++++--- drivers/gpu/drm/gma500/gma_display.h | 3 ++- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 7 ++++--- drivers/gpu/drm/nouveau/nouveau_display.h | 1 - drivers/gpu/drm/radeon/radeon_display.c | 5 +++-- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 3 ++- include/drm/drm_atomic_helper.h | 3 ++- include/drm/drm_crtc.h | 3 ++- include/drm/drm_crtc_helper.h | 3 ++- 17 files changed, 38 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 7b4fe91d3aec..ce15721cadda 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -333,7 +333,8 @@ int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, return 0; } -int amdgpu_crtc_set_config(struct drm_mode_set *set) +int amdgpu_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct amdgpu_device *adev; @@ -350,7 +351,7 @@ int amdgpu_crtc_set_config(struct drm_mode_set *set) if (ret < 0) return ret; - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->enabled) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 8573a818323f..db8f8dda209c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -590,7 +590,8 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile /* amdgpu_display.c */ void amdgpu_print_display_setup(struct drm_device *dev); int amdgpu_modeset_create_props(struct amdgpu_device *adev); -int amdgpu_crtc_set_config(struct drm_mode_set *set); +int amdgpu_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5771def4cef0..c137e39fc506 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2265,6 +2265,7 @@ static int update_output_state(struct drm_atomic_state *state, /** * drm_atomic_helper_set_config - set a new config from userspace * @set: mode set configuration + * @ctx: lock acquisition context * * Provides a default crtc set_config handler using the atomic driver interface. * @@ -2277,7 +2278,8 @@ static int update_output_state(struct drm_atomic_state *state, * Returns: * Returns 0 on success, negative errno numbers on failure. */ -int drm_atomic_helper_set_config(struct drm_mode_set *set) +int drm_atomic_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_state *state; struct drm_crtc *crtc = set->crtc; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 3553d8232649..b3f9f178375d 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -465,7 +465,7 @@ static int __drm_mode_set_config_internal(struct drm_mode_set *set, fb = set->fb; - ret = crtc->funcs->set_config(set); + ret = crtc->funcs->set_config(set, ctx); if (ret == 0) { crtc->primary->crtc = crtc; crtc->primary->fb = fb; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 8aa8c1084121..4afdf7902eda 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -476,6 +476,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) /** * drm_crtc_helper_set_config - set a new config from userspace * @set: mode set configuration + * @ctx: lock acquire context, not used here * * The drm_crtc_helper_set_config() helper function implements the of * &drm_crtc_funcs.set_config callback for drivers using the legacy CRTC @@ -510,7 +511,8 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) * Returns: * Returns 0 on success, negative errno numbers on failure. */ -int drm_crtc_helper_set_config(struct drm_mode_set *set) +int drm_crtc_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct drm_crtc **save_encoder_crtcs, *new_crtc; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 775e94c30368..b84a295230fc 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -371,7 +371,7 @@ int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, * drm_mode_setplane() already handles the basic refcounting for the * framebuffers involved in this operation. */ - ret = crtc->funcs->set_config(&set); + ret = crtc->funcs->set_config(&set, ctx); kfree(connector_list); return ret; diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index d1c5642b1c1e..93ff46535c04 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -514,17 +514,18 @@ void gma_crtc_destroy(struct drm_crtc *crtc) kfree(gma_crtc); } -int gma_crtc_set_config(struct drm_mode_set *set) +int gma_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev = set->crtc->dev; struct drm_psb_private *dev_priv = dev->dev_private; int ret; if (!dev_priv->rpm_enabled) - return drm_crtc_helper_set_config(set); + return drm_crtc_helper_set_config(set, ctx); pm_runtime_forbid(&dev->pdev->dev); - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); pm_runtime_allow(&dev->pdev->dev); return ret; diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index e72dd08b701b..166e608923db 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -79,7 +79,8 @@ extern void gma_crtc_prepare(struct drm_crtc *crtc); extern void gma_crtc_commit(struct drm_crtc *crtc); extern void gma_crtc_disable(struct drm_crtc *crtc); extern void gma_crtc_destroy(struct drm_crtc *crtc); -extern int gma_crtc_set_config(struct drm_mode_set *set); +extern int gma_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); extern void gma_crtc_save(struct drm_crtc *crtc); extern void gma_crtc_restore(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index ab7b69c11d40..43ab560de7f9 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -1031,8 +1031,9 @@ nv04_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) return 0; } -int -nouveau_crtc_set_config(struct drm_mode_set *set) +static int +nouveau_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct nouveau_drm *drm; @@ -1049,7 +1050,7 @@ nouveau_crtc_set_config(struct drm_mode_set *set) if (ret < 0 && ret != -EACCES) return ret; - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); drm = nouveau_drm(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 8b33e1db247e..e1d772d39488 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -88,7 +88,6 @@ int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, void nouveau_hdmi_mode_set(struct drm_encoder *, struct drm_display_mode *); -int nouveau_crtc_set_config(struct drm_mode_set *set); #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT extern int nouveau_backlight_init(struct drm_device *); extern void nouveau_backlight_exit(struct drm_device *); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 31020db573d5..146297a702ab 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -624,7 +624,8 @@ cleanup: } static int -radeon_crtc_set_config(struct drm_mode_set *set) +radeon_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct drm_device *dev; struct radeon_device *rdev; @@ -641,7 +642,7 @@ radeon_crtc_set_config(struct drm_mode_set *set) if (ret < 0) return ret; - ret = drm_crtc_helper_set_config(set); + ret = drm_crtc_helper_set_config(set, ctx); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) if (crtc->enabled) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 3806148e1bdb..08a66f0db2ec 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -208,7 +208,8 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv, return 0; } -static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) +static int vmw_ldu_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv; struct vmw_legacy_display_unit *ldu; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 53cf3be7a902..e9d3c4b92df7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -248,7 +248,8 @@ static int vmw_sou_backing_alloc(struct vmw_private *dev_priv, return ret; } -static int vmw_sou_crtc_set_config(struct drm_mode_set *set) +static int vmw_sou_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv; struct vmw_screen_object_unit *sou; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 85e12309cb71..b2c9d6ce7ce4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -509,7 +509,8 @@ out_srf_unref: * RETURNS: * 0 on success, error code otherwise */ -static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) +static int vmw_stdu_crtc_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx) { struct vmw_private *dev_priv; struct vmw_framebuffer *vfb; diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 9675cacb72a3..fd395dc050ee 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -100,7 +100,8 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_modeset_acquire_ctx *ctx); int __drm_atomic_helper_disable_plane(struct drm_plane *plane, struct drm_plane_state *plane_state); -int drm_atomic_helper_set_config(struct drm_mode_set *set); +int drm_atomic_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_atomic_state *state); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1a525ce66468..2be2192b1373 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -347,7 +347,8 @@ struct drm_crtc_funcs { * * 0 on success or a negative error code on failure. */ - int (*set_config)(struct drm_mode_set *set); + int (*set_config)(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); /** * @page_flip: diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 7506a60df8b1..43505c7b2b3f 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -44,7 +44,8 @@ #include void drm_helper_disable_unused_functions(struct drm_device *dev); -int drm_crtc_helper_set_config(struct drm_mode_set *set); +int drm_crtc_helper_set_config(struct drm_mode_set *set, + struct drm_modeset_acquire_ctx *ctx); bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, From 38b6441e4e75c0b319cfe4d9364c1059fc1e3c2b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 22 Mar 2017 22:50:58 +0100 Subject: [PATCH 44/63] drm/atomic-helper: Remove the backoff hack from set_config Another one bites the dust. Again let's not forget to remove the temporary hidden acquire_ctx assignment, now that we pass this all around explicitly it can go away again. Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170322215058.8671-20-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 21 ++------------------- drivers/gpu/drm/drm_crtc.c | 1 - 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c137e39fc506..c4538c5dbc97 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2290,32 +2290,15 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set, return -ENOMEM; state->legacy_set_config = true; - state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); -retry: + state->acquire_ctx = ctx; ret = __drm_atomic_helper_set_config(set, state); if (ret != 0) - goto fail; + return ret; ret = drm_atomic_commit(state); -fail: - if (ret == -EDEADLK) - goto backoff; drm_atomic_state_put(state); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_atomic_legacy_backoff(state); - - /* - * Someone might have exchanged the framebuffer while we dropped locks - * in the backoff code. We need to fix up the fb refcount tracking the - * core does for us. - */ - crtc->primary->old_fb = crtc->primary->fb; - - goto retry; } EXPORT_SYMBOL(drm_atomic_helper_set_config); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b3f9f178375d..d69e180fc563 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -581,7 +581,6 @@ retry: ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); if (ret) goto out; - dev->mode_config.acquire_ctx = &ctx; if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ From 75cff0837c14eaf632efabb8d7ab9eec6394d20d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 24 Mar 2017 17:30:58 +0000 Subject: [PATCH 45/63] drm: Make the decision to keep vblank irq enabled earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to provide the vblank irq shadow for pageflip events as well as vblank queries. Such events are completed within the vblank interrupt handler, and so the current check for disabling the irq will disable it from with the same interrupt as the last pageflip event. If we move the decision on whether to disable the irq (based on there no being no remaining vblank events, i.e. vblank->refcount == 0) to before we signal the events, we will only disable the irq on the interrupt after the last event was signaled. In the normal course of events, this will keep the vblank irq enabled for the entire flip sequence whereas before it would flip-flop around every interrupt. v2: Move the disable_fn() call outside of the vblank_event_lock. Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Cc: Michel Dänzer Cc: Laurent Pinchart Cc: Dave Airlie , Cc: Mario Kleiner Reviewed-by: Ville Syrjälä #v1 Reviewed-by: Mario Kleiner #v1 Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170324173058.23051-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_irq.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 4b0c7475ed13..290e65b93a65 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1699,6 +1699,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; + bool disable_irq; if (WARN_ON_ONCE(!dev->num_crtcs)) return false; @@ -1726,20 +1727,23 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) spin_unlock(&dev->vblank_time_lock); wake_up(&vblank->queue); - drm_handle_vblank_events(dev, pipe); /* With instant-off, we defer disabling the interrupt until after - * we finish processing the following vblank. The disable has to - * be last (after drm_handle_vblank_events) so that the timestamp - * is always accurate. + * we finish processing the following vblank after all events have + * been signaled. The disable has to be last (after + * drm_handle_vblank_events) so that the timestamp is always accurate. */ - if (dev->vblank_disable_immediate && - drm_vblank_offdelay > 0 && - !atomic_read(&vblank->refcount)) - vblank_disable_fn((unsigned long)vblank); + disable_irq = (dev->vblank_disable_immediate && + drm_vblank_offdelay > 0 && + !atomic_read(&vblank->refcount)); + + drm_handle_vblank_events(dev, pipe); spin_unlock_irqrestore(&dev->event_lock, irqflags); + if (disable_irq) + vblank_disable_fn((unsigned long)vblank); + return true; } EXPORT_SYMBOL(drm_handle_vblank); From 43dc7fe2b2118c76fbc2808dec0c57b3158e6dc0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Mar 2017 20:20:27 +0000 Subject: [PATCH 46/63] drm: Mark up accesses of vblank->enabled outside of its spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Order the update to vblank->enabled after the timestamp is primed so that a concurrent unlocked reader will only see the vblank->enabled with the current timestamp. v2: vblank->enable is guarded by dev->vbl_lock not dev->vblank_time_lock, update the READ_ONCE accordingly. Do not add a READ_ONCE(vblank->enabled) inside the interrupt handler to avoid missing an interrupt whilst racing with enable_vblank() Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170317202030.24410-1-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_irq.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 290e65b93a65..372085561f02 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -325,6 +325,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; unsigned long irqflags; + assert_spin_locked(&dev->vbl_lock); + /* Prevent vblank irq processing while disabling vblank irqs, * so no updates of timestamps or count can happen after we've * disabled. Needed to prevent races in case of delayed irq's. @@ -336,10 +338,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) * calling the ->disable_vblank() operation in atomic context with the * hardware potentially runtime suspended. */ - if (vblank->enabled) { + if (cmpxchg_relaxed(&vblank->enabled, true, false)) __disable_vblank(dev, pipe); - vblank->enabled = false; - } /* * Always update the count and timestamp to maintain the @@ -384,7 +384,7 @@ void drm_vblank_cleanup(struct drm_device *dev) for (pipe = 0; pipe < dev->num_crtcs; pipe++) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - WARN_ON(vblank->enabled && + WARN_ON(READ_ONCE(vblank->enabled) && drm_core_check_feature(dev, DRIVER_MODESET)); del_timer_sync(&vblank->disable_timer); @@ -1097,11 +1097,16 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe) */ ret = __enable_vblank(dev, pipe); DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret); - if (ret) + if (ret) { atomic_dec(&vblank->refcount); - else { - vblank->enabled = true; + } else { drm_update_vblank_count(dev, pipe, 0); + /* drm_update_vblank_count() includes a wmb so we just + * need to ensure that the compiler emits the write + * to mark the vblank as enabled after the call + * to drm_update_vblank_count(). + */ + WRITE_ONCE(vblank->enabled, true); } } @@ -1509,7 +1514,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, * vblank disable, so no need for further locking. The reference from * drm_vblank_get() protects against vblank disable from another source. */ - if (!vblank->enabled) { + if (!READ_ONCE(vblank->enabled)) { ret = -EINVAL; goto err_unlock; } @@ -1636,7 +1641,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, (((drm_vblank_count(dev, pipe) - vblwait->request.sequence) <= (1 << 23)) || - !vblank->enabled || + !READ_ONCE(vblank->enabled) || !dev->irq_enabled)); } From 6c06a59703946d2f133c067629eb911bb58ff3a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Mar 2017 20:20:28 +0000 Subject: [PATCH 47/63] drm: vblank cannot be enabled if dev->irq_enabled is false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we cannot enable the vblank if !dev->irq_enabled, we assert that checking for both !vblank->enabled and !dev->irq_enabled is tautological and only need the former. The only time it may differ is when racing with drm_irq_uninstall(), but that will then disable the vblank and wakeup the waiters. Signed-off-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170317202030.24410-2-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_irq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 372085561f02..5078984568b0 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1639,10 +1639,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, DRM_DEBUG("waiting on vblank count %u, crtc %u\n", vblwait->request.sequence, pipe); DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, - (((drm_vblank_count(dev, pipe) - - vblwait->request.sequence) <= (1 << 23)) || - !READ_ONCE(vblank->enabled) || - !dev->irq_enabled)); + (drm_vblank_count(dev, pipe) - + vblwait->request.sequence) <= (1 << 23) || + !READ_ONCE(vblank->enabled)); } if (ret != -EINTR) { From 9a4d9babceeabb86669ff280e94c560193e66a72 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 22 Mar 2017 10:06:50 +0000 Subject: [PATCH 48/63] drm: Refactor vblank sequence number comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the repeated (a - b) <= (1 << 23) to its own function. v2: Catch the '1<<23' inside drm_handle_vblank() as well Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Cc: Michel Dänzer Link: http://patchwork.freedesktop.org/patch/msgid/20170322100650.26082-1-chris@chris-wilson.co.uk Reviewed-by: Michel Dänzer Reviewed-by: Ville Syrjälä Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_irq.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 5078984568b0..124402270568 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1484,6 +1484,11 @@ int drm_legacy_modeset_ctl(struct drm_device *dev, void *data, return 0; } +static inline bool vblank_passed(u32 seq, u32 ref) +{ + return (seq - ref) <= (1 << 23); +} + static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, union drm_wait_vblank *vblwait, struct drm_file *file_priv) @@ -1534,7 +1539,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, vblwait->request.sequence); e->event.sequence = vblwait->request.sequence; - if ((seq - vblwait->request.sequence) <= (1 << 23)) { + if (vblank_passed(seq, vblwait->request.sequence)) { drm_vblank_put(dev, pipe); send_vblank_event(dev, e, seq, &now); vblwait->reply.sequence = seq; @@ -1624,9 +1629,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, } if ((flags & _DRM_VBLANK_NEXTONMISS) && - (seq - vblwait->request.sequence) <= (1 << 23)) { + vblank_passed(seq, vblwait->request.sequence)) vblwait->request.sequence = seq + 1; - } if (flags & _DRM_VBLANK_EVENT) { /* must hold on to the vblank ref until the event fires @@ -1639,8 +1643,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, DRM_DEBUG("waiting on vblank count %u, crtc %u\n", vblwait->request.sequence, pipe); DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, - (drm_vblank_count(dev, pipe) - - vblwait->request.sequence) <= (1 << 23) || + vblank_passed(drm_vblank_count(dev, pipe), + vblwait->request.sequence) || !READ_ONCE(vblank->enabled)); } @@ -1675,7 +1679,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe) list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != pipe) continue; - if ((seq - e->event.sequence) > (1<<23)) + if (!vblank_passed(seq, e->event.sequence)) continue; DRM_DEBUG("vblank event on %u, current %u\n", From b33b02707ba3eeccbf8e3687ab5c4124db6d3479 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 17 Mar 2017 20:20:30 +0000 Subject: [PATCH 49/63] drm: Peek at the current counter/timestamp for vblank queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bypass all the spinlocks and return the last timestamp and counter from the last vblank if the driver delcares that it is accurate (and stable across on/off), and the vblank is currently enabled. This is dependent upon the both the hardware and driver to provide the proper barriers to facilitate reading our bookkeeping outside of the vblank interrupt and outside of the explicit vblank locks. Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Cc: Michel Dänzer Cc: Laurent Pinchart Cc: Dave Airlie , Cc: Mario Kleiner Link: http://patchwork.freedesktop.org/patch/msgid/20170317202030.24410-4-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä Signed-off-by: Ville Syrjälä --- drivers/gpu/drm/drm_irq.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 124402270568..aa23b9833588 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1561,6 +1561,17 @@ err_put: return ret; } +static bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait) +{ + if (vblwait->request.sequence) + return false; + + return _DRM_VBLANK_RELATIVE == + (vblwait->request.type & (_DRM_VBLANK_TYPES_MASK | + _DRM_VBLANK_EVENT | + _DRM_VBLANK_NEXTONMISS)); +} + /* * Wait for VBLANK. * @@ -1610,6 +1621,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblank = &dev->vblank[pipe]; + /* If the counter is currently enabled and accurate, short-circuit + * queries to return the cached timestamp of the last vblank. + */ + if (dev->vblank_disable_immediate && + drm_wait_vblank_is_query(vblwait) && + READ_ONCE(vblank->enabled)) { + struct timeval now; + + vblwait->reply.sequence = + drm_vblank_count_and_time(dev, pipe, &now); + vblwait->reply.tval_sec = now.tv_sec; + vblwait->reply.tval_usec = now.tv_usec; + return 0; + } + ret = drm_vblank_get(dev, pipe); if (ret) { DRM_DEBUG("crtc %d failed to acquire vblank counter, %d\n", pipe, ret); From 1fa4da043a5cc2a29a98c20f67d5c999819a2b6b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 29 Mar 2017 19:41:36 +0200 Subject: [PATCH 50/63] drm: Fixup failure paths in drm_atomic_helper_set_config I've screwed this up when removing the legacy backoff hack. Fixes: 38b6441e4e75 ("drm/atomic-helper: Remove the backoff hack from set_config") Cc: Harry Wentland Cc: Daniel Vetter Cc: Daniel Vetter Cc: Jani Nikula Cc: Sean Paul Cc: David Airlie Cc: dri-devel@lists.freedesktop.org Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170329174136.10330-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_atomic_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index c4538c5dbc97..c3994b4d5f32 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -2293,10 +2293,11 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set, state->acquire_ctx = ctx; ret = __drm_atomic_helper_set_config(set, state); if (ret != 0) - return ret; + goto fail; ret = drm_atomic_commit(state); +fail: drm_atomic_state_put(state); return ret; } From a2e1319d1f496888c2eaca57fbfc17180b0dae95 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 30 Mar 2017 09:36:05 +0200 Subject: [PATCH 51/63] Revert unrelated part of "drm: simplify the locking in the GETCRTC ioctl" v2 of the commit 2c77bb29d398 ("drm: simplify the locking in the GETCRTC ioctl") accidentally introduced a unrelated change in intel_display.c, revert the unrelated change. Signed-off-by: Maarten Lankhorst Fixes: 2c77bb29d398 ("drm: simplify the locking in the GETCRTC ioctl") Reported-by: Dhinakaran Pandiyan Reviewed-by: Dhinakaran Pandiyan Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/6be47261-475f-c190-af56-c136677246d9@linux.intel.com --- drivers/gpu/drm/i915/intel_display.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 78994fdc00a4..e27ea89efd67 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12468,11 +12468,6 @@ static int intel_atomic_check(struct drm_device *dev, ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; - /* enocder->atomic_check might upgrade some crtc to a full modeset */ - ret = drm_atomic_helper_check_modeset(dev, state); - if (ret) - return ret; - for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state, i) { struct intel_crtc_state *pipe_config = From bd283d2f66c28b30647c54537aff352a394c0bed Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Wed, 29 Mar 2017 14:45:23 +0100 Subject: [PATCH 52/63] drm: use .hword to represent 16-bit numbers The size of .word is the size of a word in the given platform, which for intel systems is 16-bits but other architectures use different sizes. However, .hword emits 16-bit numbers regardless of the platform (and despite the name). The quantities specified in EDID are platform independent, so they should work in spite of the default target of the cc you are using, so use .hword where EDID specifies 16-bit numbers. Cc: Carsten Emde Cc: David Airlie Acked-by: David Airlie Signed-off-by: Javi Merino Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1490795123-16851-1-git-send-email-javi.merino@kernel.org --- Documentation/EDID/edid.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/EDID/edid.S b/Documentation/EDID/edid.S index 7ac03276d7a2..ef082dcc6084 100644 --- a/Documentation/EDID/edid.S +++ b/Documentation/EDID/edid.S @@ -59,9 +59,9 @@ /* Fixed header pattern */ header: .byte 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00 -mfg_id: .word swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3)) +mfg_id: .hword swap16(mfgname2id(MFG_LNX1, MFG_LNX2, MFG_LNX3)) -prod_code: .word 0 +prod_code: .hword 0 /* Serial number. 32 bits, little endian. */ serial_number: .long SERIAL @@ -177,7 +177,7 @@ std_vres: .byte (XY_RATIO<<6)+VFREQ-60 descriptor1: /* Pixel clock in 10 kHz units. (0.-655.35 MHz, little-endian) */ -clock: .word CLOCK/10 +clock: .hword CLOCK/10 /* Horizontal active pixels 8 lsbits (0-4095) */ x_act_lsb: .byte XPIX&0xff From f56c9202b53be70fddc583e0f5f100e31ac6eb64 Mon Sep 17 00:00:00 2001 From: Christopher Spinrath Date: Mon, 6 Mar 2017 22:40:43 +0100 Subject: [PATCH 53/63] drm/bridge: ti-tfp410: support hpd via gpio On some boards the hpd pin of a hdmi connector is wired up to a gpio pin. Since in the DRM world the tfp410 driver is responsible for handling the connector, add support for hpd gpios in this very driver. Reviewed-by: Jyri Sarha Signed-off-by: Christopher Spinrath Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/2e47786ab3d04078ae70d0c4064f7c4d@rwthex-s1-b.rwth-ad.de --- drivers/gpu/drm/bridge/ti-tfp410.c | 72 +++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c index b379d046991b..7d519b46aee4 100644 --- a/drivers/gpu/drm/bridge/ti-tfp410.c +++ b/drivers/gpu/drm/bridge/ti-tfp410.c @@ -8,6 +8,10 @@ * */ +#include +#include +#include +#include #include #include #include @@ -18,11 +22,15 @@ #include #include +#define HOTPLUG_DEBOUNCE_MS 1100 + struct tfp410 { struct drm_bridge bridge; struct drm_connector connector; struct i2c_adapter *ddc; + struct gpio_desc *hpd; + struct delayed_work hpd_work; struct device *dev; }; @@ -76,6 +84,13 @@ tfp410_connector_detect(struct drm_connector *connector, bool force) { struct tfp410 *dvi = drm_connector_to_tfp410(connector); + if (dvi->hpd) { + if (gpiod_get_value_cansleep(dvi->hpd)) + return connector_status_connected; + else + return connector_status_disconnected; + } + if (dvi->ddc) { if (drm_probe_ddc(dvi->ddc)) return connector_status_connected; @@ -106,6 +121,9 @@ static int tfp410_attach(struct drm_bridge *bridge) return -ENODEV; } + if (dvi->hpd) + dvi->connector.polled = DRM_CONNECTOR_POLL_HPD; + drm_connector_helper_add(&dvi->connector, &tfp410_con_helper_funcs); ret = drm_connector_init(bridge->dev, &dvi->connector, @@ -125,7 +143,27 @@ static const struct drm_bridge_funcs tfp410_bridge_funcs = { .attach = tfp410_attach, }; -static int tfp410_get_connector_ddc(struct tfp410 *dvi) +static void tfp410_hpd_work_func(struct work_struct *work) +{ + struct tfp410 *dvi; + + dvi = container_of(work, struct tfp410, hpd_work.work); + + if (dvi->bridge.dev) + drm_helper_hpd_irq_event(dvi->bridge.dev); +} + +static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg) +{ + struct tfp410 *dvi = arg; + + mod_delayed_work(system_wq, &dvi->hpd_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); + + return IRQ_HANDLED; +} + +static int tfp410_get_connector_properties(struct tfp410 *dvi) { struct device_node *ep = NULL, *connector_node = NULL; struct device_node *ddc_phandle = NULL; @@ -140,6 +178,17 @@ static int tfp410_get_connector_ddc(struct tfp410 *dvi) if (!connector_node) goto fail; + dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode, + "hpd-gpios", 0, GPIOD_IN, "hpd"); + if (IS_ERR(dvi->hpd)) { + ret = PTR_ERR(dvi->hpd); + dvi->hpd = NULL; + if (ret == -ENOENT) + ret = 0; + else + goto fail; + } + ddc_phandle = of_parse_phandle(connector_node, "ddc-i2c-bus", 0); if (!ddc_phandle) goto fail; @@ -176,10 +225,23 @@ static int tfp410_init(struct device *dev) dvi->bridge.of_node = dev->of_node; dvi->dev = dev; - ret = tfp410_get_connector_ddc(dvi); + ret = tfp410_get_connector_properties(dvi); if (ret) goto fail; + if (dvi->hpd) { + INIT_DELAYED_WORK(&dvi->hpd_work, tfp410_hpd_work_func); + + ret = devm_request_threaded_irq(dev, gpiod_to_irq(dvi->hpd), + NULL, tfp410_hpd_irq_thread, IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "hdmi-hpd", dvi); + if (ret) { + DRM_ERROR("failed to register hpd interrupt\n"); + goto fail; + } + } + ret = drm_bridge_add(&dvi->bridge); if (ret) { dev_err(dev, "drm_bridge_add() failed: %d\n", ret); @@ -189,6 +251,8 @@ static int tfp410_init(struct device *dev) return 0; fail: i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return ret; } @@ -196,10 +260,14 @@ static int tfp410_fini(struct device *dev) { struct tfp410 *dvi = dev_get_drvdata(dev); + cancel_delayed_work_sync(&dvi->hpd_work); + drm_bridge_remove(&dvi->bridge); if (dvi->ddc) i2c_put_adapter(dvi->ddc); + if (dvi->hpd) + gpiod_put(dvi->hpd); return 0; } From f5f4c615982ddf9b898439cd039e5af6697c1c3e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 30 Mar 2017 15:08:32 +0100 Subject: [PATCH 54/63] drm: Convert cmpxchg(bool) back to a two step operation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM v6 (at least) only allows cmpxchg on 32bit variables which doesn't always include the bool type. drivers/built-in.o: In function `vblank_disable_and_save': imx-ocotp.c:(.text+0xb45e8): undefined reference to `__bad_cmpxchg' Makefile:986: recipe for target 'vmlinux' failed Reported-by: kbuild test robot Reported-by: Leonard Crestez Fixes: 43dc7fe2b211 ("drm: Mark up accesses of vblank->enabled outside of its spinlock") Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Signed-off-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20170330140832.32377-1-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_irq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index aa23b9833588..dac1b2593cb1 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -338,8 +338,10 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe) * calling the ->disable_vblank() operation in atomic context with the * hardware potentially runtime suspended. */ - if (cmpxchg_relaxed(&vblank->enabled, true, false)) + if (vblank->enabled) { __disable_vblank(dev, pipe); + vblank->enabled = false; + } /* * Always update the count and timestamp to maintain the From 031e5896dfdc24839d60f168f6e8560e294674d3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 30 Mar 2017 15:32:53 +0200 Subject: [PATCH 55/63] drm: Clear e after kfree in drm_mode_page_flip_ioctl With the explicit retry loop static analyzers get confused by the control flow and believe that e could be accessed after kfree. That's not possible, but it's non-obvious, so let's clear it to NULL. We already cleared e = NULL at the top of the function, so this is all in line. Cc: Julia Lawall Reported-by: Julia Lawall Fixes: 29dc0d1de182 ("drm: Roll out acquire context for the page_flip ioctl") Cc: Harry Wentland Cc: Daniel Vetter Cc: Jani Nikula Cc: Sean Paul Reviewed-by: Harry Wentland Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170330133253.29500-1-daniel.vetter@ffwll.ch --- drivers/gpu/drm/drm_plane.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index ec3e2e757800..5eca3184a747 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -923,6 +923,7 @@ retry: ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base); if (ret) { kfree(e); + e = NULL; goto out; } } From bcd2ba02a41d46c426fd16ad530b96527a5f181a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 20 Mar 2017 16:36:15 -0700 Subject: [PATCH 56/63] drm: Clarify the role of plane_state argument to drm_simple update(). Like the atomic update hook it's wrapping, the plane_state is the old one, and the new one is in plane->state. Both msxfb and tinydrm use it correctly, but I mistook it for the new state in pl111 due to its naming. Signed-off-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/20170320233615.5242-3-eric@anholt.net Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_simple_kms_helper.c | 4 ++-- include/drm/drm_simple_kms_helper.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 16789faa9291..e084f9f8ca66 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -114,7 +114,7 @@ static int drm_simple_kms_plane_atomic_check(struct drm_plane *plane, } static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, - struct drm_plane_state *pstate) + struct drm_plane_state *old_pstate) { struct drm_simple_display_pipe *pipe; @@ -122,7 +122,7 @@ static void drm_simple_kms_plane_atomic_update(struct drm_plane *plane, if (!pipe->funcs || !pipe->funcs->update) return; - pipe->funcs->update(pipe, pstate); + pipe->funcs->update(pipe, old_pstate); } static int drm_simple_kms_plane_prepare_fb(struct drm_plane *plane, diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index fffbb95a0915..2d36538e4a17 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h @@ -72,7 +72,7 @@ struct drm_simple_display_pipe_funcs { * the hardware lacks vblank support entirely. */ void (*update)(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state); + struct drm_plane_state *old_plane_state); /** * @prepare_fb: From 9739e7464691456dd7c297b92ef0783fe13f6ba5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 30 Mar 2017 22:48:31 +0200 Subject: [PATCH 57/63] drm: Fix locking gotcha in page_flip ioctl We want to lock the primary plane, not the cursor (which might be optional). Real bad case of copy-paste fail, unfortunately our CI didn't catch that because i915 does have a cursor plane. Reported-by: Eric Anholt Fixes: 29dc0d1de182 ("drm: Roll out acquire context for the page_flip ioctl") Cc: Jani Nikula Cc: Sean Paul Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170330204831.8225-1-daniel.vetter@ffwll.ch Tested-by: Eric Anholt Reviewed-by: Harry Wentland --- drivers/gpu/drm/drm_plane.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 5eca3184a747..bc71aa2b7872 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -872,7 +872,7 @@ retry: ret = drm_modeset_lock(&crtc->mutex, &ctx); if (ret) goto out; - ret = drm_modeset_lock(&crtc->cursor->mutex, &ctx); + ret = drm_modeset_lock(&crtc->primary->mutex, &ctx); if (ret) goto out; From 8ccd1e5162c96462ffddff2a6f7119f3ab6b2a9a Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 27 Mar 2017 18:48:24 +0200 Subject: [PATCH 58/63] MAINTAINERS: Add Lukas Wunner as reviewer for vga_switcheroo I've been contributing to vga_switcheroo for the past two years and by now am fairly familiar with it, so danvet suggested that I add myself as reviewer. While at it, add missing file pattern for vga_switcheroo.h + vgaarb.h to the DRM and DRM-MISC sections such that get_maintainer.pl returns dri-devel@ and the drm-misc maintainers. Suggested-and-acked-by: Daniel Vetter Signed-off-by: Lukas Wunner Link: http://patchwork.freedesktop.org/patch/msgid/ff2320a0790d039e714cf352cf32ec16fa370627.1490623913.git.lukas@wunner.de --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e03e6bcefac3..d0d9ed8d2459 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4146,6 +4146,7 @@ F: Documentation/devicetree/bindings/video/ F: Documentation/gpu/ F: include/drm/ F: include/uapi/drm/ +F: include/linux/vga* DRM DRIVERS AND MISC GPU PATCHES M: Daniel Vetter @@ -4159,6 +4160,7 @@ F: drivers/gpu/vga/ F: drivers/gpu/drm/* F: include/drm/drm* F: include/uapi/drm/drm* +F: include/linux/vga* DRM DRIVER FOR AST SERVER GRAPHICS CHIPS M: Dave Airlie @@ -13263,6 +13265,14 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/platform/ +VGA_SWITCHEROO +R: Lukas Wunner +S: Maintained +F: Documentation/gpu/vga-switcheroo.rst +F: drivers/gpu/vga/vga_switcheroo.c +F: include/linux/vga_switcheroo.h +T: git git://anongit.freedesktop.org/drm/drm-misc + VIDEOBUF2 FRAMEWORK M: Pawel Osciak M: Marek Szyprowski From 8531e283bee66050734fb0e89d53e85fd5ce24a4 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 10 Mar 2017 21:23:45 +0100 Subject: [PATCH 59/63] PCI: Recognize Thunderbolt devices Detect on probe whether a PCI device is part of a Thunderbolt controller. Intel uses a Vendor-Specific Extended Capability (VSEC) with ID 0x1234 on such devices. Detect presence of this VSEC and cache it in a newly added is_thunderbolt bit in struct pci_dev. Also, add a helper to check whether a given PCI device is situated on a Thunderbolt daisy chain (i.e., below a PCI device with is_thunderbolt set). The necessity arises from the following: * If an external Thunderbolt GPU is connected to a dual GPU laptop, that GPU is currently registered with vga_switcheroo even though it can neither drive the laptop's panel nor be powered off by the platform. To vga_switcheroo it will appear as if two discrete GPUs are present. As a result, when the external GPU is runtime suspended, vga_switcheroo will cut power to the internal discrete GPU which may not be runtime suspended at all at this moment. The solution is to not register external GPUs with vga_switcheroo, which necessitates a way to recognize if they're on a Thunderbolt daisy chain. * Dual GPU MacBook Pros introduced 2011+ can no longer switch external DisplayPort ports between GPUs. (They're no longer just used for DP but have become combined DP/Thunderbolt ports.) The driver to switch the ports, drivers/platform/x86/apple-gmux.c, needs to detect presence of a Thunderbolt controller and, if found, keep external ports permanently switched to the discrete GPU. v2: Make kerneldoc for pci_is_thunderbolt_attached() more precise, drop portion of commit message pertaining to separate series. (Bjorn Helgaas) Cc: Andreas Noever Cc: Michael Jamet Cc: Tomas Winkler Cc: Amir Levy Acked-by: Bjorn Helgaas Signed-off-by: Lukas Wunner Link: http://patchwork.freedesktop.org/patch/msgid/0ab165a4a35c0b60f29d4c306c653ead14fcd8f9.1489145162.git.lukas@wunner.de --- drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 21 +++++++++++++++++++++ include/linux/pci.h | 23 +++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8dd38e69d6f2..4dbf9f96ae5b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -3,6 +3,8 @@ #define PCI_FIND_CAP_TTL 48 +#define PCI_VSEC_ID_INTEL_TBT 0x1234 /* Thunderbolt */ + extern const unsigned char pcie_link_speed[]; bool pcie_cap_has_lnkctl(const struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dfc9a2794141..90592d424e9b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1208,6 +1208,24 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev) pdev->is_hotplug_bridge = 1; } +static void set_pcie_thunderbolt(struct pci_dev *dev) +{ + int vsec = 0; + u32 header; + + while ((vsec = pci_find_next_ext_capability(dev, vsec, + PCI_EXT_CAP_ID_VNDR))) { + pci_read_config_dword(dev, vsec + PCI_VNDR_HEADER, &header); + + /* Is the device part of a Thunderbolt controller? */ + if (dev->vendor == PCI_VENDOR_ID_INTEL && + PCI_VNDR_HEADER_ID(header) == PCI_VSEC_ID_INTEL_TBT) { + dev->is_thunderbolt = 1; + return; + } + } +} + /** * pci_ext_cfg_is_aliased - is ext config space just an alias of std config? * @dev: PCI device @@ -1360,6 +1378,9 @@ int pci_setup_device(struct pci_dev *dev) /* need to have dev->class ready */ dev->cfg_size = pci_cfg_space_size(dev); + /* need to have dev->cfg_size ready */ + set_pcie_thunderbolt(dev); + /* "Unknown power state" */ dev->current_state = PCI_UNKNOWN; diff --git a/include/linux/pci.h b/include/linux/pci.h index eb3da1a04e6c..5948cfdc984e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -358,6 +358,7 @@ struct pci_dev { unsigned int is_virtfn:1; unsigned int reset_fn:1; unsigned int is_hotplug_bridge:1; + unsigned int is_thunderbolt:1; /* Thunderbolt controller */ unsigned int __aer_firmware_first_valid:1; unsigned int __aer_firmware_first:1; unsigned int broken_intx_masking:1; @@ -2160,6 +2161,28 @@ static inline bool pci_ari_enabled(struct pci_bus *bus) return bus->self && bus->self->ari_enabled; } +/** + * pci_is_thunderbolt_attached - whether device is on a Thunderbolt daisy chain + * @pdev: PCI device to check + * + * Walk upwards from @pdev and check for each encountered bridge if it's part + * of a Thunderbolt controller. Reaching the host bridge means @pdev is not + * Thunderbolt-attached. (But rather soldered to the mainboard usually.) + */ +static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev; + + if (pdev->is_thunderbolt) + return true; + + while ((parent = pci_upstream_bridge(parent))) + if (parent->is_thunderbolt) + return true; + + return false; +} + /* provide the legacy pci_dma_* API */ #include From 7ffb0ce31cf90c21dfa496c19c2c795534b12e76 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 10 Mar 2017 21:23:45 +0100 Subject: [PATCH 60/63] drm/radeon: Don't register Thunderbolt eGPU with vga_switcheroo An external Thunderbolt GPU can neither drive the laptop's panel nor be powered off by the platform, so there's no point in registering it with vga_switcheroo. In fact, when the external GPU is runtime suspended, vga_switcheroo will cut power to the internal discrete GPU, resulting in a lockup. Moreover AMD's Windows driver special-cases Thunderbolt as well. Acked-by: Alex Deucher Signed-off-by: Lukas Wunner Link: http://patchwork.freedesktop.org/patch/msgid/72d8a9645aece3eff44e116303f0fec8be061c88.1489145162.git.lukas@wunner.de --- drivers/gpu/drm/radeon/radeon_device.c | 7 +++++-- drivers/gpu/drm/radeon/radeon_kms.c | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 4b0c388be3f5..27be17f0b227 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1471,7 +1471,9 @@ int radeon_device_init(struct radeon_device *rdev, if (rdev->flags & RADEON_IS_PX) runtime = true; - vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops, runtime); + if (!pci_is_thunderbolt_attached(rdev->pdev)) + vga_switcheroo_register_client(rdev->pdev, + &radeon_switcheroo_ops, runtime); if (runtime) vga_switcheroo_init_domain_pm_ops(rdev->dev, &rdev->vga_pm_domain); @@ -1564,7 +1566,8 @@ void radeon_device_fini(struct radeon_device *rdev) /* evict vram memory */ radeon_bo_evict_vram(rdev); radeon_fini(rdev); - vga_switcheroo_unregister_client(rdev->pdev); + if (!pci_is_thunderbolt_attached(rdev->pdev)) + vga_switcheroo_unregister_client(rdev->pdev); if (rdev->flags & RADEON_IS_PX) vga_switcheroo_fini_domain_pm_ops(rdev->dev); vga_client_register(rdev->pdev, NULL, NULL, NULL); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 56f35c06742c..e95ceec1c97a 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -115,7 +115,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) if ((radeon_runtime_pm != 0) && radeon_has_atpx() && - ((flags & RADEON_IS_IGP) == 0)) + ((flags & RADEON_IS_IGP) == 0) && + !pci_is_thunderbolt_attached(rdev->pdev)) flags |= RADEON_IS_PX; /* radeon_device_init should report only fatal error From 84c8b22e9fe8d9a7f2ab3d561a6b4576540f5a31 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 10 Mar 2017 21:23:45 +0100 Subject: [PATCH 61/63] drm/amdgpu: Don't register Thunderbolt eGPU with vga_switcheroo An external Thunderbolt GPU can neither drive the laptop's panel nor be powered off by the platform, so there's no point in registering it with vga_switcheroo. In fact, when the external GPU is runtime suspended, vga_switcheroo will cut power to the internal discrete GPU, resulting in a lockup. Moreover AMD's Windows driver special-cases Thunderbolt as well. Acked-by: Alex Deucher Signed-off-by: Lukas Wunner Link: http://patchwork.freedesktop.org/patch/msgid/701a8e89ce8ac39734736ab779558b6a4042a19e.1489145162.git.lukas@wunner.de --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 7 +++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index a3a105ec99e2..29965498c91f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1763,7 +1763,9 @@ int amdgpu_device_init(struct amdgpu_device *adev, runtime = true; if (amdgpu_device_is_px(ddev)) runtime = true; - vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime); + if (!pci_is_thunderbolt_attached(adev->pdev)) + vga_switcheroo_register_client(adev->pdev, + &amdgpu_switcheroo_ops, runtime); if (runtime) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); @@ -1926,7 +1928,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_atombios_fini(adev); kfree(adev->bios); adev->bios = NULL; - vga_switcheroo_unregister_client(adev->pdev); + if (!pci_is_thunderbolt_attached(adev->pdev)) + vga_switcheroo_unregister_client(adev->pdev); if (adev->flags & AMD_IS_PX) vga_switcheroo_fini_domain_pm_ops(adev->dev); vga_client_register(adev->pdev, NULL, NULL, NULL); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 61d94c745672..2f3b236721c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -103,7 +103,8 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) amdgpu_has_atpx() && (amdgpu_is_atpx_hybrid() || amdgpu_has_atpx_dgpu_power_cntl()) && - ((flags & AMD_IS_APU) == 0)) + ((flags & AMD_IS_APU) == 0) && + !pci_is_thunderbolt_attached(dev->pdev)) flags |= AMD_IS_PX; /* amdgpu_device_init should report only fatal error From 1d3c11030103680a30bbe78b599f7e009bba3bc6 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 10 Mar 2017 21:23:45 +0100 Subject: [PATCH 62/63] drm/nouveau: Don't register Thunderbolt eGPU with vga_switcheroo An external Thunderbolt GPU can neither drive the laptop's panel nor be powered off by the platform, so there's no point in registering it with vga_switcheroo. In fact, when the external GPU is runtime suspended, vga_switcheroo will cut power to the internal discrete GPU, resulting in a lockup. Cc: Ben Skeggs Acked-by: Alex Deucher Signed-off-by: Lukas Wunner Link: http://patchwork.freedesktop.org/patch/msgid/8e733152b13e7c14501ad5af45c1c5c736584111.1489145162.git.lukas@wunner.de --- drivers/gpu/drm/nouveau/nouveau_vga.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index ccb597eac538..a4aacbc0cec8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -95,6 +95,10 @@ nouveau_vga_init(struct nouveau_drm *drm) vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); + /* don't register Thunderbolt eGPU with vga_switcheroo */ + if (pci_is_thunderbolt_attached(dev->pdev)) + return; + if (nouveau_runtime_pm == 1) runtime = true; if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) @@ -111,6 +115,11 @@ nouveau_vga_fini(struct nouveau_drm *drm) struct drm_device *dev = drm->dev; bool runtime = false; + vga_client_register(dev->pdev, NULL, NULL, NULL); + + if (pci_is_thunderbolt_attached(dev->pdev)) + return; + if (nouveau_runtime_pm == 1) runtime = true; if ((nouveau_runtime_pm == -1) && (nouveau_is_optimus() || nouveau_is_v1_dsm())) @@ -119,7 +128,6 @@ nouveau_vga_fini(struct nouveau_drm *drm) vga_switcheroo_unregister_client(dev->pdev); if (runtime && nouveau_is_v1_dsm() && !nouveau_is_optimus()) vga_switcheroo_fini_domain_pm_ops(drm->dev->dev); - vga_client_register(dev->pdev, NULL, NULL, NULL); } From b121b051d14cc6e4e799e96e9c06c55989f9e073 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 10 Mar 2017 21:23:45 +0100 Subject: [PATCH 63/63] apple-gmux: Don't switch external DP port on 2011+ MacBook Pros On MacBook Pros introduced 2011 and onward, external DP ports are combined DP/Thunderbolt ports that are no longer fully switchable between GPUs, they can only be driven by the discrete GPU. More specifically, the Main Link pins (which transport the actual video and audio streams) are soldered to the discrete GPU, whereas the AUX Channel pins are switchable. Because the integrated GPU is missing the Main Link, external displays appear to it as phantoms which fail to link-train. Force the AUX channel to the discrete GPU on these models to avoid any confusion. Document the switching policy implemented by this commit. Acked-by: Andy Shevchenko Signed-off-by: Lukas Wunner Link: http://patchwork.freedesktop.org/patch/msgid/4d1fcc92d1960049e2cff997fbd2d74e45e84e49.1489145162.git.lukas@wunner.de --- drivers/platform/x86/apple-gmux.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index a66be137324c..623d322447a2 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -60,6 +60,7 @@ struct apple_gmux_data { /* switcheroo data */ acpi_handle dhandle; int gpe; + bool external_switchable; enum vga_switcheroo_client_id switch_state_display; enum vga_switcheroo_client_id switch_state_ddc; enum vga_switcheroo_client_id switch_state_external; @@ -358,6 +359,19 @@ static const struct backlight_ops gmux_bl_ops = { * ports while the discrete GPU is asleep, but currently we do not make use * of this feature. * + * Our switching policy for the external port is that on those generations + * which are able to switch it fully, the port is switched together with the + * panel when IGD / DIS commands are issued to vga_switcheroo. It is thus + * possible to drive e.g. a beamer on battery power with the integrated GPU. + * The user may manually switch to the discrete GPU if more performance is + * needed. + * + * On all newer generations, the external port can only be driven by the + * discrete GPU. If a display is plugged in while the panel is switched to + * the integrated GPU, *both* GPUs will be in use for maximum performance. + * To decrease power consumption, the user may manually switch to the + * discrete GPU, thereby suspending the integrated GPU. + * * gmux' initial switch state on bootup is user configurable via the EFI * variable ``gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9`` (5th byte, * 1 = IGD, 0 = DIS). Based on this setting, the EFI firmware tells gmux to @@ -414,7 +428,8 @@ static int gmux_switchto(enum vga_switcheroo_client_id id) { apple_gmux_data->switch_state_ddc = id; apple_gmux_data->switch_state_display = id; - apple_gmux_data->switch_state_external = id; + if (apple_gmux_data->external_switchable) + apple_gmux_data->switch_state_external = id; gmux_write_switch_state(apple_gmux_data); @@ -601,6 +616,11 @@ static struct pci_dev *gmux_get_io_pdev(void) return NULL; } +static int is_thunderbolt(struct device *dev, void *data) +{ + return to_pci_dev(dev)->is_thunderbolt; +} + static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { struct apple_gmux_data *gmux_data; @@ -755,6 +775,15 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) gmux_data->gpe = -1; } + /* + * If Thunderbolt is present, the external DP port is not fully + * switchable. Force its AUX channel to the discrete GPU. + */ + gmux_data->external_switchable = + !bus_for_each_dev(&pci_bus_type, NULL, NULL, is_thunderbolt); + if (!gmux_data->external_switchable) + gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3); + apple_gmux_data = gmux_data; init_completion(&gmux_data->powerchange_done); gmux_enable_interrupts(gmux_data);