public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
From: Dave Airlie <airlied@gmail.com>
To: dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org
Subject: [PATCH 09/11] drm/crtc: workaround userspace trying to derail crtc stealing
Date: Tue,  9 Sep 2014 16:28:14 +1000	[thread overview]
Message-ID: <1410244096-9854-10-git-send-email-airlied@gmail.com> (raw)
In-Reply-To: <1410244096-9854-1-git-send-email-airlied@gmail.com>

From: Dave Airlie <airlied@redhat.com>

This is probably not the greatest idea in the world, but if userspace
does a modesetting sequences

initial state : crtc 0 -> eDP-1
modeset : crtc 1 -> DP-4 (dual crtc)
we have to steal crtc 2 for DP-3
modeset : crtc 2 -> eDP-1

we are kind off stuck, so when we see this, we back up the crtc
configuration, proceed with the userspace modeset, then do
the second modeset on the released crtc 0.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/drm_crtc.c | 107 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 102 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 628f3af..e30518b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2509,6 +2509,91 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 }
 EXPORT_SYMBOL(drm_crtc_check_viewport);
 
+static int drm_mode_get_crtc_set(struct drm_crtc *crtc, struct drm_mode_set *backup_set)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_display_mode *mode;
+	struct drm_connector *connector;
+	int num_connectors = 0;
+	int i;
+
+	backup_set->crtc = crtc;
+	backup_set->x = crtc->x;
+	backup_set->y = crtc->y;
+	backup_set->fb = crtc->primary->fb;
+
+	mode = drm_mode_create(dev);
+	if (!mode) {
+		return -ENOMEM;
+	}
+
+	*mode = crtc->mode;
+	backup_set->mode = mode;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (!connector->encoder)
+			continue;
+		if (!connector->encoder->crtc)
+			continue;
+
+		if (connector->encoder->crtc == crtc)
+			num_connectors++;
+	}
+
+	backup_set->connectors = kmalloc(num_connectors * sizeof(struct drm_connector *), GFP_KERNEL);
+	if (!backup_set->connectors) {
+		drm_mode_destroy(dev, mode);
+		return -ENOMEM;
+	}
+
+	i = 0;
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (!connector->encoder)
+			continue;
+		if (!connector->encoder->crtc)
+			continue;
+
+		if (connector->encoder->crtc == crtc)
+			backup_set->connectors[i++] = connector;
+	}
+
+	backup_set->num_connectors = i;
+	return 0;
+}
+
+static int drm_mode_reset_tiled_crtc(struct drm_mode_set *backup_set,
+				     struct drm_crtc *tile_master)
+{
+	struct drm_crtc *crtc2, *pick_crtc = NULL;
+	struct drm_device *dev = backup_set->crtc->dev;
+	int ret;
+	/* first up we need to find another crtc to use */
+	list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) {
+		if (crtc2 == backup_set->crtc)
+			continue;
+		if (crtc2->enabled && !crtc2->tile_master)
+			continue;
+		pick_crtc = crtc2;
+		break;
+	}
+
+	if (!pick_crtc) {
+		DRM_DEBUG_KMS("unable to find backup crtc\n");
+		goto out;
+
+	}
+
+	backup_set->crtc = pick_crtc;
+
+	pick_crtc->tile_master = tile_master;
+	list_add_tail(&pick_crtc->tile, &tile_master->tile_crtc_list);
+
+	ret = drm_mode_set_config_internal(backup_set);
+out:
+	kfree(backup_set->connectors);
+	return 0;
+}
+
 /* tiled variants */
 static int drm_mode_setcrtc_tiled(struct drm_mode_set *orig_set)
 {
@@ -2631,6 +2716,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	struct drm_framebuffer *fb = NULL;
 	struct drm_display_mode *mode = NULL;
 	struct drm_mode_set set;
+	struct drm_mode_set tile_backup_set;
+	struct drm_crtc *backup_tile_master = NULL;
+	bool rework_backup = false;
 	uint32_t __user *set_connectors_ptr;
 	int ret;
 	int i;
@@ -2653,12 +2741,17 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
 
 	if (crtc->tile_master) {
-		if (crtc_req->mode_valid)
-			ret = -EBUSY;
-		else
+		if (!crtc_req->mode_valid) {
 			ret = 0;
-		DRM_DEBUG_KMS("[CRTC:%d] refused due to tile %d\n", crtc->base.id, ret);
-		goto out;
+			goto out;
+		}
+
+		drm_mode_get_crtc_set(crtc, &tile_backup_set);
+		DRM_DEBUG_KMS("[CRTC:%d] backing up tiling\n", crtc->base.id);
+		rework_backup = true;
+		backup_tile_master = crtc->tile_master;
+		crtc->tile_master = false;
+		list_del(&crtc->tile);
 	}
 
 	if (crtc_req->mode_valid) {
@@ -2791,6 +2884,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 		}
 		ret = drm_mode_set_config_internal(&set);
 	}
+
+	if (rework_backup) {
+		drm_mode_reset_tiled_crtc(&tile_backup_set, backup_tile_master);
+	}
 out:
 	if (fb)
 		drm_framebuffer_unreference(fb);
-- 
1.9.3

  parent reply	other threads:[~2014-09-09  6:28 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-09  6:28 [RFC] attempting to hide 30" monitor in kernel (raw) Dave Airlie
2014-09-09  6:28 ` [PATCH 01/11] drm/mst: rework payload table allocation to conform better Dave Airlie
2014-09-09  6:28 ` [PATCH 02/11] drm/i915: add config option to enable/disable DP MST Dave Airlie
2014-09-09  7:51   ` Jani Nikula
2014-09-09  6:28 ` [PATCH 03/11] drm/mst: start caching edid for logical ports Dave Airlie
2014-09-09  6:28 ` [PATCH 04/11] drm/displayid: add some DisplayID related defines/structs Dave Airlie
2014-09-09  6:28 ` [PATCH 05/11] drm/dp/mst: add concept of base connector id Dave Airlie
2014-09-09  6:28 ` [PATCH 06/11] drm/tile: attempt to set tiled crtcs up Dave Airlie
2014-09-09  6:28 ` [PATCH 07/11] drm/edid: allow patching the EDID to report monster mode Dave Airlie
2014-09-09  6:28 ` [PATCH 08/11] drm/crtc: attempt to set tiled modes from userspace Dave Airlie
2014-09-09  6:28 ` Dave Airlie [this message]
2014-09-09  6:28 ` [PATCH 10/11] drm/tiled: add page_flip support for multi-crtc monitors Dave Airlie
2014-09-09  6:28 ` [PATCH 11/11] drm/tiled: vague attempt at waving at cursors Dave Airlie
2014-09-09  8:54 ` [RFC] attempting to hide 30" monitor in kernel (raw) Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1410244096-9854-10-git-send-email-airlied@gmail.com \
    --to=airlied@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox