From 40478455fefdc0bde24ae872c3f88d58a1b0e435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Mar 2014 11:08:45 +0200 Subject: [PATCH 01/16] drm/i915: Allow user modes to exceed DVI 165MHz limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit commit 6375b768a9850b6154478993e5fb566fa4614a9c Author: Ville Syrjälä Date: Mon Mar 3 11:33:36 2014 +0200 drm/i915: Reject >165MHz modes w/ DVI monitors the driver started to filter out display modes which exceed the single-link DVI 165Mz dotclock limits when the monitor doesn't report itself as being HDMI compliant. The intent was to filter out all EDID derived modes that require dual-link DVI to operate since we don't support dual-link. However the patch went a bit too far and also causes the driver to reject such modes even when specified by the user. Normally we don't check the sink limitations when setting a mode from the user. This allows the user to specify any mode whether the sink reports to support it or not. This can be useful since often the sinks support more modes than they report in the EDID. So relax the checks a bit, and apply the single-link DVI dotclock limit only when filtering the mode list, and ignore the limit when setting a user specified mode. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=72961 Tested-by: Nicholas Vinson Cc: stable@vger.kernel.org [3.14] Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_hdmi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index b0413e190625..157267aa3561 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -821,11 +821,11 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) } } -static int hdmi_portclock_limit(struct intel_hdmi *hdmi) +static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) { struct drm_device *dev = intel_hdmi_to_dev(hdmi); - if (!hdmi->has_hdmi_sink || IS_G4X(dev)) + if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev)) return 165000; else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) return 300000; @@ -837,7 +837,8 @@ static enum drm_mode_status intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector))) + if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector), + true)) return MODE_CLOCK_HIGH; if (mode->clock < 20000) return MODE_CLOCK_LOW; @@ -879,7 +880,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2; - int portclock_limit = hdmi_portclock_limit(intel_hdmi); + int portclock_limit = hdmi_portclock_limit(intel_hdmi, false); int desired_bpp; if (intel_hdmi->color_range_auto) { From 9953599bc02dbc1d3330e6a0bfc6c50e9dffcac6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 13 Apr 2014 12:00:33 +0200 Subject: [PATCH 02/16] drm/i915: Don't check gmch state on inherited configs ... our current modeset code isn't good enough yet to handle this. The scenario is: 1. BIOS sets up a cloned config with lvds+external screen on the same pipe, e.g. pipe B. 2. We read out that state for pipe B and assign the gmch_pfit state to it. 3. The initial modeset switches the lvds to pipe A but due to lack of atomic modeset we don't recompute the config of pipe B. -> both pipes now claim (in the sw pipe config structure) to use the gmch_pfit, which just won't work. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=74081 Tested-by: max Cc: Alan Stern Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 23 ++++++++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 3 ++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dae976f51d83..69bcc42a0e44 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9654,11 +9654,22 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pipe_src_w); PIPE_CONF_CHECK_I(pipe_src_h); - PIPE_CONF_CHECK_I(gmch_pfit.control); - /* pfit ratios are autocomputed by the hw on gen4+ */ - if (INTEL_INFO(dev)->gen < 4) - PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); - PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); + /* + * FIXME: BIOS likes to set up a cloned config with lvds+external + * screen. Since we don't yet re-compute the pipe config when moving + * just the lvds port away to another pipe the sw tracking won't match. + * + * Proper atomic modesets with recomputed global state will fix this. + * Until then just don't check gmch state for inherited modes. + */ + if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_INHERITED_MODE)) { + PIPE_CONF_CHECK_I(gmch_pfit.control); + /* pfit ratios are autocomputed by the hw on gen4+ */ + if (INTEL_INFO(dev)->gen < 4) + PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); + PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); + } + PIPE_CONF_CHECK_I(pch_pfit.enabled); if (current_config->pch_pfit.enabled) { PIPE_CONF_CHECK_I(pch_pfit.pos); @@ -11616,6 +11627,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) base.head) { memset(&crtc->config, 0, sizeof(crtc->config)); + crtc->config.quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; + crtc->active = dev_priv->display.get_pipe_config(crtc, &crtc->config); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0542de982260..328b1a70264b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -236,7 +236,8 @@ struct intel_crtc_config { * tracked with quirk flags so that fastboot and state checker can act * accordingly. */ -#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ +#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ +#define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ unsigned long quirks; /* User requested mode, only valid as a starting point to From 636352173a0dd127636fe331c97b117a8004bf50 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 22 Apr 2014 19:55:42 -0300 Subject: [PATCH 03/16] drm/i915: get power domain in case the BIOS enabled eDP VDD If I unplug the eDP monitor, the BIOS of my machine will enable the VDD bit, then when the driver loads it will think VDD is enabled. It will detect that the eDP is not enabled and return false from intel_edp_init_connector. This will trigger a call to edp_panel_vdd_off_sync(), which trigger a WARN saying that the refcount of the power domain is less than zero. The problem happens because the driver gets a refcount whenever it enables the VDD bit, and puts the refcount whenever it disables the VDD bit. But on this case, the BIOS enabled VDD, so all we do is to call put() without calling get() first, so the code added is there to make sure we always have the get() in case the BIOS enabled the bit. This regression was introduced in commit e9cb81a22841908b1c075156b409a538d09c8466 Author: Paulo Zanoni Date: Thu Nov 21 13:47:23 2013 -0200 drm/i915: get a runtime PM reference when the panel VDD is on v2: - Rebase Tested-by: Chris Wilson (v1) Reviewed-by: Daniel Vetter Cc: stable@vger.kernel.org (v3.13+) Signed-off-by: Paulo Zanoni Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d2a55884ad52..dfa85289f28f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3619,7 +3619,8 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, { struct drm_connector *connector = &intel_connector->base; struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = intel_dig_port->base.base.dev; + struct intel_encoder *intel_encoder = &intel_dig_port->base; + struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *fixed_mode = NULL; bool has_dpcd; @@ -3629,6 +3630,14 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, if (!is_edp(intel_dp)) return true; + /* The VDD bit needs a power domain reference, so if the bit is already + * enabled when we boot, grab this reference. */ + if (edp_have_panel_vdd(intel_dp)) { + enum intel_display_power_domain power_domain; + power_domain = intel_display_port_power_domain(intel_encoder); + intel_display_power_get(dev_priv, power_domain); + } + /* Cache DPCD and EDID for edp. */ intel_edp_panel_vdd_on(intel_dp); has_dpcd = intel_dp_get_dpcd(intel_dp); From cbd75e97a525e3819c02dc18bc2d67aa544c9e45 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 15 Apr 2014 18:25:48 +0200 Subject: [PATCH 04/16] drm/vmwgfx: Make sure user-space can't DMA across buffer object boundaries v2 We already check that the buffer object we're accessing is registered with the file. Now also make sure that we can't DMA across buffer object boundaries. v2: Code commenting update. Cc: stable@vger.kernel.org Signed-off-by: Thomas Hellstrom Reviewed-by: Jakob Bornecrantz --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 931490b9cfed..87df0b3674fd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1214,14 +1214,36 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, SVGA3dCmdSurfaceDMA dma; } *cmd; int ret; + SVGA3dCmdSurfaceDMASuffix *suffix; + uint32_t bo_size; cmd = container_of(header, struct vmw_dma_cmd, header); + suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->dma + + header->size - sizeof(*suffix)); + + /* Make sure device and verifier stays in sync. */ + if (unlikely(suffix->suffixSize != sizeof(*suffix))) { + DRM_ERROR("Invalid DMA suffix size.\n"); + return -EINVAL; + } + ret = vmw_translate_guest_ptr(dev_priv, sw_context, &cmd->dma.guest.ptr, &vmw_bo); if (unlikely(ret != 0)) return ret; + /* Make sure DMA doesn't cross BO boundaries. */ + bo_size = vmw_bo->base.num_pages * PAGE_SIZE; + if (unlikely(cmd->dma.guest.ptr.offset > bo_size)) { + DRM_ERROR("Invalid DMA offset.\n"); + return -EINVAL; + } + + bo_size -= cmd->dma.guest.ptr.offset; + if (unlikely(suffix->maximumOffset > bo_size)) + suffix->maximumOffset = bo_size; + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->dma.host.sid, NULL); From edd586fe705e819bc711b5ed7194a0b6f9f1a7e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 23 Apr 2014 08:54:31 +0100 Subject: [PATCH 05/16] drm/i915: Discard BIOS framebuffers too small to accommodate chosen mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the inherited BIOS framebuffer is smaller than the mode selected for fbdev, then if we continue to use it then we cause display corruption as we do not setup the panel fitter to upscale. Regression from commit d978ef14456a38034f6c0e94a794129501f89200 Author: Jesse Barnes Date: Fri Mar 7 08:57:51 2014 -0800 drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v12 v2: Add a debug message to track the discard of the BIOS fb. v3: Ville pointed out the difference between ref/unref Reported-by: Knut Petersen Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=77767 Signed-off-by: Chris Wilson Cc: Jesse Barnes Reviewed-by: Daniel Vetter Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_fbdev.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b4d44e62f0c7..fce4a0d93c0b 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -132,6 +132,16 @@ static int intelfb_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); + if (intel_fb && + (sizes->fb_width > intel_fb->base.width || + sizes->fb_height > intel_fb->base.height)) { + DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d)," + " releasing it\n", + intel_fb->base.width, intel_fb->base.height, + sizes->fb_width, sizes->fb_height); + drm_framebuffer_unreference(&intel_fb->base); + intel_fb = ifbdev->fb = NULL; + } if (!intel_fb || WARN_ON(!intel_fb->obj)) { DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); From 0f9dc59db6abc475dc23afc077fabbc606b8830f Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 24 Mar 2014 18:06:00 -0700 Subject: [PATCH 06/16] drm/i915: Allow full PPGTT with param override When PPGTT was disabled by default, the patch also prevented the user from overriding this behavior via module parameter. Being able to test this on arbitrary kernels is extremely beneficial to track down the remaining bugs. The patch that prevented this was: commit 93a25a9e2d67765c3092bfaac9b855d95e39df97 Author: Daniel Vetter Date: Thu Mar 6 09:40:43 2014 +0100 drm/i915: Disable full ppgtt by default By default PPGTT is set to -1. 0 means off, 1 means aliasing only, 2 means full, all other values are reserved. Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ab5e93c30aa2..62a5c3627b90 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -50,7 +50,7 @@ bool intel_enable_ppgtt(struct drm_device *dev, bool full) /* Full ppgtt disabled by default for now due to issues. */ if (full) - return false; /* HAS_PPGTT(dev) */ + return HAS_PPGTT(dev) && (i915.enable_ppgtt == 2); else return HAS_ALIASING_PPGTT(dev); } From 2b4c36612efac173397756398000921a7771fdda Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 23 Apr 2014 15:15:32 +0200 Subject: [PATCH 07/16] drm/tegra: restrict plane loops to legacy planes In Matt Ropers primary plane series a set of prep patches like commit af2b653bfb4ef40931b4d101ca842ce0c5da57ef Author: Matt Roper Date: Tue Apr 1 15:22:32 2014 -0700 drm/i915: Restrict plane loops to only operate on overlay planes (v2) ensured that all exisiting users of the mode_config->plane_list wouldn't change behaviour. Unfortunately tegra seems to have fallen through the cracks. Fix it. This regression was introduced in commit e13161af80c185ecd8dc4641d0f5df58f9e3e0af Author: Matt Roper Date: Tue Apr 1 15:22:38 2014 -0700 drm: Add drm_crtc_init_with_planes() (v2) The result was that we've unref'ed the fb for the primary plane twice, leading to a use-after free bug. This is because the drm core will already set crtc->primary->fb to NULL and do the unref for us, and the crtc disable hook is called by the drm crtc helpers for exactly this case. Aside: Now that the fbdev helpers clean up planes there's no longer a need to do this in drivers. So this could probably be nuked entirely in linux-next. Signed-off-by: Daniel Vetter Reviewed-by: Matt Roper Tested-by: Stephen Warren Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 36c717af6cf9..edb871d7d395 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -312,7 +312,7 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) struct drm_device *drm = crtc->dev; struct drm_plane *plane; - list_for_each_entry(plane, &drm->mode_config.plane_list, head) { + drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) { if (plane->crtc == crtc) { tegra_plane_disable(plane); plane->crtc = NULL; From 1ffa2425bf7cc70f87d5cdbe12175fd4c661dd19 Mon Sep 17 00:00:00 2001 From: Micah Richert Date: Wed, 9 Apr 2014 14:11:31 -0700 Subject: [PATCH 08/16] drm/msm: fix memory leak Signed-off-by: Micah Richert Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 3da8264d3039..bb8026daebc9 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -118,8 +118,10 @@ static void put_pages(struct drm_gem_object *obj) if (iommu_present(&platform_bus_type)) drm_gem_put_pages(obj, msm_obj->pages, true, false); - else + else { drm_mm_remove_node(msm_obj->vram_node); + drm_free_large(msm_obj->pages); + } msm_obj->pages = NULL; } From 96673ecbd7f638c0865045377a44f53cd8606850 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 25 Apr 2014 08:50:08 -0400 Subject: [PATCH 09/16] drm/msm: default to XR24 rather than AR24 Since X11 is going to create an XR24 fb, if the pixel formats do not match then crtc helpers will think it is a full modeset even if mode is the same, which prevents smooth/flickerless handover from fbcon/plymouth to X11. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_fbdev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 6c6d7d4c9b4e..a752ab83b810 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -62,11 +62,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, dma_addr_t paddr; int ret, size; - /* only doing ARGB32 since this is what is needed to alpha-blend - * with video overlays: - */ sizes->surface_bpp = 32; - sizes->surface_depth = 32; + sizes->surface_depth = 24; DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, sizes->surface_height, sizes->surface_bpp, From 7d8d9f670513593377cd1442f987ce03a64ba55d Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 22 Apr 2014 12:27:28 -0400 Subject: [PATCH 10/16] drm/msm/mdp4: cure for the cursor blues (v2) The hw cursor is relatively adept at triggering underflows, which manifest as a "blue flash" (since blue is configured as the underflow color). Juggle a few things around to tighten up the timing for setting cursor registers in DONE irq. And most importantly, don't ever disable the hw cursor. Instead flip it to a blank/empty cursor. This seems far more reliable, as even simply clearing the cursor-enable bit (with no other updates in previous/ following frames) can in some cases cause underflow. v1: original v2: add missing locking spotted by Micah Cc: Micah Richert Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 9 +++------ drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c | 4 ++-- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 21 +++++++++++++++++++++ drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h | 4 ++++ drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c | 4 ++-- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 3e6c0f3ed592..ef9957dbac94 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -510,9 +510,8 @@ static void update_cursor(struct drm_crtc *crtc) MDP4_DMA_CURSOR_BLEND_CONFIG_CURSOR_EN); } else { /* disable cursor: */ - mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), 0); - mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BLEND_CONFIG(dma), - MDP4_DMA_CURSOR_BLEND_CONFIG_FORMAT(CURSOR_ARGB)); + mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_BASE(dma), + mdp4_kms->blank_cursor_iova); } /* and drop the iova ref + obj rev when done scanning out: */ @@ -574,11 +573,9 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, if (old_bo) { /* drop our previous reference: */ - msm_gem_put_iova(old_bo, mdp4_kms->id); - drm_gem_object_unreference_unlocked(old_bo); + drm_flip_work_queue(&mdp4_crtc->unref_cursor_work, old_bo); } - crtc_flush(crtc); request_pending(crtc, PENDING_CURSOR); return 0; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c index c740ccd1cc67..8edd531cb621 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c @@ -70,12 +70,12 @@ irqreturn_t mdp4_irq(struct msm_kms *kms) VERB("status=%08x", status); + mdp_dispatch_irqs(mdp_kms, status); + for (id = 0; id < priv->num_crtcs; id++) if (status & mdp4_crtc_vblank(priv->crtcs[id])) drm_handle_vblank(dev, id); - mdp_dispatch_irqs(mdp_kms, status); - return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 272e707c9487..0bb4faa17523 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -144,6 +144,10 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) static void mdp4_destroy(struct msm_kms *kms) { struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + if (mdp4_kms->blank_cursor_iova) + msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id); + if (mdp4_kms->blank_cursor_bo) + drm_gem_object_unreference(mdp4_kms->blank_cursor_bo); kfree(mdp4_kms); } @@ -372,6 +376,23 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) goto fail; } + mutex_lock(&dev->struct_mutex); + mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC); + mutex_unlock(&dev->struct_mutex); + if (IS_ERR(mdp4_kms->blank_cursor_bo)) { + ret = PTR_ERR(mdp4_kms->blank_cursor_bo); + dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret); + mdp4_kms->blank_cursor_bo = NULL; + goto fail; + } + + ret = msm_gem_get_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id, + &mdp4_kms->blank_cursor_iova); + if (ret) { + dev_err(dev->dev, "could not pin blank-cursor bo: %d\n", ret); + goto fail; + } + return kms; fail: diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index 66a4d31aec80..715520c54cde 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -44,6 +44,10 @@ struct mdp4_kms { struct clk *lut_clk; struct mdp_irq error_handler; + + /* empty/blank cursor bo to use when cursor is "disabled" */ + struct drm_gem_object *blank_cursor_bo; + uint32_t blank_cursor_iova; }; #define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c index 353d494a497f..f2b985bc2adf 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -71,11 +71,11 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) VERB("status=%08x", status); + mdp_dispatch_irqs(mdp_kms, status); + for (id = 0; id < priv->num_crtcs; id++) if (status & mdp5_crtc_vblank(priv->crtcs[id])) drm_handle_vblank(dev, id); - - mdp_dispatch_irqs(mdp_kms, status); } irqreturn_t mdp5_irq(struct msm_kms *kms) From 3ff04a160a891e56cdcee5c198d4c764d1c8c78b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 24 Apr 2014 12:03:17 +0200 Subject: [PATCH 11/16] drm/i915: Don't WARN nor handle unexpected hpd interrupts on gmch platforms The status bits are unconditionally set, the control bits only enable the actual interrupt generation. Which means if we get some random other interrupts we'll bogusly complain about them. So restrict the WARN to platforms with a sane hotplug interrupt handling scheme. And even more important also don't attempt to process the hpd bit since we've detected a storm already. Instead just clear the bit silently. This WARN has been introduced in commit b8f102e8bf71cacf33326360fdf9dcfd1a63925b Author: Egbert Eich Date: Fri Jul 26 14:14:24 2013 +0200 drm/i915: Add messages useful for HPD storm detection debugging (v2) before that we silently handled the hpd event and so partially defeated the storm detection. v2: Pimp commit message (Jani) Cc: Jani Nikula Cc: Egbert Eich Cc: bitlord Reported-by: bitlord Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 7753249b3a95..f98ba4e6e70b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1362,10 +1362,20 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev, spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { - WARN_ONCE(hpd[i] & hotplug_trigger && - dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED, - "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", - hotplug_trigger, i, hpd[i]); + if (hpd[i] & hotplug_trigger && + dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED) { + /* + * On GMCH platforms the interrupt mask bits only + * prevent irq generation, not the setting of the + * hotplug bits itself. So only WARN about unexpected + * interrupts on saner platforms. + */ + WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), + "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", + hotplug_trigger, i, hpd[i]); + + continue; + } if (!(hpd[i] & hotplug_trigger) || dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) From 78f2975eec9faff353a6194e854d3d39907bab68 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 2 Apr 2014 16:36:07 +0100 Subject: [PATCH 12/16] drm/i915: Move all ring resets before setting the HWS page In commit a51435a3137ad8ae75c288c39bd2d8b2696bae8f Author: Naresh Kumar Kachhi Date: Wed Mar 12 16:39:40 2014 +0530 drm/i915: disable rings before HW status page setup we reordered stopping the rings to do so before we set the HWS register. However, there is an extra workaround for g45 to reset the rings twice, and for consistency we should apply that workaround before setting the HWS to be sure that the rings are truly stopped. Reference: http://lkml.kernel.org/r/20140423202248.GA3621@amd.pavel.ucw.cz Tested-by: Pavel Machek Cc: Naresh Kumar Kachhi Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 54 ++++++++++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9f5b18d9d885..c77af69c2d8f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -827,6 +827,7 @@ enum punit_power_well { # define MI_FLUSH_ENABLE (1 << 12) # define ASYNC_FLIP_PERF_DISABLE (1 << 14) # define MODE_IDLE (1 << 9) +# define STOP_RING (1 << 8) #define GEN6_GT_MODE 0x20d0 #define GEN7_GT_MODE 0x7008 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6bc68bdcf433..79fb4cc2137c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -437,32 +437,41 @@ static void ring_setup_phys_status_page(struct intel_ring_buffer *ring) I915_WRITE(HWS_PGA, addr); } +static bool stop_ring(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = to_i915(ring->dev); + + if (!IS_GEN2(ring->dev)) { + I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING)); + if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) { + DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); + return false; + } + } + + I915_WRITE_CTL(ring, 0); + I915_WRITE_HEAD(ring, 0); + ring->write_tail(ring, 0); + + if (!IS_GEN2(ring->dev)) { + (void)I915_READ_CTL(ring); + I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING)); + } + + return (I915_READ_HEAD(ring) & HEAD_ADDR) == 0; +} + static int init_ring_common(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj = ring->obj; int ret = 0; - u32 head; gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); - /* Stop the ring if it's running. */ - I915_WRITE_CTL(ring, 0); - I915_WRITE_HEAD(ring, 0); - ring->write_tail(ring, 0); - if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) - DRM_ERROR("%s :timed out trying to stop ring\n", ring->name); - - if (I915_NEED_GFX_HWS(dev)) - intel_ring_setup_status_page(ring); - else - ring_setup_phys_status_page(ring); - - head = I915_READ_HEAD(ring) & HEAD_ADDR; - - /* G45 ring initialization fails to reset head to zero */ - if (head != 0) { + if (!stop_ring(ring)) { + /* G45 ring initialization often fails to reset head to zero */ DRM_DEBUG_KMS("%s head not reset to zero " "ctl %08x head %08x tail %08x start %08x\n", ring->name, @@ -471,9 +480,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_READ_TAIL(ring), I915_READ_START(ring)); - I915_WRITE_HEAD(ring, 0); - - if (I915_READ_HEAD(ring) & HEAD_ADDR) { + if (!stop_ring(ring)) { DRM_ERROR("failed to set %s head to zero " "ctl %08x head %08x tail %08x start %08x\n", ring->name, @@ -481,9 +488,16 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_READ_HEAD(ring), I915_READ_TAIL(ring), I915_READ_START(ring)); + ret = -EIO; + goto out; } } + if (I915_NEED_GFX_HWS(dev)) + intel_ring_setup_status_page(ring); + else + ring_setup_phys_status_page(ring); + /* Initialize the ring. This must happen _after_ we've cleared the ring * registers with the above sequence (the readback of the HEAD registers * also enforces ordering), otherwise the hw might lose the new ring diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 270a6a973438..2b91c4b4d34b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -34,6 +34,7 @@ struct intel_hw_status_page { #define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val) #define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base)) +#define I915_WRITE_MODE(ring, val) I915_WRITE(RING_MI_MODE((ring)->mmio_base), val) enum intel_ring_hangcheck_action { HANGCHECK_IDLE = 0, From 25c8b5c3048cb6c98d402ca8d4735ccf910f727c Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 15 Apr 2014 15:33:01 +0200 Subject: [PATCH 13/16] drm/exynos: balance framebuffer refcount exynos_drm_crtc_mode_set assigns primary framebuffer to plane without taking reference. Then during framebuffer removal it is dereferenced twice, causing oops. The patch fixes it. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae Signed-off-by: Dave Airlie --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index e930d4fe29c7..1ef5ab9c9d51 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -145,6 +145,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, plane->crtc = crtc; plane->fb = crtc->primary->fb; + drm_framebuffer_reference(plane->fb); return 0; } From e2a75c446e38ddf32ccdeb6e8cf2baa61fd8510f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 10 Apr 2014 20:24:03 +0900 Subject: [PATCH 14/16] MAINTAINERS: update maintainer entry for Exynos DP driver Recently, Exynos DP driver was moved from drivers/video/exynos/ directory to drivers/gpu/drm/exynos/ directory. So, I update and add maintainer entry for Exynos DP driver. Signed-off-by: Jingoo Han Signed-off-by: Inki Dae Signed-off-by: Dave Airlie --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e67ea2442041..ea44a57f790e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3485,6 +3485,12 @@ S: Maintained F: drivers/extcon/ F: Documentation/extcon/ +EXYNOS DP DRIVER +M: Jingoo Han +L: dri-devel@lists.freedesktop.org +S: Maintained +F: drivers/gpu/drm/exynos/exynos_dp* + EXYNOS MIPI DISPLAY DRIVERS M: Inki Dae M: Donghwa Lee From 293d3f6a70704691c3539bc3630ba1acbabc5c43 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 17 Apr 2014 19:08:40 +0900 Subject: [PATCH 15/16] drm/exynos: dsi: use IS_ERR() to check devm_ioremap_resource() results devm_ioremap_resource() returns an error pointer, not NULL. Thus, the result should be checked with IS_ERR(). Signed-off-by: Jingoo Han Signed-off-by: Inki Dae Signed-off-by: Dave Airlie --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index eb73e3bf2a0c..4ac438187568 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1426,9 +1426,9 @@ static int exynos_dsi_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (!dsi->reg_base) { + if (IS_ERR(dsi->reg_base)) { dev_err(&pdev->dev, "failed to remap io region\n"); - return -EADDRNOTAVAIL; + return PTR_ERR(dsi->reg_base); } dsi->phy = devm_phy_get(&pdev->dev, "dsim"); From b8eade24c9891b8f153c40cf310ef4696c873af9 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 22 Apr 2014 14:45:32 +0900 Subject: [PATCH 16/16] drm/exynos: use %pad for dma_addr_t Use %pad for dma_addr_t, because a dma_addr_t type can vary based on build options. So, it prevents possible build warnings in printks. Signed-off-by: Jingoo Han Reviewed-by: Daniel Kurtz Signed-off-by: Inki Dae Signed-off-by: Dave Airlie --- drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index c786cd4f457b..2a3ad24276f8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c @@ -263,7 +263,7 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev, buffer->sgt = sgt; exynos_gem_obj->base.import_attach = attach; - DRM_DEBUG_PRIME("dma_addr = 0x%x, size = 0x%lx\n", buffer->dma_addr, + DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr, buffer->size); return &exynos_gem_obj->base; diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 7afead9c3f30..852f2dadaebd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -220,7 +220,7 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) win_data->enabled = true; - DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr); + DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr); if (ctx->vblank_on) schedule_work(&ctx->work);