All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client
@ 2019-04-07 16:52 Noralf Trønnes
  2019-04-07 16:52 ` [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
                   ` (16 more replies)
  0 siblings, 17 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, Noralf Trønnes, Emmanuel Vadot

This moves the modesetting code from drm_fb_helper to drm_client so it
can be shared by all internal clients.

The main change this time is to attach the modeset array to
drm_client_dev and honour the drm_fb_helper MIT license. I've dropped
the display abstraction.

Noralf.

Cc: Emmanuel Vadot <manu@bidouilliste.com>

Noralf Trønnes (12):
  drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  drm/fb-helper: Avoid race with DRM userspace
  drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  drm/fb-helper: No need to cache rotation and sw_rotations
  drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
  drm/fb-helper: Remove drm_fb_helper_crtc
  drm/fb-helper: Prepare to move out commit code
  drm/fb-helper: Move out commit code
  drm/fb-helper: Remove drm_fb_helper_connector
  drm/fb-helper: Prepare to move out modeset config code
  drm/fb-helper: Move out modeset config code
  drm/client: Hack: Add bootsplash example

 Documentation/gpu/todo.rst           |   10 +
 drivers/gpu/drm/Kconfig              |    5 +
 drivers/gpu/drm/Makefile             |    3 +-
 drivers/gpu/drm/drm_atomic.c         |  168 ++++
 drivers/gpu/drm/drm_atomic_helper.c  |  164 ----
 drivers/gpu/drm/drm_auth.c           |   20 +
 drivers/gpu/drm/drm_bootsplash.c     |  359 ++++++++
 drivers/gpu/drm/drm_client.c         |   17 +-
 drivers/gpu/drm/drm_client_modeset.c | 1086 +++++++++++++++++++++++
 drivers/gpu/drm/drm_crtc_internal.h  |    5 +
 drivers/gpu/drm/drm_drv.c            |    4 +
 drivers/gpu/drm/drm_fb_helper.c      | 1195 +++-----------------------
 drivers/gpu/drm/drm_internal.h       |    2 +
 drivers/gpu/drm/i915/intel_fbdev.c   |  218 -----
 include/drm/drm_atomic_helper.h      |    4 -
 include/drm/drm_client.h             |   48 ++
 include/drm/drm_fb_helper.h          |  125 +--
 17 files changed, 1859 insertions(+), 1574 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_bootsplash.c
 create mode 100644 drivers/gpu/drm/drm_client_modeset.c

-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  9:12   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, Noralf Trønnes

Prepare for moving drm_fb_helper modesetting code to drm_client.
drm_client will be linked to drm.ko, so move
__drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
out of drm_kms_helper.ko.

While at it, fix two checkpatch complaints:
- WARNING: Block comments use a trailing */ on a separate line
- CHECK: Alignment should match open parenthesis

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c | 164 ---------------------------
 drivers/gpu/drm/drm_crtc_internal.h |   5 +
 include/drm/drm_atomic_helper.h     |   4 -
 4 files changed, 173 insertions(+), 168 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5eb40130fafb..c3a9ffbf2310 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1130,6 +1130,174 @@ int drm_atomic_nonblocking_commit(struct drm_atomic_state *state)
 }
 EXPORT_SYMBOL(drm_atomic_nonblocking_commit);
 
+/* just used from drm-client and atomic-helper: */
+int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
+				      struct drm_plane_state *plane_state)
+{
+	int ret;
+
+	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
+	if (ret != 0)
+		return ret;
+
+	drm_atomic_set_fb_for_plane(plane_state, NULL);
+	plane_state->crtc_x = 0;
+	plane_state->crtc_y = 0;
+	plane_state->crtc_w = 0;
+	plane_state->crtc_h = 0;
+	plane_state->src_x = 0;
+	plane_state->src_y = 0;
+	plane_state->src_w = 0;
+	plane_state->src_h = 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_disable_plane);
+
+static int update_output_state(struct drm_atomic_state *state,
+			       struct drm_mode_set *set)
+{
+	struct drm_device *dev = set->crtc->dev;
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *new_crtc_state;
+	struct drm_connector *connector;
+	struct drm_connector_state *new_conn_state;
+	int ret, i;
+
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
+			       state->acquire_ctx);
+	if (ret)
+		return ret;
+
+	/* First disable all connectors on the target crtc. */
+	ret = drm_atomic_add_affected_connectors(state, set->crtc);
+	if (ret)
+		return ret;
+
+	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
+		if (new_conn_state->crtc == set->crtc) {
+			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
+								NULL);
+			if (ret)
+				return ret;
+
+			/* Make sure legacy setCrtc always re-trains */
+			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
+		}
+	}
+
+	/* Then set all connectors from set->connectors on the target crtc */
+	for (i = 0; i < set->num_connectors; i++) {
+		new_conn_state = drm_atomic_get_connector_state(state,
+								set->connectors[i]);
+		if (IS_ERR(new_conn_state))
+			return PTR_ERR(new_conn_state);
+
+		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
+							set->crtc);
+		if (ret)
+			return ret;
+	}
+
+	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+		/*
+		 * Don't update ->enable for the CRTC in the set_config request,
+		 * since a mismatch would indicate a bug in the upper layers.
+		 * The actual modeset code later on will catch any
+		 * inconsistencies here.
+		 */
+		if (crtc == set->crtc)
+			continue;
+
+		if (!new_crtc_state->connector_mask) {
+			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
+								NULL);
+			if (ret < 0)
+				return ret;
+
+			new_crtc_state->active = false;
+		}
+	}
+
+	return 0;
+}
+
+/* just used from drm-client and atomic-helper: */
+int __drm_atomic_helper_set_config(struct drm_mode_set *set,
+				   struct drm_atomic_state *state)
+{
+	struct drm_crtc_state *crtc_state;
+	struct drm_plane_state *primary_state;
+	struct drm_crtc *crtc = set->crtc;
+	int hdisplay, vdisplay;
+	int ret;
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
+	if (IS_ERR(primary_state))
+		return PTR_ERR(primary_state);
+
+	if (!set->mode) {
+		WARN_ON(set->fb);
+		WARN_ON(set->num_connectors);
+
+		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
+		if (ret != 0)
+			return ret;
+
+		crtc_state->active = false;
+
+		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
+		if (ret != 0)
+			return ret;
+
+		drm_atomic_set_fb_for_plane(primary_state, NULL);
+
+		goto commit;
+	}
+
+	WARN_ON(!set->fb);
+	WARN_ON(!set->num_connectors);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
+	if (ret != 0)
+		return ret;
+
+	crtc_state->active = true;
+
+	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
+	if (ret != 0)
+		return ret;
+
+	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+
+	drm_atomic_set_fb_for_plane(primary_state, set->fb);
+	primary_state->crtc_x = 0;
+	primary_state->crtc_y = 0;
+	primary_state->crtc_w = hdisplay;
+	primary_state->crtc_h = vdisplay;
+	primary_state->src_x = set->x << 16;
+	primary_state->src_y = set->y << 16;
+	if (drm_rotation_90_or_270(primary_state->rotation)) {
+		primary_state->src_w = vdisplay << 16;
+		primary_state->src_h = hdisplay << 16;
+	} else {
+		primary_state->src_w = hdisplay << 16;
+		primary_state->src_h = vdisplay << 16;
+	}
+
+commit:
+	ret = update_output_state(state, set);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL(__drm_atomic_helper_set_config);
+
 void drm_atomic_print_state(const struct drm_atomic_state *state)
 {
 	struct drm_printer p = drm_info_printer(state->dev->dev);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 16d74b8a09fe..db19c94ab5fa 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2831,95 +2831,6 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
 }
 EXPORT_SYMBOL(drm_atomic_helper_disable_plane);
 
-/* just used from fb-helper and atomic-helper: */
-int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
-		struct drm_plane_state *plane_state)
-{
-	int ret;
-
-	ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
-	if (ret != 0)
-		return ret;
-
-	drm_atomic_set_fb_for_plane(plane_state, NULL);
-	plane_state->crtc_x = 0;
-	plane_state->crtc_y = 0;
-	plane_state->crtc_w = 0;
-	plane_state->crtc_h = 0;
-	plane_state->src_x = 0;
-	plane_state->src_y = 0;
-	plane_state->src_w = 0;
-	plane_state->src_h = 0;
-
-	return 0;
-}
-
-static int update_output_state(struct drm_atomic_state *state,
-			       struct drm_mode_set *set)
-{
-	struct drm_device *dev = set->crtc->dev;
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *new_crtc_state;
-	struct drm_connector *connector;
-	struct drm_connector_state *new_conn_state;
-	int ret, i;
-
-	ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
-			       state->acquire_ctx);
-	if (ret)
-		return ret;
-
-	/* First disable all connectors on the target crtc. */
-	ret = drm_atomic_add_affected_connectors(state, set->crtc);
-	if (ret)
-		return ret;
-
-	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
-		if (new_conn_state->crtc == set->crtc) {
-			ret = drm_atomic_set_crtc_for_connector(new_conn_state,
-								NULL);
-			if (ret)
-				return ret;
-
-			/* Make sure legacy setCrtc always re-trains */
-			new_conn_state->link_status = DRM_LINK_STATUS_GOOD;
-		}
-	}
-
-	/* Then set all connectors from set->connectors on the target crtc */
-	for (i = 0; i < set->num_connectors; i++) {
-		new_conn_state = drm_atomic_get_connector_state(state,
-							    set->connectors[i]);
-		if (IS_ERR(new_conn_state))
-			return PTR_ERR(new_conn_state);
-
-		ret = drm_atomic_set_crtc_for_connector(new_conn_state,
-							set->crtc);
-		if (ret)
-			return ret;
-	}
-
-	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
-		/* Don't update ->enable for the CRTC in the set_config request,
-		 * since a mismatch would indicate a bug in the upper layers.
-		 * The actual modeset code later on will catch any
-		 * inconsistencies here. */
-		if (crtc == set->crtc)
-			continue;
-
-		if (!new_crtc_state->connector_mask) {
-			ret = drm_atomic_set_mode_prop_for_crtc(new_crtc_state,
-								NULL);
-			if (ret < 0)
-				return ret;
-
-			new_crtc_state->active = false;
-		}
-	}
-
-	return 0;
-}
-
 /**
  * drm_atomic_helper_set_config - set a new config from userspace
  * @set: mode set configuration
@@ -2964,81 +2875,6 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
 }
 EXPORT_SYMBOL(drm_atomic_helper_set_config);
 
-/* just used from fb-helper and atomic-helper: */
-int __drm_atomic_helper_set_config(struct drm_mode_set *set,
-		struct drm_atomic_state *state)
-{
-	struct drm_crtc_state *crtc_state;
-	struct drm_plane_state *primary_state;
-	struct drm_crtc *crtc = set->crtc;
-	int hdisplay, vdisplay;
-	int ret;
-
-	crtc_state = drm_atomic_get_crtc_state(state, crtc);
-	if (IS_ERR(crtc_state))
-		return PTR_ERR(crtc_state);
-
-	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
-	if (IS_ERR(primary_state))
-		return PTR_ERR(primary_state);
-
-	if (!set->mode) {
-		WARN_ON(set->fb);
-		WARN_ON(set->num_connectors);
-
-		ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
-		if (ret != 0)
-			return ret;
-
-		crtc_state->active = false;
-
-		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
-		if (ret != 0)
-			return ret;
-
-		drm_atomic_set_fb_for_plane(primary_state, NULL);
-
-		goto commit;
-	}
-
-	WARN_ON(!set->fb);
-	WARN_ON(!set->num_connectors);
-
-	ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
-	if (ret != 0)
-		return ret;
-
-	crtc_state->active = true;
-
-	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
-	if (ret != 0)
-		return ret;
-
-	drm_mode_get_hv_timing(set->mode, &hdisplay, &vdisplay);
-
-	drm_atomic_set_fb_for_plane(primary_state, set->fb);
-	primary_state->crtc_x = 0;
-	primary_state->crtc_y = 0;
-	primary_state->crtc_w = hdisplay;
-	primary_state->crtc_h = vdisplay;
-	primary_state->src_x = set->x << 16;
-	primary_state->src_y = set->y << 16;
-	if (drm_rotation_90_or_270(primary_state->rotation)) {
-		primary_state->src_w = vdisplay << 16;
-		primary_state->src_h = hdisplay << 16;
-	} else {
-		primary_state->src_w = hdisplay << 16;
-		primary_state->src_h = vdisplay << 16;
-	}
-
-commit:
-	ret = update_output_state(state, set);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
 /**
  * drm_atomic_helper_disable_all - disable all currently active outputs
  * @dev: DRM device
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 216f2a9ee3d4..22a63a544ec7 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -207,6 +207,11 @@ struct drm_minor;
 int drm_atomic_debugfs_init(struct drm_minor *minor);
 #endif
 
+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,
+				   struct drm_atomic_state *state);
+
 void drm_atomic_print_state(const struct drm_atomic_state *state);
 
 /* drm_atomic_uapi.c */
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 58214be3bf3d..bf4e07141d81 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -117,12 +117,8 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
 				   struct drm_modeset_acquire_ctx *ctx);
 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,
 				 struct drm_modeset_acquire_ctx *ctx);
-int __drm_atomic_helper_set_config(struct drm_mode_set *set,
-		struct drm_atomic_state *state);
 
 int drm_atomic_helper_disable_all(struct drm_device *dev,
 				  struct drm_modeset_acquire_ctx *ctx);
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
  2019-04-07 16:52 ` [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  7:59   ` Daniel Vetter
  2019-04-16  9:26   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
                   ` (14 subsequent siblings)
  16 siblings, 2 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, Noralf Trønnes

drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
This is done by looking at the fb on the primary plane. By the time
fb-helper gets around to committing, it's possible that the facts have
changed.

Avoid this race by holding the drm_device->master_mutex lock while
committing. When DRM userspace does its first open, it will now wait
until fb-helper is done. The helper will stay away if there's a master.

Locking rule: Always take the fb-helper lock first.

v2:
- Remove drm_fb_helper_is_bound() (Daniel Vetter)
- No need to check fb_helper->dev->master in
  drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_auth.c      | 20 ++++++++
 drivers/gpu/drm/drm_fb_helper.c | 90 ++++++++++++++++-----------------
 drivers/gpu/drm/drm_internal.h  |  2 +
 3 files changed, 67 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 1669c42c40ed..db199807b7dc 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
 	*master = NULL;
 }
 EXPORT_SYMBOL(drm_master_put);
+
+/* Used by drm_client and drm_fb_helper */
+bool drm_master_internal_acquire(struct drm_device *dev)
+{
+	mutex_lock(&dev->master_mutex);
+	if (dev->master) {
+		mutex_unlock(&dev->master_mutex);
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL(drm_master_internal_acquire);
+
+/* Used by drm_client and drm_fb_helper */
+void drm_master_internal_release(struct drm_device *dev)
+{
+	mutex_unlock(&dev->master_mutex);
+}
+EXPORT_SYMBOL(drm_master_internal_release);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 84791dd4a90d..a6be09ae899b 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -44,6 +44,7 @@
 
 #include "drm_crtc_internal.h"
 #include "drm_crtc_helper_internal.h"
+#include "drm_internal.h"
 
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
@@ -509,7 +510,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 	return ret;
 }
 
-static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
 {
 	struct drm_device *dev = fb_helper->dev;
 
@@ -519,6 +520,21 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 		return restore_fbdev_mode_legacy(fb_helper);
 }
 
+static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+{
+	struct drm_device *dev = fb_helper->dev;
+	int ret;
+
+	if (!drm_master_internal_acquire(dev))
+		return -EBUSY;
+
+	ret = restore_fbdev_mode_force(fb_helper);
+
+	drm_master_internal_release(dev);
+
+	return ret;
+}
+
 /**
  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
  * @fb_helper: driver-allocated fbdev helper, can be NULL
@@ -556,34 +572,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
 
-static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
-{
-	struct drm_device *dev = fb_helper->dev;
-	struct drm_crtc *crtc;
-	int bound = 0, crtcs_bound = 0;
-
-	/*
-	 * Sometimes user space wants everything disabled, so don't steal the
-	 * display if there's a master.
-	 */
-	if (READ_ONCE(dev->master))
-		return false;
-
-	drm_for_each_crtc(crtc, dev) {
-		drm_modeset_lock(&crtc->mutex, NULL);
-		if (crtc->primary->fb)
-			crtcs_bound++;
-		if (crtc->primary->fb == fb_helper->fb)
-			bound++;
-		drm_modeset_unlock(&crtc->mutex);
-	}
-
-	if (bound < crtcs_bound)
-		return false;
-
-	return true;
-}
-
 #ifdef CONFIG_MAGIC_SYSRQ
 /*
  * restore fbcon display for all kms driver's using this helper, used for sysrq
@@ -604,7 +592,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
 			continue;
 
 		mutex_lock(&helper->lock);
-		ret = restore_fbdev_mode(helper);
+		ret = restore_fbdev_mode_force(helper);
 		if (ret)
 			error = true;
 		mutex_unlock(&helper->lock);
@@ -663,20 +651,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
 
 	/*
 	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
 	mutex_lock(&fb_helper->lock);
-	if (!drm_fb_helper_is_bound(fb_helper)) {
-		mutex_unlock(&fb_helper->lock);
-		return;
-	}
+	if (!drm_master_internal_acquire(dev))
+		goto unlock;
 
-	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
+	if (drm_drv_uses_atomic_modeset(dev))
 		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
 	else
 		dpms_legacy(fb_helper, dpms_mode);
+
+	drm_master_internal_release(dev);
+unlock:
 	mutex_unlock(&fb_helper->lock);
 }
 
@@ -1509,6 +1499,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
 	int ret;
 
 	if (oops_in_progress)
@@ -1516,9 +1507,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 
 	mutex_lock(&fb_helper->lock);
 
-	if (!drm_fb_helper_is_bound(fb_helper)) {
+	if (!drm_master_internal_acquire(dev)) {
 		ret = -EBUSY;
-		goto out;
+		goto unlock;
 	}
 
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
@@ -1528,7 +1519,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 	else
 		ret = setcmap_legacy(cmap, info);
 
-out:
+	drm_master_internal_release(dev);
+unlock:
 	mutex_unlock(&fb_helper->lock);
 
 	return ret;
@@ -1548,12 +1540,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 			unsigned long arg)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
 	struct drm_mode_set *mode_set;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
 	mutex_lock(&fb_helper->lock);
-	if (!drm_fb_helper_is_bound(fb_helper)) {
+	if (!drm_master_internal_acquire(dev)) {
 		ret = -EBUSY;
 		goto unlock;
 	}
@@ -1591,11 +1584,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 		}
 
 		ret = 0;
-		goto unlock;
+		break;
 	default:
 		ret = -ENOTTY;
 	}
 
+	drm_master_internal_release(dev);
 unlock:
 	mutex_unlock(&fb_helper->lock);
 	return ret;
@@ -1847,15 +1841,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 		return -EBUSY;
 
 	mutex_lock(&fb_helper->lock);
-	if (!drm_fb_helper_is_bound(fb_helper)) {
-		mutex_unlock(&fb_helper->lock);
-		return -EBUSY;
+	if (!drm_master_internal_acquire(dev)) {
+		ret = -EBUSY;
+		goto unlock;
 	}
 
 	if (drm_drv_uses_atomic_modeset(dev))
 		ret = pan_display_atomic(var, info);
 	else
 		ret = pan_display_legacy(var, info);
+
+	drm_master_internal_release(dev);
+unlock:
 	mutex_unlock(&fb_helper->lock);
 
 	return ret;
@@ -2014,7 +2011,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		DRM_INFO("Cannot find any crtc or sizes\n");
 
 		/* First time: disable all crtc's.. */
-		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
+		if (!fb_helper->deferred_setup)
 			restore_fbdev_mode(fb_helper);
 		return -EAGAIN;
 	}
@@ -2842,6 +2839,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
  */
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
+	struct drm_device *dev = fb_helper->dev;
 	int err = 0;
 
 	if (!drm_fbdev_emulation || !fb_helper)
@@ -2854,12 +2852,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 		return err;
 	}
 
-	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
+	if (!fb_helper->fb || !drm_master_internal_acquire(dev)) {
 		fb_helper->delayed_hotplug = true;
 		mutex_unlock(&fb_helper->lock);
 		return err;
 	}
 
+	drm_master_internal_release(dev);
+
 	DRM_DEBUG_KMS("\n");
 
 	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index d9a483a5fce0..3ee97c9998a2 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
 int drm_master_open(struct drm_file *file_priv);
 void drm_master_release(struct drm_file *file_priv);
+bool drm_master_internal_acquire(struct drm_device *dev);
+void drm_master_internal_release(struct drm_device *dev);
 
 /* drm_sysfs.c */
 extern struct class *drm_class;
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
  2019-04-07 16:52 ` [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
  2019-04-07 16:52 ` [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-11 14:25   ` Noralf Trønnes
  2019-04-23 14:17   ` Thomas Zimmermann
  2019-04-07 16:52 ` [PATCH v2 04/12] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
                   ` (13 subsequent siblings)
  16 siblings, 2 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: Jani Nikula, daniel.vetter, intel-gfx, Noralf Trønnes

It is generic code and having it in the helper will let other drivers
benefit from it.

One change was necessary assuming this to be true:
INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: intel-gfx@lists.freedesktop.org
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
 include/drm/drm_fb_helper.h        |  23 ---
 3 files changed, 190 insertions(+), 245 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index a6be09ae899b..eda8b63f350d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2556,6 +2556,194 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
 	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
 }
 
+static struct drm_fb_helper_crtc *
+drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
+{
+	int i;
+
+	for (i = 0; i < fb_helper->crtc_count; i++)
+		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
+			return &fb_helper->crtc_info[i];
+
+	return NULL;
+}
+
+/* Try to read the BIOS display configuration and use it for the initial config */
+static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
+					  struct drm_fb_helper_crtc **crtcs,
+					  struct drm_display_mode **modes,
+					  struct drm_fb_offset *offsets,
+					  bool *enabled, int width, int height)
+{
+	struct drm_device *dev = fb_helper->dev;
+	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
+	unsigned long conn_configured, conn_seq;
+	int i, j;
+	bool *save_enabled;
+	bool fallback = true, ret = true;
+	int num_connectors_enabled = 0;
+	int num_connectors_detected = 0;
+	struct drm_modeset_acquire_ctx ctx;
+
+	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
+	if (!save_enabled)
+		return false;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
+		drm_modeset_backoff(&ctx);
+
+	memcpy(save_enabled, enabled, count);
+	conn_seq = GENMASK(count - 1, 0);
+	conn_configured = 0;
+retry:
+	for (i = 0; i < count; i++) {
+		struct drm_fb_helper_connector *fb_conn;
+		struct drm_connector *connector;
+		struct drm_encoder *encoder;
+		struct drm_fb_helper_crtc *new_crtc;
+
+		fb_conn = fb_helper->connector_info[i];
+		connector = fb_conn->connector;
+
+		if (conn_configured & BIT(i))
+			continue;
+
+		/* First pass, only consider tiled connectors */
+		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
+			continue;
+
+		if (connector->status == connector_status_connected)
+			num_connectors_detected++;
+
+		if (!enabled[i]) {
+			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
+				      connector->name);
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		if (connector->force == DRM_FORCE_OFF) {
+			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			continue;
+		}
+
+		encoder = connector->state->best_encoder;
+		if (!encoder || WARN_ON(!connector->state->crtc)) {
+			if (connector->force > DRM_FORCE_OFF)
+				goto bail;
+
+			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		num_connectors_enabled++;
+
+		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
+
+		/*
+		 * Make sure we're not trying to drive multiple connectors
+		 * with a single CRTC, since our cloning support may not
+		 * match the BIOS.
+		 */
+		for (j = 0; j < count; j++) {
+			if (crtcs[j] == new_crtc) {
+				DRM_DEBUG_KMS("fallback: cloned configuration\n");
+				goto bail;
+			}
+		}
+
+		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
+			      connector->name);
+
+		/* go for command line mode first */
+		modes[i] = drm_pick_cmdline_mode(fb_conn);
+
+		/* try for preferred next */
+		if (!modes[i]) {
+			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
+				      connector->name, connector->has_tile);
+			modes[i] = drm_has_preferred_mode(fb_conn, width,
+							  height);
+		}
+
+		/* No preferred mode marked by the EDID? Are there any modes? */
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
+				      connector->name);
+			modes[i] = list_first_entry(&connector->modes,
+						    struct drm_display_mode,
+						    head);
+		}
+
+		/* last resort: use current mode */
+		if (!modes[i]) {
+			/*
+			 * IMPORTANT: We want to use the adjusted mode (i.e.
+			 * after the panel fitter upscaling) as the initial
+			 * config, not the input mode, which is what crtc->mode
+			 * usually contains. But since our current
+			 * code puts a mode derived from the post-pfit timings
+			 * into crtc->mode this works out correctly.
+			 *
+			 * This is crtc->mode and not crtc->state->mode for the
+			 * fastboot check to work correctly.
+			 */
+			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
+				      connector->name);
+			modes[i] = &connector->state->crtc->mode;
+		}
+		crtcs[i] = new_crtc;
+
+		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
+			      connector->name,
+			      connector->state->crtc->base.id,
+			      connector->state->crtc->name,
+			      modes[i]->hdisplay, modes[i]->vdisplay,
+			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
+
+		fallback = false;
+		conn_configured |= BIT(i);
+	}
+
+	if (conn_configured != conn_seq) { /* repeat until no more are found */
+		conn_seq = conn_configured;
+		goto retry;
+	}
+
+	/*
+	 * If the BIOS didn't enable everything it could, fall back to have the
+	 * same user experiencing of lighting up as much as possible like the
+	 * fbdev helper library.
+	 */
+	if (num_connectors_enabled != num_connectors_detected &&
+	    num_connectors_enabled < dev->mode_config.num_crtc) {
+		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
+		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
+			      num_connectors_detected);
+		fallback = true;
+	}
+
+	if (fallback) {
+bail:
+		DRM_DEBUG_KMS("Not using firmware configuration\n");
+		memcpy(enabled, save_enabled, count);
+		ret = false;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	kfree(save_enabled);
+	return ret;
+}
+
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
@@ -2588,10 +2776,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
 	drm_enable_connectors(fb_helper, enabled);
 
-	if (!(fb_helper->funcs->initial_config &&
-	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
-					       offsets,
-					       enabled, width, height))) {
+	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
+					   enabled, width, height)) {
 		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
 		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
 		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index ef93c27e60b4..c4d17dda3355 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -284,225 +284,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 	return ret;
 }
 
-static struct drm_fb_helper_crtc *
-intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
-{
-	int i;
-
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
-			return &fb_helper->crtc_info[i];
-
-	return NULL;
-}
-
-/*
- * Try to read the BIOS display configuration and use it for the initial
- * fb configuration.
- *
- * The BIOS or boot loader will generally create an initial display
- * configuration for us that includes some set of active pipes and displays.
- * This routine tries to figure out which pipes and connectors are active
- * and stuffs them into the crtcs and modes array given to us by the
- * drm_fb_helper code.
- *
- * The overall sequence is:
- *   intel_fbdev_init - from driver load
- *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
- *     drm_fb_helper_init - build fb helper structs
- *     drm_fb_helper_single_add_all_connectors - more fb helper structs
- *   intel_fbdev_initial_config - apply the config
- *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
- *         drm_setup_crtcs - build crtc config for fbdev
- *           intel_fb_initial_config - find active connectors etc
- *         drm_fb_helper_single_fb_probe - set up fbdev
- *           intelfb_create - re-use or alloc fb, build out fbdev structs
- *
- * Note that we don't make special consideration whether we could actually
- * switch to the selected modes without a full modeset. E.g. when the display
- * is in VGA mode we need to recalculate watermarks and set a new high-res
- * framebuffer anyway.
- */
-static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
-				    struct drm_fb_helper_crtc **crtcs,
-				    struct drm_display_mode **modes,
-				    struct drm_fb_offset *offsets,
-				    bool *enabled, int width, int height)
-{
-	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
-	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
-	unsigned long conn_configured, conn_seq;
-	int i, j;
-	bool *save_enabled;
-	bool fallback = true, ret = true;
-	int num_connectors_enabled = 0;
-	int num_connectors_detected = 0;
-	struct drm_modeset_acquire_ctx ctx;
-
-	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
-	if (!save_enabled)
-		return false;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
-		drm_modeset_backoff(&ctx);
-
-	memcpy(save_enabled, enabled, count);
-	conn_seq = GENMASK(count - 1, 0);
-	conn_configured = 0;
-retry:
-	for (i = 0; i < count; i++) {
-		struct drm_fb_helper_connector *fb_conn;
-		struct drm_connector *connector;
-		struct drm_encoder *encoder;
-		struct drm_fb_helper_crtc *new_crtc;
-
-		fb_conn = fb_helper->connector_info[i];
-		connector = fb_conn->connector;
-
-		if (conn_configured & BIT(i))
-			continue;
-
-		/* First pass, only consider tiled connectors */
-		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
-			continue;
-
-		if (connector->status == connector_status_connected)
-			num_connectors_detected++;
-
-		if (!enabled[i]) {
-			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
-				      connector->name);
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		if (connector->force == DRM_FORCE_OFF) {
-			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			continue;
-		}
-
-		encoder = connector->state->best_encoder;
-		if (!encoder || WARN_ON(!connector->state->crtc)) {
-			if (connector->force > DRM_FORCE_OFF)
-				goto bail;
-
-			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		num_connectors_enabled++;
-
-		new_crtc = intel_fb_helper_crtc(fb_helper,
-						connector->state->crtc);
-
-		/*
-		 * Make sure we're not trying to drive multiple connectors
-		 * with a single CRTC, since our cloning support may not
-		 * match the BIOS.
-		 */
-		for (j = 0; j < count; j++) {
-			if (crtcs[j] == new_crtc) {
-				DRM_DEBUG_KMS("fallback: cloned configuration\n");
-				goto bail;
-			}
-		}
-
-		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
-			      connector->name);
-
-		/* go for command line mode first */
-		modes[i] = drm_pick_cmdline_mode(fb_conn);
-
-		/* try for preferred next */
-		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
-				      connector->name, connector->has_tile);
-			modes[i] = drm_has_preferred_mode(fb_conn, width,
-							  height);
-		}
-
-		/* No preferred mode marked by the EDID? Are there any modes? */
-		if (!modes[i] && !list_empty(&connector->modes)) {
-			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
-				      connector->name);
-			modes[i] = list_first_entry(&connector->modes,
-						    struct drm_display_mode,
-						    head);
-		}
-
-		/* last resort: use current mode */
-		if (!modes[i]) {
-			/*
-			 * IMPORTANT: We want to use the adjusted mode (i.e.
-			 * after the panel fitter upscaling) as the initial
-			 * config, not the input mode, which is what crtc->mode
-			 * usually contains. But since our current
-			 * code puts a mode derived from the post-pfit timings
-			 * into crtc->mode this works out correctly.
-			 *
-			 * This is crtc->mode and not crtc->state->mode for the
-			 * fastboot check to work correctly. crtc_state->mode has
-			 * I915_MODE_FLAG_INHERITED, which we clear to force check
-			 * state.
-			 */
-			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
-				      connector->name);
-			modes[i] = &connector->state->crtc->mode;
-		}
-		crtcs[i] = new_crtc;
-
-		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
-			      connector->name,
-			      connector->state->crtc->base.id,
-			      connector->state->crtc->name,
-			      modes[i]->hdisplay, modes[i]->vdisplay,
-			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
-
-		fallback = false;
-		conn_configured |= BIT(i);
-	}
-
-	if (conn_configured != conn_seq) { /* repeat until no more are found */
-		conn_seq = conn_configured;
-		goto retry;
-	}
-
-	/*
-	 * If the BIOS didn't enable everything it could, fall back to have the
-	 * same user experiencing of lighting up as much as possible like the
-	 * fbdev helper library.
-	 */
-	if (num_connectors_enabled != num_connectors_detected &&
-	    num_connectors_enabled < INTEL_INFO(dev_priv)->num_pipes) {
-		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
-		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
-			      num_connectors_detected);
-		fallback = true;
-	}
-
-	if (fallback) {
-bail:
-		DRM_DEBUG_KMS("Not using firmware configuration\n");
-		memcpy(enabled, save_enabled, count);
-		ret = false;
-	}
-
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
-
-	kfree(save_enabled);
-	return ret;
-}
-
 static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
-	.initial_config = intel_fb_initial_config,
 	.fb_probe = intelfb_create,
 };
 
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 81ae48a0df48..4db7de19a491 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -101,29 +101,6 @@ struct drm_fb_helper_funcs {
 	 */
 	int (*fb_probe)(struct drm_fb_helper *helper,
 			struct drm_fb_helper_surface_size *sizes);
-
-	/**
-	 * @initial_config:
-	 *
-	 * Driver callback to setup an initial fbdev display configuration.
-	 * Drivers can use this callback to tell the fbdev emulation what the
-	 * preferred initial configuration is. This is useful to implement
-	 * smooth booting where the fbdev (and subsequently all userspace) never
-	 * changes the mode, but always inherits the existing configuration.
-	 *
-	 * This callback is optional.
-	 *
-	 * RETURNS:
-	 *
-	 * The driver should return true if a suitable initial configuration has
-	 * been filled out and false when the fbdev helper should fall back to
-	 * the default probing logic.
-	 */
-	bool (*initial_config)(struct drm_fb_helper *fb_helper,
-			       struct drm_fb_helper_crtc **crtcs,
-			       struct drm_display_mode **modes,
-			       struct drm_fb_offset *offsets,
-			       bool *enabled, int width, int height);
 };
 
 struct drm_fb_helper_connector {
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 04/12] drm/fb-helper: No need to cache rotation and sw_rotations
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (2 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  9:28   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 05/12] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, Noralf Trønnes

Getting rotation info is cheap so we can do it on demand.

This is done in preparation for the removal of struct drm_fb_helper_crtc.

Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_fb_helper.c | 131 ++++++++++++++++----------------
 include/drm/drm_fb_helper.h     |   8 --
 2 files changed, 65 insertions(+), 74 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index eda8b63f350d..2f71160cc904 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -388,6 +388,49 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
+/* Check if the plane can hw rotate to match panel orientation */
+static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
+					 unsigned int *rotation)
+{
+	struct drm_connector *connector = modeset->connectors[0];
+	struct drm_plane *plane = modeset->crtc->primary;
+	u64 valid_mask = 0;
+	unsigned int i;
+
+	if (!modeset->num_connectors)
+		return false;
+
+	switch (connector->display_info.panel_orientation) {
+	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+		*rotation = DRM_MODE_ROTATE_180;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+		*rotation = DRM_MODE_ROTATE_90;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+		*rotation = DRM_MODE_ROTATE_270;
+		break;
+	default:
+		*rotation = DRM_MODE_ROTATE_0;
+	}
+
+	/*
+	 * TODO: support 90 / 270 degree hardware rotation,
+	 * depending on the hardware this may require the framebuffer
+	 * to be in a specific tiling format.
+	 */
+	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+		return false;
+
+	for (i = 0; i < plane->rotation_property->num_values; i++)
+		valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+	if (!(*rotation & valid_mask))
+		return false;
+
+	return true;
+}
+
 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
 {
 	struct drm_device *dev = fb_helper->dev;
@@ -428,10 +471,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
 		struct drm_plane *primary = mode_set->crtc->primary;
+		unsigned int rotation;
 
-		/* Cannot fail as we've already gotten the plane state above */
-		plane_state = drm_atomic_get_new_plane_state(state, primary);
-		plane_state->rotation = fb_helper->crtc_info[i].rotation;
+		if (drm_fb_helper_panel_rotation(mode_set, &rotation)) {
+			/* Cannot fail as we've already gotten the plane state above */
+			plane_state = drm_atomic_get_new_plane_state(state, primary);
+			plane_state->rotation = rotation;
+		}
 
 		ret = __drm_atomic_helper_set_config(mode_set, state);
 		if (ret != 0)
@@ -871,7 +917,6 @@ int drm_fb_helper_init(struct drm_device *dev,
 		if (!fb_helper->crtc_info[i].mode_set.connectors)
 			goto out_free;
 		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-		fb_helper->crtc_info[i].rotation = DRM_MODE_ROTATE_0;
 	}
 
 	i = 0;
@@ -2500,62 +2545,6 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	return best_score;
 }
 
-/*
- * This function checks if rotation is necessary because of panel orientation
- * and if it is, if it is supported.
- * If rotation is necessary and supported, it gets set in fb_crtc.rotation.
- * If rotation is necessary but not supported, a DRM_MODE_ROTATE_* flag gets
- * or-ed into fb_helper->sw_rotations. In drm_setup_crtcs_fb() we check if only
- * one bit is set and then we set fb_info.fbcon_rotate_hint to make fbcon do
- * the unsupported rotation.
- */
-static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
-				    struct drm_fb_helper_crtc *fb_crtc,
-				    struct drm_connector *connector)
-{
-	struct drm_plane *plane = fb_crtc->mode_set.crtc->primary;
-	uint64_t valid_mask = 0;
-	int i, rotation;
-
-	fb_crtc->rotation = DRM_MODE_ROTATE_0;
-
-	switch (connector->display_info.panel_orientation) {
-	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
-		rotation = DRM_MODE_ROTATE_180;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
-		rotation = DRM_MODE_ROTATE_90;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
-		rotation = DRM_MODE_ROTATE_270;
-		break;
-	default:
-		rotation = DRM_MODE_ROTATE_0;
-	}
-
-	/*
-	 * TODO: support 90 / 270 degree hardware rotation,
-	 * depending on the hardware this may require the framebuffer
-	 * to be in a specific tiling format.
-	 */
-	if (rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property) {
-		fb_helper->sw_rotations |= rotation;
-		return;
-	}
-
-	for (i = 0; i < plane->rotation_property->num_values; i++)
-		valid_mask |= (1ULL << plane->rotation_property->values[i]);
-
-	if (!(rotation & valid_mask)) {
-		fb_helper->sw_rotations |= rotation;
-		return;
-	}
-
-	fb_crtc->rotation = rotation;
-	/* Rotating in hardware, fbcon should not rotate */
-	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
-}
-
 static struct drm_fb_helper_crtc *
 drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
 {
@@ -2801,7 +2790,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		drm_fb_helper_modeset_release(fb_helper,
 					      &fb_helper->crtc_info[i].mode_set);
 
-	fb_helper->sw_rotations = 0;
 	drm_fb_helper_for_each_connector(fb_helper, i) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
@@ -2821,7 +2809,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			modeset->mode = drm_mode_duplicate(dev,
 							   fb_crtc->desired_mode);
 			drm_connector_get(connector);
-			drm_setup_crtc_rotation(fb_helper, fb_crtc, connector);
 			modeset->connectors[modeset->num_connectors++] = connector;
 			modeset->x = offset->x;
 			modeset->y = offset->y;
@@ -2844,11 +2831,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info = fb_helper->fbdev;
+	unsigned int rotation, sw_rotations = 0;
 	int i;
 
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		if (fb_helper->crtc_info[i].mode_set.num_connectors)
-			fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
+	for (i = 0; i < fb_helper->crtc_count; i++) {
+		struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
+
+		if (!modeset->num_connectors)
+			continue;
+
+		modeset->fb = fb_helper->fb;
+
+		if (drm_fb_helper_panel_rotation(modeset, &rotation))
+			/* Rotating in hardware, fbcon should not rotate */
+			sw_rotations |= DRM_MODE_ROTATE_0;
+		else
+			sw_rotations |= rotation;
+	}
 
 	mutex_lock(&fb_helper->dev->mode_config.mutex);
 	drm_fb_helper_for_each_connector(fb_helper, i) {
@@ -2864,7 +2863,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 	}
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
-	switch (fb_helper->sw_rotations) {
+	switch (sw_rotations) {
 	case DRM_MODE_ROTATE_0:
 		info->fbcon_rotate_hint = FB_ROTATE_UR;
 		break;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 4db7de19a491..d954f48c9636 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -50,7 +50,6 @@ struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
 	struct drm_display_mode *desired_mode;
 	int x, y;
-	int rotation;
 };
 
 /**
@@ -150,13 +149,6 @@ struct drm_fb_helper {
 	struct drm_fb_helper_crtc *crtc_info;
 	int connector_count;
 	int connector_info_alloc_count;
-	/**
-	 * @sw_rotations:
-	 * Bitmask of all rotations requested for panel-orientation which
-	 * could not be handled in hardware. If only one bit is set
-	 * fbdev->fbcon_rotate_hint gets set to the requested rotation.
-	 */
-	int sw_rotations;
 	/**
 	 * @connector_info:
 	 *
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 05/12] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (3 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 04/12] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  9:29   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 06/12] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx

The values are already present in the modeset.

This is done in preparation for the removal of struct drm_fb_helper_crtc.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_fb_helper.c | 12 ++++--------
 include/drm/drm_fb_helper.h     |  2 --
 2 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2f71160cc904..69dddc4a9231 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2021,16 +2021,16 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		 */
 		bool lastv = true, lasth = true;
 
-		desired_mode = fb_helper->crtc_info[i].desired_mode;
 		mode_set = &fb_helper->crtc_info[i].mode_set;
+		desired_mode = mode_set->mode;
 
 		if (!desired_mode)
 			continue;
 
 		crtc_count++;
 
-		x = fb_helper->crtc_info[i].x;
-		y = fb_helper->crtc_info[i].y;
+		x = mode_set->x;
+		y = mode_set->y;
 
 		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
 		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
@@ -2803,11 +2803,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
 				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
 
-			fb_crtc->desired_mode = mode;
-			fb_crtc->x = offset->x;
-			fb_crtc->y = offset->y;
-			modeset->mode = drm_mode_duplicate(dev,
-							   fb_crtc->desired_mode);
+			modeset->mode = drm_mode_duplicate(dev, mode);
 			drm_connector_get(connector);
 			modeset->connectors[modeset->num_connectors++] = connector;
 			modeset->x = offset->x;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index d954f48c9636..0d6d23a15b42 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -48,8 +48,6 @@ struct drm_fb_offset {
 
 struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
-	struct drm_display_mode *desired_mode;
-	int x, y;
 };
 
 /**
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 06/12] drm/fb-helper: Remove drm_fb_helper_crtc
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (4 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 05/12] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  8:34   ` Daniel Vetter
  2019-04-07 16:52 ` [PATCH v2 07/12] drm/fb-helper: Prepare to move out commit code Noralf Trønnes
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, Noralf Trønnes

It now only contains the modeset so use that directly instead and attach
a modeset array to drm_client_dev. drm_fb_helper will use this array.
Code will later be moved to drm_client, so add code there in a new file
drm_client_modeset.c with MIT license to match drm_fb_helper.c.

The modeset connector array size is hardcoded for the cloned case to avoid
having to pass in a value from the driver. A value of 8 is chosen to err
on the safe side. This means that the max connector argument for
drm_fb_helper_init() and drm_fb_helper_fbdev_setup() isn't used anymore,
a todo entry for this is added.

In pan_display_atomic() restore_fbdev_mode_force() is used instead of
restore_fbdev_mode_atomic() because that one will later become internal
to drm_client_modeset.

Locking order:
1. drm_fb_helper->lock
2. drm_master_internal_acquire
3. drm_client_dev->modeset_mutex

v2:
- Add modesets array to drm_client (Daniel Vetter)
- Use a new file for the modeset code (Daniel Vetter)
- File has to be MIT licensed (Emmanuel Vadot)
- Add copyrights from drm_fb_helper.c

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 Documentation/gpu/todo.rst           |   7 +
 drivers/gpu/drm/Makefile             |   2 +-
 drivers/gpu/drm/drm_client.c         |  10 +-
 drivers/gpu/drm/drm_client_modeset.c | 102 +++++++++
 drivers/gpu/drm/drm_fb_helper.c      | 301 +++++++++++----------------
 include/drm/drm_client.h             |  28 +++
 include/drm/drm_fb_helper.h          |   8 -
 7 files changed, 272 insertions(+), 186 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_client_modeset.c

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 1528ad2d598b..8fa08b5feab7 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -300,6 +300,13 @@ it to use drm_mode_hsync() instead.
 
 Contact: Sean Paul
 
+drm_fb_helper cleanup tasks
+---------------------------
+
+- The max connector argument for drm_fb_helper_init() and
+  drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
+
+
 Core refactorings
 =================
 
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 6c7e8d162b4e..08c77c10ccbb 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -19,7 +19,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_plane.o drm_color_mgmt.o drm_print.o \
 		drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
 		drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
-		drm_atomic_uapi.o
+		drm_client_modeset.o drm_atomic_uapi.o
 
 drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
 drm-$(CONFIG_DRM_VM) += drm_vm.o
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 9b2bd28dde0a..3ad5b57c1419 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -91,14 +91,20 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
 	client->name = name;
 	client->funcs = funcs;
 
-	ret = drm_client_open(client);
+	ret = drm_client_modeset_create(client);
 	if (ret)
 		goto err_put_module;
 
+	ret = drm_client_open(client);
+	if (ret)
+		goto err_free;
+
 	drm_dev_get(dev);
 
 	return 0;
 
+err_free:
+	drm_client_modeset_free(client);
 err_put_module:
 	if (funcs)
 		module_put(funcs->owner);
@@ -147,6 +153,8 @@ void drm_client_release(struct drm_client_dev *client)
 
 	DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
 
+	drm_client_modeset_release(client);
+	drm_client_modeset_free(client);
 	drm_client_close(client);
 	drm_dev_put(dev);
 	if (client->funcs)
diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
new file mode 100644
index 000000000000..bb34222c9db8
--- /dev/null
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2018 Noralf Trønnes
+ * Copyright (c) 2006-2009 Red Hat Inc.
+ * Copyright (c) 2006-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+
+/* Used by drm_client and drm_fb_helper */
+int drm_client_modeset_create(struct drm_client_dev *client)
+{
+	struct drm_device *dev = client->dev;
+	unsigned int num_crtc = dev->mode_config.num_crtc;
+	unsigned int max_connector_count = 1;
+	struct drm_mode_set *modeset;
+	struct drm_crtc *crtc;
+	unsigned int i = 0;
+
+	/* Add terminating zero entry to enable index less iteration */
+	client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);
+	if (!client->modesets)
+		return -ENOMEM;
+
+	mutex_init(&client->modeset_mutex);
+
+	drm_for_each_crtc(crtc, dev)
+		client->modesets[i++].crtc = crtc;
+
+	/* Cloning is only supported in the single crtc case. */
+	if (num_crtc == 1)
+		max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
+
+	drm_client_for_each_modeset(modeset, client) {
+		modeset->connectors = kcalloc(max_connector_count,
+					      sizeof(*modeset->connectors), GFP_KERNEL);
+		if (!modeset->connectors)
+			goto err_free;
+	}
+
+	return 0;
+
+err_free:
+	drm_client_modeset_free(client);
+
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_client_modeset_create);
+
+/* Used by drm_client and drm_fb_helper */
+void drm_client_modeset_free(struct drm_client_dev *client)
+{
+	struct drm_mode_set *modeset;
+
+	mutex_destroy(&client->modeset_mutex);
+
+	drm_client_for_each_modeset(modeset, client)
+		kfree(modeset->connectors);
+	kfree(client->modesets);
+}
+EXPORT_SYMBOL(drm_client_modeset_free);
+
+/* Used by drm_client and drm_fb_helper */
+void drm_client_modeset_release(struct drm_client_dev *client)
+{
+	struct drm_mode_set *modeset;
+	unsigned int i;
+
+	drm_client_for_each_modeset(modeset, client) {
+		drm_mode_destroy(client->dev, modeset->mode);
+		modeset->mode = NULL;
+		modeset->fb = NULL;
+
+		for (i = 0; i < modeset->num_connectors; i++) {
+			drm_connector_put(modeset->connectors[i]);
+			modeset->connectors[i] = NULL;
+		}
+		modeset->num_connectors = 0;
+	}
+}
+EXPORT_SYMBOL(drm_client_modeset_release);
+
+struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
+{
+	struct drm_mode_set *modeset;
+
+	drm_client_for_each_modeset(modeset, client)
+		if (modeset->crtc == crtc)
+			return modeset;
+
+	return NULL;
+}
+/* TODO: Remove export when modeset code has been moved over */
+EXPORT_SYMBOL(drm_client_find_modeset);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 69dddc4a9231..b65edfc99feb 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -317,13 +317,11 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
 {
 	struct drm_fb_helper *helper = info->par;
 	const struct drm_crtc_helper_funcs *funcs;
-	int i;
+	struct drm_mode_set *mode_set;
 
 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-		for (i = 0; i < helper->crtc_count; i++) {
-			struct drm_mode_set *mode_set =
-				&helper->crtc_info[i].mode_set;
-
+		mutex_lock(&helper->client.modeset_mutex);
+		drm_client_for_each_modeset(mode_set, &helper->client) {
 			if (!mode_set->crtc->enabled)
 				continue;
 
@@ -340,6 +338,7 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
 						    mode_set->y,
 						    ENTER_ATOMIC_MODE_SET);
 		}
+		mutex_unlock(&helper->client.modeset_mutex);
 	}
 
 	return 0;
@@ -353,14 +352,14 @@ EXPORT_SYMBOL(drm_fb_helper_debug_enter);
 int drm_fb_helper_debug_leave(struct fb_info *info)
 {
 	struct drm_fb_helper *helper = info->par;
+	struct drm_client_dev *client = &helper->client;
 	struct drm_crtc *crtc;
 	const struct drm_crtc_helper_funcs *funcs;
+	struct drm_mode_set *mode_set;
 	struct drm_framebuffer *fb;
-	int i;
-
-	for (i = 0; i < helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
 
+	mutex_lock(&client->modeset_mutex);
+	drm_client_for_each_modeset(mode_set, client) {
 		crtc = mode_set->crtc;
 		if (drm_drv_uses_atomic_modeset(crtc->dev))
 			continue;
@@ -383,6 +382,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
 					    crtc->y, LEAVE_ATOMIC_MODE_SET);
 	}
+	mutex_unlock(&client->modeset_mutex);
 
 	return 0;
 }
@@ -433,12 +433,14 @@ static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
 
 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
 {
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_plane_state *plane_state;
 	struct drm_plane *plane;
 	struct drm_atomic_state *state;
-	int i, ret;
 	struct drm_modeset_acquire_ctx ctx;
+	struct drm_mode_set *mode_set;
+	int ret;
 
 	drm_modeset_acquire_init(&ctx, 0);
 
@@ -468,8 +470,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 			goto out_state;
 	}
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+	drm_client_for_each_modeset(mode_set, client) {
 		struct drm_plane *primary = mode_set->crtc->primary;
 		unsigned int rotation;
 
@@ -517,9 +518,11 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 
 static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 {
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_device *dev = fb_helper->dev;
+	struct drm_mode_set *mode_set;
 	struct drm_plane *plane;
-	int i, ret = 0;
+	int ret = 0;
 
 	drm_modeset_lock_all(fb_helper->dev);
 	drm_for_each_plane(plane, dev) {
@@ -532,8 +535,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 						    DRM_MODE_ROTATE_0);
 	}
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+	drm_client_for_each_modeset(mode_set, client) {
 		struct drm_crtc *crtc = mode_set->crtc;
 
 		if (crtc->funcs->cursor_set2) {
@@ -559,11 +561,16 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
 {
 	struct drm_device *dev = fb_helper->dev;
+	int ret;
 
+	mutex_lock(&fb_helper->client.modeset_mutex);
 	if (drm_drv_uses_atomic_modeset(dev))
-		return restore_fbdev_mode_atomic(fb_helper, true);
+		ret = restore_fbdev_mode_atomic(fb_helper, true);
 	else
-		return restore_fbdev_mode_legacy(fb_helper);
+		ret = restore_fbdev_mode_legacy(fb_helper);
+	mutex_unlock(&fb_helper->client.modeset_mutex);
+
+	return ret;
 }
 
 static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
@@ -672,15 +679,14 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 
 static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 {
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
-	int i, j;
+	int j;
 
 	drm_modeset_lock_all(dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		modeset = &fb_helper->crtc_info[i].mode_set;
-
+	drm_client_for_each_modeset(modeset, client) {
 		if (!modeset->crtc->enabled)
 			continue;
 
@@ -697,6 +703,7 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_device *dev = fb_helper->dev;
 
 	/*
@@ -706,10 +713,12 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 	if (!drm_master_internal_acquire(dev))
 		goto unlock;
 
+	mutex_lock(&client->modeset_mutex);
 	if (drm_drv_uses_atomic_modeset(dev))
 		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
 	else
 		dpms_legacy(fb_helper, dpms_mode);
+	mutex_unlock(&client->modeset_mutex);
 
 	drm_master_internal_release(dev);
 unlock:
@@ -752,43 +761,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_blank);
 
-static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
-					  struct drm_mode_set *modeset)
-{
-	int i;
-
-	for (i = 0; i < modeset->num_connectors; i++) {
-		drm_connector_put(modeset->connectors[i]);
-		modeset->connectors[i] = NULL;
-	}
-	modeset->num_connectors = 0;
-
-	drm_mode_destroy(helper->dev, modeset->mode);
-	modeset->mode = NULL;
-
-	/* FIXME should hold a ref? */
-	modeset->fb = NULL;
-}
-
-static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
-{
-	int i;
-
-	for (i = 0; i < helper->connector_count; i++) {
-		drm_connector_put(helper->connector_info[i]->connector);
-		kfree(helper->connector_info[i]);
-	}
-	kfree(helper->connector_info);
-
-	for (i = 0; i < helper->crtc_count; i++) {
-		struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
-
-		drm_fb_helper_modeset_release(helper, modeset);
-		kfree(modeset->connectors);
-	}
-	kfree(helper->crtc_info);
-}
-
 static void drm_fb_helper_resume_worker(struct work_struct *work)
 {
 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
@@ -867,7 +839,7 @@ EXPORT_SYMBOL(drm_fb_helper_prepare);
  * drm_fb_helper_init - initialize a &struct drm_fb_helper
  * @dev: drm device
  * @fb_helper: driver-allocated fbdev helper structure to initialize
- * @max_conn_count: max connector count
+ * @max_conn_count: max connector count (not used)
  *
  * This allocates the structures for the fbdev helper with the given limits.
  * Note that this won't yet touch the hardware (through the driver interfaces)
@@ -883,53 +855,34 @@ int drm_fb_helper_init(struct drm_device *dev,
 		       struct drm_fb_helper *fb_helper,
 		       int max_conn_count)
 {
-	struct drm_crtc *crtc;
-	struct drm_mode_config *config = &dev->mode_config;
-	int i;
+	int ret;
 
 	if (!drm_fbdev_emulation) {
 		dev->fb_helper = fb_helper;
 		return 0;
 	}
 
-	if (!max_conn_count)
-		return -EINVAL;
-
-	fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
-	if (!fb_helper->crtc_info)
-		return -ENOMEM;
-
-	fb_helper->crtc_count = config->num_crtc;
-	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-	if (!fb_helper->connector_info) {
-		kfree(fb_helper->crtc_info);
-		return -ENOMEM;
+	/* The generic fbdev client has already done this */
+	if (!fb_helper->client.funcs) {
+		fb_helper->client.dev = dev;
+		ret = drm_client_modeset_create(&fb_helper->client);
+		if (ret)
+			return ret;
 	}
+
+	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
+	if (!fb_helper->connector_info)
+		goto out_free;
+
 	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
 	fb_helper->connector_count = 0;
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		fb_helper->crtc_info[i].mode_set.connectors =
-			kcalloc(max_conn_count,
-				sizeof(struct drm_connector *),
-				GFP_KERNEL);
-
-		if (!fb_helper->crtc_info[i].mode_set.connectors)
-			goto out_free;
-		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-	}
-
-	i = 0;
-	drm_for_each_crtc(crtc, dev) {
-		fb_helper->crtc_info[i].mode_set.crtc = crtc;
-		i++;
-	}
-
 	dev->fb_helper = fb_helper;
 
 	return 0;
 out_free:
-	drm_fb_helper_crtc_free(fb_helper);
+	drm_client_modeset_free(&fb_helper->client);
+
 	return -ENOMEM;
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
@@ -1005,6 +958,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info;
+	int i;
 
 	if (!fb_helper)
 		return;
@@ -1034,8 +988,17 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 	mutex_unlock(&kernel_fb_helper_lock);
 
 	mutex_destroy(&fb_helper->lock);
-	drm_fb_helper_crtc_free(fb_helper);
 
+	if (!fb_helper->client.funcs) {
+		drm_client_modeset_release(&fb_helper->client);
+		drm_client_modeset_free(&fb_helper->client);
+	}
+
+	for (i = 0; i < fb_helper->connector_count; i++) {
+		drm_connector_put(fb_helper->connector_info[i]->connector);
+		kfree(fb_helper->connector_info[i]);
+	}
+	kfree(fb_helper->connector_info);
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
@@ -1380,13 +1343,14 @@ static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
 static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_mode_set *modeset;
 	struct drm_crtc *crtc;
 	u16 *r, *g, *b;
-	int i, ret = 0;
+	int ret = 0;
 
 	drm_modeset_lock_all(fb_helper->dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+	drm_client_for_each_modeset(modeset, &fb_helper->client) {
+		crtc = modeset->crtc;
 		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
 			return -EINVAL;
 
@@ -1462,10 +1426,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 	struct drm_modeset_acquire_ctx ctx;
 	struct drm_crtc_state *crtc_state;
 	struct drm_atomic_state *state;
+	struct drm_mode_set *modeset;
 	struct drm_crtc *crtc;
 	u16 *r, *g, *b;
-	int i, ret = 0;
 	bool replaced;
+	int ret = 0;
 
 	drm_modeset_acquire_init(&ctx, 0);
 
@@ -1477,8 +1442,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 
 	state->acquire_ctx = &ctx;
 retry:
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+	drm_client_for_each_modeset(modeset, &fb_helper->client) {
+		crtc = modeset->crtc;
 
 		if (!gamma_lut)
 			gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
@@ -1506,8 +1471,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
 	if (ret)
 		goto out_state;
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+	drm_client_for_each_modeset(modeset, &fb_helper->client) {
+		crtc = modeset->crtc;
 
 		r = crtc->gamma_store;
 		g = r + crtc->gamma_size;
@@ -1557,12 +1522,14 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
 		goto unlock;
 	}
 
+	mutex_lock(&fb_helper->client.modeset_mutex);
 	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
 		ret = setcmap_pseudo_palette(cmap, info);
 	else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
 		ret = setcmap_atomic(cmap, info);
 	else
 		ret = setcmap_legacy(cmap, info);
+	mutex_unlock(&fb_helper->client.modeset_mutex);
 
 	drm_master_internal_release(dev);
 unlock:
@@ -1586,7 +1553,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 {
 	struct drm_fb_helper *fb_helper = info->par;
 	struct drm_device *dev = fb_helper->dev;
-	struct drm_mode_set *mode_set;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
@@ -1614,8 +1580,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 		 * make. If we're not smart enough here, one should
 		 * just consider switch the userspace to KMS.
 		 */
-		mode_set = &fb_helper->crtc_info[0].mode_set;
-		crtc = mode_set->crtc;
+		crtc = fb_helper->client.modesets[0].crtc;
 
 		/*
 		 * Only wait for a vblank event if the CRTC is
@@ -1812,16 +1777,14 @@ EXPORT_SYMBOL(drm_fb_helper_set_par);
 
 static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
 {
-	int i;
-
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set;
-
-		mode_set = &fb_helper->crtc_info[i].mode_set;
+	struct drm_mode_set *mode_set;
 
+	mutex_lock(&fb_helper->client.modeset_mutex);
+	drm_client_for_each_modeset(mode_set, &fb_helper->client) {
 		mode_set->x = x;
 		mode_set->y = y;
 	}
+	mutex_unlock(&fb_helper->client.modeset_mutex);
 }
 
 static int pan_display_atomic(struct fb_var_screeninfo *var,
@@ -1832,7 +1795,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
 
 	pan_set(fb_helper, var->xoffset, var->yoffset);
 
-	ret = restore_fbdev_mode_atomic(fb_helper, true);
+	ret = restore_fbdev_mode_force(fb_helper);
 	if (!ret) {
 		info->var.xoffset = var->xoffset;
 		info->var.yoffset = var->yoffset;
@@ -1846,14 +1809,13 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
 			      struct fb_info *info)
 {
 	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_mode_set *modeset;
 	int ret = 0;
-	int i;
 
 	drm_modeset_lock_all(fb_helper->dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		modeset = &fb_helper->crtc_info[i].mode_set;
-
+	mutex_lock(&client->modeset_mutex);
+	drm_client_for_each_modeset(modeset, client) {
 		modeset->x = var->xoffset;
 		modeset->y = var->yoffset;
 
@@ -1865,6 +1827,7 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
 			}
 		}
 	}
+	mutex_unlock(&client->modeset_mutex);
 	drm_modeset_unlock_all(fb_helper->dev);
 
 	return ret;
@@ -1911,10 +1874,12 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 					 int preferred_bpp)
 {
+	struct drm_client_dev *client = &fb_helper->client;
 	int ret = 0;
 	int crtc_count = 0;
 	int i;
 	struct drm_fb_helper_surface_size sizes;
+	struct drm_mode_set *mode_set;
 	int best_depth = 0;
 
 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
@@ -1965,13 +1930,13 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	 * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
 	 * 16) we need to scale down the depth of the sizes we request.
 	 */
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+	mutex_lock(&client->modeset_mutex);
+	drm_client_for_each_modeset(mode_set, client) {
 		struct drm_crtc *crtc = mode_set->crtc;
 		struct drm_plane *plane = crtc->primary;
 		int j;
 
-		DRM_DEBUG("test CRTC %d primary plane\n", i);
+		DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc));
 
 		for (j = 0; j < plane->format_count; j++) {
 			const struct drm_format_info *fmt;
@@ -2011,9 +1976,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 
 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
 	crtc_count = 0;
-	for (i = 0; i < fb_helper->crtc_count; i++) {
+	drm_client_for_each_modeset(mode_set, client) {
 		struct drm_display_mode *desired_mode;
-		struct drm_mode_set *mode_set;
 		int x, y, j;
 		/* in case of tile group, are we the last tile vert or horiz?
 		 * If no tile group you are always the last one both vertically
@@ -2021,7 +1985,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		 */
 		bool lastv = true, lasth = true;
 
-		mode_set = &fb_helper->crtc_info[i].mode_set;
 		desired_mode = mode_set->mode;
 
 		if (!desired_mode)
@@ -2051,6 +2014,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		if (lastv)
 			sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
 	}
+	mutex_unlock(&client->modeset_mutex);
 
 	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
 		DRM_INFO("Cannot find any crtc or sizes\n");
@@ -2282,7 +2246,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 	struct drm_display_mode *dmt_mode, *mode;
 
 	/* only contemplate cloning in the single crtc case */
-	if (fb_helper->crtc_count > 1)
+	if (fb_helper->dev->mode_config.num_crtc > 1)
 		return false;
 
 	count = 0;
@@ -2471,15 +2435,17 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
 }
 
 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
-			  struct drm_fb_helper_crtc **best_crtcs,
+			  struct drm_crtc **best_crtcs,
 			  struct drm_display_mode **modes,
 			  int n, int width, int height)
 {
-	int c, o;
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_connector *connector;
 	int my_score, best_score, score;
-	struct drm_fb_helper_crtc **crtcs, *crtc;
+	struct drm_crtc **crtcs, *crtc;
+	struct drm_mode_set *modeset;
 	struct drm_fb_helper_connector *fb_helper_conn;
+	int o;
 
 	if (n == fb_helper->connector_count)
 		return 0;
@@ -2492,8 +2458,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	if (modes[n] == NULL)
 		return best_score;
 
-	crtcs = kcalloc(fb_helper->connector_count,
-			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
+	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
 	if (!crtcs)
 		return best_score;
 
@@ -2509,11 +2474,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	 * select a crtc for this connector and then attempt to configure
 	 * remaining connectors
 	 */
-	for (c = 0; c < fb_helper->crtc_count; c++) {
-		crtc = &fb_helper->crtc_info[c];
+	drm_client_for_each_modeset(modeset, client) {
+		crtc = modeset->crtc;
 
-		if (!connector_has_possible_crtc(connector,
-						 crtc->mode_set.crtc))
+		if (!connector_has_possible_crtc(connector, crtc))
 			continue;
 
 		for (o = 0; o < n; o++)
@@ -2522,7 +2486,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 		if (o < n) {
 			/* ignore cloning unless only a single crtc */
-			if (fb_helper->crtc_count > 1)
+			if (fb_helper->dev->mode_config.num_crtc > 1)
 				continue;
 
 			if (!drm_mode_equal(modes[o], modes[n]))
@@ -2530,14 +2494,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 		}
 
 		crtcs[n] = crtc;
-		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
+		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
 		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
 						  width, height);
 		if (score > best_score) {
 			best_score = score;
 			memcpy(best_crtcs, crtcs,
-			       fb_helper->connector_count *
-			       sizeof(struct drm_fb_helper_crtc *));
+			       fb_helper->connector_count * sizeof(*crtcs));
 		}
 	}
 
@@ -2545,21 +2508,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	return best_score;
 }
 
-static struct drm_fb_helper_crtc *
-drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
-{
-	int i;
-
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
-			return &fb_helper->crtc_info[i];
-
-	return NULL;
-}
-
 /* Try to read the BIOS display configuration and use it for the initial config */
 static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
-					  struct drm_fb_helper_crtc **crtcs,
+					  struct drm_crtc **crtcs,
 					  struct drm_display_mode **modes,
 					  struct drm_fb_offset *offsets,
 					  bool *enabled, int width, int height)
@@ -2591,7 +2542,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 		struct drm_fb_helper_connector *fb_conn;
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
-		struct drm_fb_helper_crtc *new_crtc;
+		struct drm_crtc *new_crtc;
 
 		fb_conn = fb_helper->connector_info[i];
 		connector = fb_conn->connector;
@@ -2634,7 +2585,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 
 		num_connectors_enabled++;
 
-		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
+		new_crtc = connector->state->crtc;
 
 		/*
 		 * Make sure we're not trying to drive multiple connectors
@@ -2736,10 +2687,11 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
+	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_device *dev = fb_helper->dev;
-	struct drm_fb_helper_crtc **crtcs;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
+	struct drm_crtc **crtcs;
 	bool *enabled;
 	int i;
 
@@ -2747,8 +2699,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	/* prevent concurrent modification of connector_count by hotplug */
 	lockdep_assert_held(&fb_helper->lock);
 
-	crtcs = kcalloc(fb_helper->connector_count,
-			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
+	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
 	modes = kcalloc(fb_helper->connector_count,
 			sizeof(struct drm_display_mode *), GFP_KERNEL);
 	offsets = kcalloc(fb_helper->connector_count,
@@ -2760,6 +2711,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		goto out;
 	}
 
+	mutex_lock(&client->modeset_mutex);
+
 	mutex_lock(&fb_helper->dev->mode_config.mutex);
 	if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
 		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
@@ -2784,24 +2737,24 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	}
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
-	/* need to set the modesets up here for use later */
-	/* fill out the connector<->crtc mappings into the modesets */
-	for (i = 0; i < fb_helper->crtc_count; i++)
-		drm_fb_helper_modeset_release(fb_helper,
-					      &fb_helper->crtc_info[i].mode_set);
+	drm_client_modeset_release(client);
 
 	drm_fb_helper_for_each_connector(fb_helper, i) {
 		struct drm_display_mode *mode = modes[i];
-		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
+		struct drm_crtc *crtc = crtcs[i];
 		struct drm_fb_offset *offset = &offsets[i];
 
-		if (mode && fb_crtc) {
-			struct drm_mode_set *modeset = &fb_crtc->mode_set;
+		if (mode && crtc) {
+			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
 			struct drm_connector *connector =
 				fb_helper->connector_info[i]->connector;
 
 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
-				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
+				      mode->name, crtc->base.id, offset->x, offset->y);
+
+			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
+				break;
 
 			modeset->mode = drm_mode_duplicate(dev, mode);
 			drm_connector_get(connector);
@@ -2810,6 +2763,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			modeset->y = offset->y;
 		}
 	}
+
+	mutex_unlock(&client->modeset_mutex);
 out:
 	kfree(crtcs);
 	kfree(modes);
@@ -2826,13 +2781,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
  */
 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
+	struct drm_client_dev *client = &fb_helper->client;
 	struct fb_info *info = fb_helper->fbdev;
 	unsigned int rotation, sw_rotations = 0;
+	struct drm_mode_set *modeset;
 	int i;
 
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
-
+	mutex_lock(&client->modeset_mutex);
+	drm_client_for_each_modeset(modeset, client) {
 		if (!modeset->num_connectors)
 			continue;
 
@@ -2844,6 +2800,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 		else
 			sw_rotations |= rotation;
 	}
+	mutex_unlock(&client->modeset_mutex);
 
 	mutex_lock(&fb_helper->dev->mode_config.mutex);
 	drm_fb_helper_for_each_connector(fb_helper, i) {
@@ -3060,8 +3017,7 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
  * @funcs: fbdev helper functions
  * @preferred_bpp: Preferred bits per pixel for the device.
  *                 @dev->mode_config.preferred_depth is used if this is zero.
- * @max_conn_count: Maximum number of connectors.
- *                  @dev->mode_config.num_connector is used if this is zero.
+ * @max_conn_count: Maximum number of connectors (not used)
  *
  * This function sets up fbdev emulation and registers fbdev for access by
  * userspace. If all connectors are disconnected, setup is deferred to the next
@@ -3089,16 +3045,9 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
 	if (!preferred_bpp)
 		preferred_bpp = 32;
 
-	if (!max_conn_count)
-		max_conn_count = dev->mode_config.num_connector;
-	if (!max_conn_count) {
-		DRM_DEV_ERROR(dev->dev, "fbdev: No connectors\n");
-		return -EINVAL;
-	}
-
 	drm_fb_helper_prepare(dev, fb_helper, funcs);
 
-	ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
+	ret = drm_fb_helper_init(dev, fb_helper, 0);
 	if (ret < 0) {
 		DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
 		return ret;
@@ -3411,7 +3360,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
 
 	drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
 
-	ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector);
+	ret = drm_fb_helper_init(dev, fb_helper, 0);
 	if (ret)
 		goto err;
 
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 8b552b1a6ce9..858c8be70870 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,8 +3,11 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+#include <linux/mutex.h>
 #include <linux/types.h>
 
+#include <drm/drm_crtc.h>
+
 struct drm_client_dev;
 struct drm_device;
 struct drm_file;
@@ -13,6 +16,8 @@ struct drm_gem_object;
 struct drm_minor;
 struct module;
 
+#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
+
 /**
  * struct drm_client_funcs - DRM client callbacks
  */
@@ -85,6 +90,16 @@ struct drm_client_dev {
 	 * @file: DRM file
 	 */
 	struct drm_file *file;
+
+	/**
+	 * @modeset_mutex: Protects @modesets.
+	 */
+	struct mutex modeset_mutex;
+
+	/**
+	 * @modesets: CRTC configurations
+	 */
+	struct drm_mode_set *modesets;
 };
 
 int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
@@ -135,6 +150,19 @@ struct drm_client_buffer *
 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
 
+int drm_client_modeset_create(struct drm_client_dev *client);
+void drm_client_modeset_free(struct drm_client_dev *client);
+void drm_client_modeset_release(struct drm_client_dev *client);
+struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
+
+/**
+ * drm_client_for_each_modeset() - Iterate over client modesets
+ * @modeset: &drm_mode_set loop cursor
+ * @client: DRM client
+ */
+#define drm_client_for_each_modeset(modeset, client) \
+	for (modeset = (client)->modesets; modeset && modeset->crtc; modeset++)
+
 int drm_client_debugfs_init(struct drm_minor *minor);
 
 #endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 0d6d23a15b42..8d0ddea74a9e 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -46,10 +46,6 @@ struct drm_fb_offset {
 	int x, y;
 };
 
-struct drm_fb_helper_crtc {
-	struct drm_mode_set mode_set;
-};
-
 /**
  * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
  * @fb_width: fbdev width
@@ -108,8 +104,6 @@ struct drm_fb_helper_connector {
  * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
  * @fb: Scanout framebuffer object
  * @dev: DRM device
- * @crtc_count: number of possible CRTCs
- * @crtc_info: per-CRTC helper state (mode, x/y offset, etc)
  * @connector_count: number of connected connectors
  * @connector_info_alloc_count: size of connector_info
  * @funcs: driver callbacks for fb helper
@@ -143,8 +137,6 @@ struct drm_fb_helper {
 
 	struct drm_framebuffer *fb;
 	struct drm_device *dev;
-	int crtc_count;
-	struct drm_fb_helper_crtc *crtc_info;
 	int connector_count;
 	int connector_info_alloc_count;
 	/**
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 07/12] drm/fb-helper: Prepare to move out commit code
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (5 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 06/12] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-07 16:52 ` [PATCH v2 08/12] drm/fb-helper: Move " Noralf Trønnes
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx

This makes the necessary changes so the commit code can be moved out to
drm_client as-is in the next patch. It's split up to ease review.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 122 +++++++++++++++++++++-----------
 1 file changed, 81 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b65edfc99feb..0229e187e6de 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -388,9 +388,20 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
-/* Check if the plane can hw rotate to match panel orientation */
-static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
-					 unsigned int *rotation)
+/**
+ * drm_client_panel_rotation() - Check panel orientation
+ * @modeset: DRM modeset
+ * @rotation: Returned rotation value
+ *
+ * This function checks if the primary plane in @modeset can hw rotate to match
+ * the panel orientation on its connector.
+ *
+ * Note: Currently only 0 and 180 degrees are supported.
+ *
+ * Return:
+ * True if the plane can do the rotation, false otherwise.
+ */
+bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
 {
 	struct drm_connector *connector = modeset->connectors[0];
 	struct drm_plane *plane = modeset->crtc->primary;
@@ -431,10 +442,9 @@ static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
 	return true;
 }
 
-static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
+static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
 {
-	struct drm_client_dev *client = &fb_helper->client;
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
 	struct drm_plane_state *plane_state;
 	struct drm_plane *plane;
 	struct drm_atomic_state *state;
@@ -474,7 +484,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 		struct drm_plane *primary = mode_set->crtc->primary;
 		unsigned int rotation;
 
-		if (drm_fb_helper_panel_rotation(mode_set, &rotation)) {
+		if (drm_client_panel_rotation(mode_set, &rotation)) {
 			/* Cannot fail as we've already gotten the plane state above */
 			plane_state = drm_atomic_get_new_plane_state(state, primary);
 			plane_state->rotation = rotation;
@@ -516,15 +526,14 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 	goto retry;
 }
 
-static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
+static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
 {
-	struct drm_client_dev *client = &fb_helper->client;
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
 	struct drm_mode_set *mode_set;
 	struct drm_plane *plane;
 	int ret = 0;
 
-	drm_modeset_lock_all(fb_helper->dev);
+	drm_modeset_lock_all(dev);
 	drm_for_each_plane(plane, dev) {
 		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
 			drm_plane_force_disable(plane);
@@ -553,35 +562,53 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
 			goto out;
 	}
 out:
-	drm_modeset_unlock_all(fb_helper->dev);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
 
-static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
+/**
+ * drm_client_modeset_commit_force() - Force commit CRTC configuration
+ * @client: DRM client
+ *
+ * Commit modeset configuration to crtcs without checking if there is a DRM master.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_commit_force(struct drm_client_dev *client)
 {
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
 	int ret;
 
-	mutex_lock(&fb_helper->client.modeset_mutex);
+	mutex_lock(&client->modeset_mutex);
 	if (drm_drv_uses_atomic_modeset(dev))
-		ret = restore_fbdev_mode_atomic(fb_helper, true);
+		ret = drm_client_modeset_commit_atomic(client, true);
 	else
-		ret = restore_fbdev_mode_legacy(fb_helper);
-	mutex_unlock(&fb_helper->client.modeset_mutex);
+		ret = drm_client_modeset_commit_legacy(client);
+	mutex_unlock(&client->modeset_mutex);
 
 	return ret;
 }
 
-static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
+/**
+ * drm_client_modeset_commit() - Commit CRTC configuration
+ * @client: DRM client
+ *
+ * Commit modeset configuration to crtcs.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_commit(struct drm_client_dev *client)
 {
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
 	int ret;
 
 	if (!drm_master_internal_acquire(dev))
 		return -EBUSY;
 
-	ret = restore_fbdev_mode_force(fb_helper);
+	ret = drm_client_modeset_commit_force(client);
 
 	drm_master_internal_release(dev);
 
@@ -611,7 +638,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 		return 0;
 
 	mutex_lock(&fb_helper->lock);
-	ret = restore_fbdev_mode(fb_helper);
+	ret = drm_client_modeset_commit(&fb_helper->client);
 
 	do_delayed = fb_helper->delayed_hotplug;
 	if (do_delayed)
@@ -645,7 +672,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
 			continue;
 
 		mutex_lock(&helper->lock);
-		ret = restore_fbdev_mode_force(helper);
+		ret = drm_client_modeset_commit_force(&helper->client);
 		if (ret)
 			error = true;
 		mutex_unlock(&helper->lock);
@@ -677,10 +704,9 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
+static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
 {
-	struct drm_client_dev *client = &fb_helper->client;
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
 	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
 	int j;
@@ -700,28 +726,42 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 	drm_modeset_unlock_all(dev);
 }
 
-static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
+/**
+ * drm_client_modeset_dpms() - Set DPMS mode
+ * @client: DRM client
+ * @mode: DPMS mode
+ *
+ * Note: For atomic drivers @mode is reduced to on/off.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
 {
-	struct drm_fb_helper *fb_helper = info->par;
-	struct drm_client_dev *client = &fb_helper->client;
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
+	int ret = 0;
 
-	/*
-	 * For each CRTC in this fb, turn the connectors on/off.
-	 */
-	mutex_lock(&fb_helper->lock);
 	if (!drm_master_internal_acquire(dev))
-		goto unlock;
+		return -EBUSY;
 
 	mutex_lock(&client->modeset_mutex);
 	if (drm_drv_uses_atomic_modeset(dev))
-		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
+		ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON);
 	else
-		dpms_legacy(fb_helper, dpms_mode);
+		drm_client_modeset_dpms_legacy(client, mode);
 	mutex_unlock(&client->modeset_mutex);
 
 	drm_master_internal_release(dev);
-unlock:
+
+	return ret;
+}
+
+static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	mutex_lock(&fb_helper->lock);
+	drm_client_modeset_dpms(&fb_helper->client, dpms_mode);
 	mutex_unlock(&fb_helper->lock);
 }
 
@@ -1795,7 +1835,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
 
 	pan_set(fb_helper, var->xoffset, var->yoffset);
 
-	ret = restore_fbdev_mode_force(fb_helper);
+	ret = drm_client_modeset_commit_force(&fb_helper->client);
 	if (!ret) {
 		info->var.xoffset = var->xoffset;
 		info->var.yoffset = var->yoffset;
@@ -2021,7 +2061,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 
 		/* First time: disable all crtc's.. */
 		if (!fb_helper->deferred_setup)
-			restore_fbdev_mode(fb_helper);
+			drm_client_modeset_commit(client);
 		return -EAGAIN;
 	}
 
@@ -2794,7 +2834,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 
 		modeset->fb = fb_helper->fb;
 
-		if (drm_fb_helper_panel_rotation(modeset, &rotation))
+		if (drm_client_panel_rotation(modeset, &rotation))
 			/* Rotating in hardware, fbcon should not rotate */
 			sw_rotations |= DRM_MODE_ROTATE_0;
 		else
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 08/12] drm/fb-helper: Move out commit code
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (6 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 07/12] drm/fb-helper: Prepare to move out commit code Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  8:38   ` Daniel Vetter
  2019-04-07 16:52 ` [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, Noralf Trønnes

Move the modeset commit code to drm_client_modeset.
No changes except exporting API.

v2: Move to drm_client_modeset.c instead of drm_client.c

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client_modeset.c | 287 +++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c      | 282 --------------------------
 include/drm/drm_client.h             |   4 +
 3 files changed, 291 insertions(+), 282 deletions(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index bb34222c9db8..94b52f97c06b 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -11,9 +11,14 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 
+#include <drm/drm_atomic.h>
 #include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
+#include <drm/drm_drv.h>
+
+#include "drm_crtc_internal.h"
+#include "drm_internal.h"
 
 /* Used by drm_client and drm_fb_helper */
 int drm_client_modeset_create(struct drm_client_dev *client)
@@ -100,3 +105,285 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, stru
 }
 /* TODO: Remove export when modeset code has been moved over */
 EXPORT_SYMBOL(drm_client_find_modeset);
+
+/**
+ * drm_client_panel_rotation() - Check panel orientation
+ * @modeset: DRM modeset
+ * @rotation: Returned rotation value
+ *
+ * This function checks if the primary plane in @modeset can hw rotate to match
+ * the panel orientation on its connector.
+ *
+ * Note: Currently only 0 and 180 degrees are supported.
+ *
+ * Return:
+ * True if the plane can do the rotation, false otherwise.
+ */
+bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
+{
+	struct drm_connector *connector = modeset->connectors[0];
+	struct drm_plane *plane = modeset->crtc->primary;
+	u64 valid_mask = 0;
+	unsigned int i;
+
+	if (!modeset->num_connectors)
+		return false;
+
+	switch (connector->display_info.panel_orientation) {
+	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
+		*rotation = DRM_MODE_ROTATE_180;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
+		*rotation = DRM_MODE_ROTATE_90;
+		break;
+	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
+		*rotation = DRM_MODE_ROTATE_270;
+		break;
+	default:
+		*rotation = DRM_MODE_ROTATE_0;
+	}
+
+	/*
+	 * TODO: support 90 / 270 degree hardware rotation,
+	 * depending on the hardware this may require the framebuffer
+	 * to be in a specific tiling format.
+	 */
+	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
+		return false;
+
+	for (i = 0; i < plane->rotation_property->num_values; i++)
+		valid_mask |= (1ULL << plane->rotation_property->values[i]);
+
+	if (!(*rotation & valid_mask))
+		return false;
+
+	return true;
+}
+
+static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
+{
+	struct drm_device *dev = client->dev;
+	struct drm_plane_state *plane_state;
+	struct drm_plane *plane;
+	struct drm_atomic_state *state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_mode_set *mode_set;
+	int ret;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state) {
+		ret = -ENOMEM;
+		goto out_ctx;
+	}
+
+	state->acquire_ctx = &ctx;
+retry:
+	drm_for_each_plane(plane, dev) {
+		plane_state = drm_atomic_get_plane_state(state, plane);
+		if (IS_ERR(plane_state)) {
+			ret = PTR_ERR(plane_state);
+			goto out_state;
+		}
+
+		plane_state->rotation = DRM_MODE_ROTATE_0;
+
+		/* disable non-primary: */
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			continue;
+
+		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
+		if (ret != 0)
+			goto out_state;
+	}
+
+	drm_client_for_each_modeset(mode_set, client) {
+		struct drm_plane *primary = mode_set->crtc->primary;
+		unsigned int rotation;
+
+		if (drm_client_panel_rotation(mode_set, &rotation)) {
+			/* Cannot fail as we've already gotten the plane state above */
+			plane_state = drm_atomic_get_new_plane_state(state, primary);
+			plane_state->rotation = rotation;
+		}
+
+		ret = __drm_atomic_helper_set_config(mode_set, state);
+		if (ret != 0)
+			goto out_state;
+
+		/*
+		 * __drm_atomic_helper_set_config() sets active when a
+		 * mode is set, unconditionally clear it if we force DPMS off
+		 */
+		if (!active) {
+			struct drm_crtc *crtc = mode_set->crtc;
+			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+			crtc_state->active = false;
+		}
+	}
+
+	ret = drm_atomic_commit(state);
+
+out_state:
+	if (ret == -EDEADLK)
+		goto backoff;
+
+	drm_atomic_state_put(state);
+out_ctx:
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	return ret;
+
+backoff:
+	drm_atomic_state_clear(state);
+	drm_modeset_backoff(&ctx);
+
+	goto retry;
+}
+
+static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
+{
+	struct drm_device *dev = client->dev;
+	struct drm_mode_set *mode_set;
+	struct drm_plane *plane;
+	int ret = 0;
+
+	drm_modeset_lock_all(dev);
+	drm_for_each_plane(plane, dev) {
+		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+			drm_plane_force_disable(plane);
+
+		if (plane->rotation_property)
+			drm_mode_plane_set_obj_prop(plane,
+						    plane->rotation_property,
+						    DRM_MODE_ROTATE_0);
+	}
+
+	drm_client_for_each_modeset(mode_set, client) {
+		struct drm_crtc *crtc = mode_set->crtc;
+
+		if (crtc->funcs->cursor_set2) {
+			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
+			if (ret)
+				goto out;
+		} else if (crtc->funcs->cursor_set) {
+			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
+			if (ret)
+				goto out;
+		}
+
+		ret = drm_mode_set_config_internal(mode_set);
+		if (ret)
+			goto out;
+	}
+out:
+	drm_modeset_unlock_all(dev);
+
+	return ret;
+}
+
+/**
+ * drm_client_modeset_commit_force() - Force commit CRTC configuration
+ * @client: DRM client
+ *
+ * Commit modeset configuration to crtcs without checking if there is a DRM master.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_commit_force(struct drm_client_dev *client)
+{
+	struct drm_device *dev = client->dev;
+	int ret;
+
+	mutex_lock(&client->modeset_mutex);
+	if (drm_drv_uses_atomic_modeset(dev))
+		ret = drm_client_modeset_commit_atomic(client, true);
+	else
+		ret = drm_client_modeset_commit_legacy(client);
+	mutex_unlock(&client->modeset_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_client_modeset_commit_force);
+
+/**
+ * drm_client_modeset_commit() - Commit CRTC configuration
+ * @client: DRM client
+ *
+ * Commit modeset configuration to crtcs.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_commit(struct drm_client_dev *client)
+{
+	struct drm_device *dev = client->dev;
+	int ret;
+
+	if (!drm_master_internal_acquire(dev))
+		return -EBUSY;
+
+	ret = drm_client_modeset_commit_force(client);
+
+	drm_master_internal_release(dev);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_client_modeset_commit);
+
+static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
+{
+	struct drm_device *dev = client->dev;
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	int j;
+
+	drm_modeset_lock_all(dev);
+	drm_client_for_each_modeset(modeset, client) {
+		if (!modeset->crtc->enabled)
+			continue;
+
+		for (j = 0; j < modeset->num_connectors; j++) {
+			connector = modeset->connectors[j];
+			connector->funcs->dpms(connector, dpms_mode);
+			drm_object_property_set_value(&connector->base,
+				dev->mode_config.dpms_property, dpms_mode);
+		}
+	}
+	drm_modeset_unlock_all(dev);
+}
+
+/**
+ * drm_client_modeset_dpms() - Set DPMS mode
+ * @client: DRM client
+ * @mode: DPMS mode
+ *
+ * Note: For atomic drivers @mode is reduced to on/off.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
+{
+	struct drm_device *dev = client->dev;
+	int ret = 0;
+
+	if (!drm_master_internal_acquire(dev))
+		return -EBUSY;
+
+	mutex_lock(&client->modeset_mutex);
+	if (drm_drv_uses_atomic_modeset(dev))
+		ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON);
+	else
+		drm_client_modeset_dpms_legacy(client, mode);
+	mutex_unlock(&client->modeset_mutex);
+
+	drm_master_internal_release(dev);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_client_modeset_dpms);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0229e187e6de..73fbcd748ddd 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -40,10 +40,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
 
-#include "drm_crtc_internal.h"
-#include "drm_crtc_helper_internal.h"
 #include "drm_internal.h"
 
 static bool drm_fbdev_emulation = true;
@@ -388,233 +385,6 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
-/**
- * drm_client_panel_rotation() - Check panel orientation
- * @modeset: DRM modeset
- * @rotation: Returned rotation value
- *
- * This function checks if the primary plane in @modeset can hw rotate to match
- * the panel orientation on its connector.
- *
- * Note: Currently only 0 and 180 degrees are supported.
- *
- * Return:
- * True if the plane can do the rotation, false otherwise.
- */
-bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
-{
-	struct drm_connector *connector = modeset->connectors[0];
-	struct drm_plane *plane = modeset->crtc->primary;
-	u64 valid_mask = 0;
-	unsigned int i;
-
-	if (!modeset->num_connectors)
-		return false;
-
-	switch (connector->display_info.panel_orientation) {
-	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
-		*rotation = DRM_MODE_ROTATE_180;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
-		*rotation = DRM_MODE_ROTATE_90;
-		break;
-	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
-		*rotation = DRM_MODE_ROTATE_270;
-		break;
-	default:
-		*rotation = DRM_MODE_ROTATE_0;
-	}
-
-	/*
-	 * TODO: support 90 / 270 degree hardware rotation,
-	 * depending on the hardware this may require the framebuffer
-	 * to be in a specific tiling format.
-	 */
-	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
-		return false;
-
-	for (i = 0; i < plane->rotation_property->num_values; i++)
-		valid_mask |= (1ULL << plane->rotation_property->values[i]);
-
-	if (!(*rotation & valid_mask))
-		return false;
-
-	return true;
-}
-
-static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
-{
-	struct drm_device *dev = client->dev;
-	struct drm_plane_state *plane_state;
-	struct drm_plane *plane;
-	struct drm_atomic_state *state;
-	struct drm_modeset_acquire_ctx ctx;
-	struct drm_mode_set *mode_set;
-	int ret;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	state = drm_atomic_state_alloc(dev);
-	if (!state) {
-		ret = -ENOMEM;
-		goto out_ctx;
-	}
-
-	state->acquire_ctx = &ctx;
-retry:
-	drm_for_each_plane(plane, dev) {
-		plane_state = drm_atomic_get_plane_state(state, plane);
-		if (IS_ERR(plane_state)) {
-			ret = PTR_ERR(plane_state);
-			goto out_state;
-		}
-
-		plane_state->rotation = DRM_MODE_ROTATE_0;
-
-		/* disable non-primary: */
-		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
-			continue;
-
-		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
-		if (ret != 0)
-			goto out_state;
-	}
-
-	drm_client_for_each_modeset(mode_set, client) {
-		struct drm_plane *primary = mode_set->crtc->primary;
-		unsigned int rotation;
-
-		if (drm_client_panel_rotation(mode_set, &rotation)) {
-			/* Cannot fail as we've already gotten the plane state above */
-			plane_state = drm_atomic_get_new_plane_state(state, primary);
-			plane_state->rotation = rotation;
-		}
-
-		ret = __drm_atomic_helper_set_config(mode_set, state);
-		if (ret != 0)
-			goto out_state;
-
-		/*
-		 * __drm_atomic_helper_set_config() sets active when a
-		 * mode is set, unconditionally clear it if we force DPMS off
-		 */
-		if (!active) {
-			struct drm_crtc *crtc = mode_set->crtc;
-			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
-
-			crtc_state->active = false;
-		}
-	}
-
-	ret = drm_atomic_commit(state);
-
-out_state:
-	if (ret == -EDEADLK)
-		goto backoff;
-
-	drm_atomic_state_put(state);
-out_ctx:
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
-
-	return ret;
-
-backoff:
-	drm_atomic_state_clear(state);
-	drm_modeset_backoff(&ctx);
-
-	goto retry;
-}
-
-static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
-{
-	struct drm_device *dev = client->dev;
-	struct drm_mode_set *mode_set;
-	struct drm_plane *plane;
-	int ret = 0;
-
-	drm_modeset_lock_all(dev);
-	drm_for_each_plane(plane, dev) {
-		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
-			drm_plane_force_disable(plane);
-
-		if (plane->rotation_property)
-			drm_mode_plane_set_obj_prop(plane,
-						    plane->rotation_property,
-						    DRM_MODE_ROTATE_0);
-	}
-
-	drm_client_for_each_modeset(mode_set, client) {
-		struct drm_crtc *crtc = mode_set->crtc;
-
-		if (crtc->funcs->cursor_set2) {
-			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
-			if (ret)
-				goto out;
-		} else if (crtc->funcs->cursor_set) {
-			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
-			if (ret)
-				goto out;
-		}
-
-		ret = drm_mode_set_config_internal(mode_set);
-		if (ret)
-			goto out;
-	}
-out:
-	drm_modeset_unlock_all(dev);
-
-	return ret;
-}
-
-/**
- * drm_client_modeset_commit_force() - Force commit CRTC configuration
- * @client: DRM client
- *
- * Commit modeset configuration to crtcs without checking if there is a DRM master.
- *
- * Returns:
- * Zero on success or negative error code on failure.
- */
-int drm_client_modeset_commit_force(struct drm_client_dev *client)
-{
-	struct drm_device *dev = client->dev;
-	int ret;
-
-	mutex_lock(&client->modeset_mutex);
-	if (drm_drv_uses_atomic_modeset(dev))
-		ret = drm_client_modeset_commit_atomic(client, true);
-	else
-		ret = drm_client_modeset_commit_legacy(client);
-	mutex_unlock(&client->modeset_mutex);
-
-	return ret;
-}
-
-/**
- * drm_client_modeset_commit() - Commit CRTC configuration
- * @client: DRM client
- *
- * Commit modeset configuration to crtcs.
- *
- * Returns:
- * Zero on success or negative error code on failure.
- */
-int drm_client_modeset_commit(struct drm_client_dev *client)
-{
-	struct drm_device *dev = client->dev;
-	int ret;
-
-	if (!drm_master_internal_acquire(dev))
-		return -EBUSY;
-
-	ret = drm_client_modeset_commit_force(client);
-
-	drm_master_internal_release(dev);
-
-	return ret;
-}
-
 /**
  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
  * @fb_helper: driver-allocated fbdev helper, can be NULL
@@ -704,58 +474,6 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
-{
-	struct drm_device *dev = client->dev;
-	struct drm_connector *connector;
-	struct drm_mode_set *modeset;
-	int j;
-
-	drm_modeset_lock_all(dev);
-	drm_client_for_each_modeset(modeset, client) {
-		if (!modeset->crtc->enabled)
-			continue;
-
-		for (j = 0; j < modeset->num_connectors; j++) {
-			connector = modeset->connectors[j];
-			connector->funcs->dpms(connector, dpms_mode);
-			drm_object_property_set_value(&connector->base,
-				dev->mode_config.dpms_property, dpms_mode);
-		}
-	}
-	drm_modeset_unlock_all(dev);
-}
-
-/**
- * drm_client_modeset_dpms() - Set DPMS mode
- * @client: DRM client
- * @mode: DPMS mode
- *
- * Note: For atomic drivers @mode is reduced to on/off.
- *
- * Returns:
- * Zero on success or negative error code on failure.
- */
-int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
-{
-	struct drm_device *dev = client->dev;
-	int ret = 0;
-
-	if (!drm_master_internal_acquire(dev))
-		return -EBUSY;
-
-	mutex_lock(&client->modeset_mutex);
-	if (drm_drv_uses_atomic_modeset(dev))
-		ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON);
-	else
-		drm_client_modeset_dpms_legacy(client, mode);
-	mutex_unlock(&client->modeset_mutex);
-
-	drm_master_internal_release(dev);
-
-	return ret;
-}
-
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 858c8be70870..64b725b318f2 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -154,6 +154,10 @@ int drm_client_modeset_create(struct drm_client_dev *client);
 void drm_client_modeset_free(struct drm_client_dev *client);
 void drm_client_modeset_release(struct drm_client_dev *client);
 struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
+bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
+int drm_client_modeset_commit_force(struct drm_client_dev *client);
+int drm_client_modeset_commit(struct drm_client_dev *client);
+int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
 
 /**
  * drm_client_for_each_modeset() - Iterate over client modesets
-- 
2.20.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (7 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 08/12] drm/fb-helper: Move " Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  9:42   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 10/12] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx

All drivers add all their connectors so there's no need to keep around an
array of available connectors.

Rename functions which signature is changed since they will be moved to
drm_client in a later patch.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---

checkpatch complains, but I'm unable to satisfy it:

ERROR: Macros with complex values should be enclosed in parentheses
#941: FILE: include/drm/drm_client.h:181:
+#define drm_client_for_each_connector_iter(connector, iter) \
+       drm_for_each_connector_iter(connector, iter) \
+               if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)

 Documentation/gpu/todo.rst      |   3 +
 drivers/gpu/drm/drm_fb_helper.c | 498 ++++++++++----------------------
 include/drm/drm_client.h        |  15 +
 include/drm/drm_fb_helper.h     |  80 ++---
 4 files changed, 192 insertions(+), 404 deletions(-)

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 8fa08b5feab7..f6cdd1c26788 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -306,6 +306,9 @@ drm_fb_helper cleanup tasks
 - The max connector argument for drm_fb_helper_init() and
   drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
 
+- The helper doesn't keep an array of connectors anymore so these can be
+  removed: drm_fb_helper_single_add_all_connectors(),
+  drm_fb_helper_add_one_connector() and drm_fb_helper_remove_one_connector().
 
 Core refactorings
 =================
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 73fbcd748ddd..e13026724b2c 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -90,12 +90,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it
  * down by calling drm_fb_helper_fbdev_teardown().
  *
- * Drivers that need to handle connector hotplugging (e.g. dp mst) can't use
- * the setup helper and will need to do the whole four-step setup process with
- * drm_fb_helper_prepare(), drm_fb_helper_init(),
- * drm_fb_helper_single_add_all_connectors(), enable hotplugging and
- * drm_fb_helper_initial_config() to avoid a possible race window.
- *
  * At runtime drivers should restore the fbdev console by using
  * drm_fb_helper_lastclose() as their &drm_driver.lastclose callback.
  * They should also notify the fb helper code from updates to the output
@@ -118,8 +112,7 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * encoders and connectors. To finish up the fbdev helper initialization, the
  * drm_fb_helper_init() function is called. To probe for all attached displays
  * and set up an initial configuration using the detected hardware, drivers
- * should call drm_fb_helper_single_add_all_connectors() followed by
- * drm_fb_helper_initial_config().
+ * should call drm_fb_helper_initial_config().
  *
  * If &drm_framebuffer_funcs.dirty is set, the
  * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will
@@ -132,165 +125,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
  * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()).
  */
 
-#define drm_fb_helper_for_each_connector(fbh, i__) \
-	for (({ lockdep_assert_held(&(fbh)->lock); }), \
-	     i__ = 0; i__ < (fbh)->connector_count; i__++)
-
-static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-					     struct drm_connector *connector)
-{
-	struct drm_fb_helper_connector *fb_conn;
-	struct drm_fb_helper_connector **temp;
-	unsigned int count;
-
-	if (!drm_fbdev_emulation)
-		return 0;
-
-	lockdep_assert_held(&fb_helper->lock);
-
-	count = fb_helper->connector_count + 1;
-
-	if (count > fb_helper->connector_info_alloc_count) {
-		size_t size = count * sizeof(fb_conn);
-
-		temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL);
-		if (!temp)
-			return -ENOMEM;
-
-		fb_helper->connector_info_alloc_count = count;
-		fb_helper->connector_info = temp;
-	}
-
-	fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL);
-	if (!fb_conn)
-		return -ENOMEM;
-
-	drm_connector_get(connector);
-	fb_conn->connector = connector;
-	fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
-
-	return 0;
-}
-
-int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-				    struct drm_connector *connector)
-{
-	int err;
-
-	if (!fb_helper)
-		return 0;
-
-	mutex_lock(&fb_helper->lock);
-	err = __drm_fb_helper_add_one_connector(fb_helper, connector);
-	mutex_unlock(&fb_helper->lock);
-
-	return err;
-}
-EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
-
-/**
- * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
- * 					       emulation helper
- * @fb_helper: fbdev initialized with drm_fb_helper_init, can be NULL
- *
- * This functions adds all the available connectors for use with the given
- * fb_helper. This is a separate step to allow drivers to freely assign
- * connectors to the fbdev, e.g. if some are reserved for special purposes or
- * not adequate to be used for the fbcon.
- *
- * This function is protected against concurrent connector hotadds/removals
- * using drm_fb_helper_add_one_connector() and
- * drm_fb_helper_remove_one_connector().
- */
-int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
-{
-	struct drm_device *dev;
-	struct drm_connector *connector;
-	struct drm_connector_list_iter conn_iter;
-	int i, ret = 0;
-
-	if (!drm_fbdev_emulation || !fb_helper)
-		return 0;
-
-	dev = fb_helper->dev;
-
-	mutex_lock(&fb_helper->lock);
-	drm_connector_list_iter_begin(dev, &conn_iter);
-	drm_for_each_connector_iter(connector, &conn_iter) {
-		if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
-			continue;
-
-		ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
-		if (ret)
-			goto fail;
-	}
-	goto out;
-
-fail:
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_fb_helper_connector *fb_helper_connector =
-			fb_helper->connector_info[i];
-
-		drm_connector_put(fb_helper_connector->connector);
-
-		kfree(fb_helper_connector);
-		fb_helper->connector_info[i] = NULL;
-	}
-	fb_helper->connector_count = 0;
-out:
-	drm_connector_list_iter_end(&conn_iter);
-	mutex_unlock(&fb_helper->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
-
-static int __drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-						struct drm_connector *connector)
-{
-	struct drm_fb_helper_connector *fb_helper_connector;
-	int i, j;
-
-	if (!drm_fbdev_emulation)
-		return 0;
-
-	lockdep_assert_held(&fb_helper->lock);
-
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		if (fb_helper->connector_info[i]->connector == connector)
-			break;
-	}
-
-	if (i == fb_helper->connector_count)
-		return -EINVAL;
-	fb_helper_connector = fb_helper->connector_info[i];
-	drm_connector_put(fb_helper_connector->connector);
-
-	for (j = i + 1; j < fb_helper->connector_count; j++)
-		fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
-
-	fb_helper->connector_count--;
-	kfree(fb_helper_connector);
-
-	return 0;
-}
-
-int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-				       struct drm_connector *connector)
-{
-	int err;
-
-	if (!fb_helper)
-		return 0;
-
-	mutex_lock(&fb_helper->lock);
-	err = __drm_fb_helper_remove_one_connector(fb_helper, connector);
-	mutex_unlock(&fb_helper->lock);
-
-	return err;
-}
-EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
-
 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
 {
 	uint16_t *r_base, *g_base, *b_base;
@@ -628,20 +462,9 @@ int drm_fb_helper_init(struct drm_device *dev,
 			return ret;
 	}
 
-	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-	if (!fb_helper->connector_info)
-		goto out_free;
-
-	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
-	fb_helper->connector_count = 0;
-
 	dev->fb_helper = fb_helper;
 
 	return 0;
-out_free:
-	drm_client_modeset_free(&fb_helper->client);
-
-	return -ENOMEM;
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
 
@@ -716,7 +539,6 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 {
 	struct fb_info *info;
-	int i;
 
 	if (!fb_helper)
 		return;
@@ -751,12 +573,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 		drm_client_modeset_release(&fb_helper->client);
 		drm_client_modeset_free(&fb_helper->client);
 	}
-
-	for (i = 0; i < fb_helper->connector_count; i++) {
-		drm_connector_put(fb_helper->connector_info[i]->connector);
-		kfree(fb_helper->connector_info[i]);
-	}
-	kfree(fb_helper->connector_info);
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
@@ -1635,8 +1451,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	struct drm_client_dev *client = &fb_helper->client;
 	int ret = 0;
 	int crtc_count = 0;
-	int i;
+	struct drm_connector_list_iter conn_iter;
 	struct drm_fb_helper_surface_size sizes;
+	struct drm_connector *connector;
 	struct drm_mode_set *mode_set;
 	int best_depth = 0;
 
@@ -1653,11 +1470,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	if (preferred_bpp != sizes.surface_bpp)
 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
+	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
 		struct drm_cmdline_mode *cmdline_mode;
 
-		cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+		cmdline_mode = &connector->cmdline_mode;
 
 		if (cmdline_mode->bpp_specified) {
 			switch (cmdline_mode->bpp) {
@@ -1682,6 +1499,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 			break;
 		}
 	}
+	drm_connector_list_iter_end(&conn_iter);
 
 	/*
 	 * If we run into a situation where, for example, the primary plane
@@ -1866,26 +1684,12 @@ void drm_fb_helper_fill_info(struct fb_info *info,
 }
 EXPORT_SYMBOL(drm_fb_helper_fill_info);
 
-static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
-						uint32_t maxX,
-						uint32_t maxY)
-{
-	struct drm_connector *connector;
-	int i, count = 0;
-
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
-		count += connector->funcs->fill_modes(connector, maxX, maxY);
-	}
-
-	return count;
-}
-
-struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
+static struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
 {
 	struct drm_display_mode *mode;
 
-	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		if (mode->hdisplay > width ||
 		    mode->vdisplay > height)
 			continue;
@@ -1894,20 +1698,15 @@ struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *
 	}
 	return NULL;
 }
-EXPORT_SYMBOL(drm_has_preferred_mode);
 
-static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
-{
-	return fb_connector->connector->cmdline_mode.specified;
-}
-
-struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn)
+static struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector)
 {
 	struct drm_cmdline_mode *cmdline_mode;
 	struct drm_display_mode *mode;
 	bool prefer_non_interlace;
 
-	cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+	cmdline_mode = &connector->cmdline_mode;
 	if (cmdline_mode->specified == false)
 		return NULL;
 
@@ -1919,7 +1718,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
 
 	prefer_non_interlace = !cmdline_mode->interlace;
 again:
-	list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+	list_for_each_entry(mode, &connector->modes, head) {
 		/* check width/height */
 		if (mode->hdisplay != cmdline_mode->xres ||
 		    mode->vdisplay != cmdline_mode->yres)
@@ -1946,12 +1745,11 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
 	}
 
 create_mode:
-	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
-						 cmdline_mode);
-	list_add(&mode->head, &fb_helper_conn->connector->modes);
+	mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
+	list_add(&mode->head, &connector->modes);
+
 	return mode;
 }
-EXPORT_SYMBOL(drm_pick_cmdline_mode);
 
 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 {
@@ -1968,15 +1766,16 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 	return enable;
 }
 
-static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
-				  bool *enabled)
+static void drm_client_connectors_enabled(struct drm_connector **connectors,
+					  unsigned int connector_count,
+					  bool *enabled)
 {
 	bool any_enabled = false;
 	struct drm_connector *connector;
 	int i = 0;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
 		enabled[i] = drm_connector_enabled(connector, true);
 		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
 			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
@@ -1987,28 +1786,27 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
 	if (any_enabled)
 		return;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
-		enabled[i] = drm_connector_enabled(connector, false);
-	}
+	for (i = 0; i < connector_count; i++)
+		enabled[i] = drm_connector_enabled(connectors[i], false);
 }
 
-static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
-			      struct drm_display_mode **modes,
-			      struct drm_fb_offset *offsets,
-			      bool *enabled, int width, int height)
+static bool drm_client_target_cloned(struct drm_device *dev,
+				     struct drm_connector **connectors,
+				     unsigned int connector_count,
+				     struct drm_display_mode **modes,
+				     struct drm_fb_offset *offsets,
+				     bool *enabled, int width, int height)
 {
 	int count, i, j;
 	bool can_clone = false;
-	struct drm_fb_helper_connector *fb_helper_conn;
 	struct drm_display_mode *dmt_mode, *mode;
 
 	/* only contemplate cloning in the single crtc case */
-	if (fb_helper->dev->mode_config.num_crtc > 1)
+	if (dev->mode_config.num_crtc > 1)
 		return false;
 
 	count = 0;
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (enabled[i])
 			count++;
 	}
@@ -2019,11 +1817,10 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 
 	/* check the command line or if nothing common pick 1024x768 */
 	can_clone = true;
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (!enabled[i])
 			continue;
-		fb_helper_conn = fb_helper->connector_info[i];
-		modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
+		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
 		if (!modes[i]) {
 			can_clone = false;
 			break;
@@ -2047,14 +1844,13 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 
 	/* try and find a 1024x768 mode on each connector */
 	can_clone = true;
-	dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
+	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (!enabled[i])
 			continue;
 
-		fb_helper_conn = fb_helper->connector_info[i];
-		list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+		list_for_each_entry(mode, &connectors[i]->modes, head) {
 			if (drm_mode_match(mode, dmt_mode,
 					   DRM_MODE_MATCH_TIMINGS |
 					   DRM_MODE_MATCH_CLOCK |
@@ -2074,30 +1870,31 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 	return false;
 }
 
-static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
-				struct drm_display_mode **modes,
-				struct drm_fb_offset *offsets,
-				int idx,
-				int h_idx, int v_idx)
+static int drm_client_get_tile_offsets(struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_display_mode **modes,
+				       struct drm_fb_offset *offsets,
+				       int idx,
+				       int h_idx, int v_idx)
 {
-	struct drm_fb_helper_connector *fb_helper_conn;
+	struct drm_connector *connector;
 	int i;
 	int hoffset = 0, voffset = 0;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		fb_helper_conn = fb_helper->connector_info[i];
-		if (!fb_helper_conn->connector->has_tile)
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+		if (!connector->has_tile)
 			continue;
 
 		if (!modes[i] && (h_idx || v_idx)) {
 			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
-				      fb_helper_conn->connector->base.id);
+				      connector->base.id);
 			continue;
 		}
-		if (fb_helper_conn->connector->tile_h_loc < h_idx)
+		if (connector->tile_h_loc < h_idx)
 			hoffset += modes[i]->hdisplay;
 
-		if (fb_helper_conn->connector->tile_v_loc < v_idx)
+		if (connector->tile_v_loc < v_idx)
 			voffset += modes[i]->vdisplay;
 	}
 	offsets[idx].x = hoffset;
@@ -2106,20 +1903,21 @@ static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
 	return 0;
 }
 
-static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
-				 struct drm_display_mode **modes,
-				 struct drm_fb_offset *offsets,
-				 bool *enabled, int width, int height)
+static bool drm_client_target_preferred(struct drm_connector **connectors,
+					unsigned int connector_count,
+					struct drm_display_mode **modes,
+					struct drm_fb_offset *offsets,
+					bool *enabled, int width, int height)
 {
-	struct drm_fb_helper_connector *fb_helper_conn;
-	const u64 mask = BIT_ULL(fb_helper->connector_count) - 1;
+	const u64 mask = BIT_ULL(connector_count) - 1;
+	struct drm_connector *connector;
 	u64 conn_configured = 0;
 	int tile_pass = 0;
 	int i;
 
 retry:
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		fb_helper_conn = fb_helper->connector_info[i];
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
 
 		if (conn_configured & BIT_ULL(i))
 			continue;
@@ -2130,17 +1928,17 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 		}
 
 		/* first pass over all the untiled connectors */
-		if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
+		if (tile_pass == 0 && connector->has_tile)
 			continue;
 
 		if (tile_pass == 1) {
-			if (fb_helper_conn->connector->tile_h_loc != 0 ||
-			    fb_helper_conn->connector->tile_v_loc != 0)
+			if (connector->tile_h_loc != 0 ||
+			    connector->tile_v_loc != 0)
 				continue;
 
 		} else {
-			if (fb_helper_conn->connector->tile_h_loc != tile_pass - 1 &&
-			    fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
+			if (connector->tile_h_loc != tile_pass - 1 &&
+			    connector->tile_v_loc != tile_pass - 1)
 			/* if this tile_pass doesn't cover any of the tiles - keep going */
 				continue;
 
@@ -2148,22 +1946,22 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 			 * find the tile offsets for this pass - need to find
 			 * all tiles left and above
 			 */
-			drm_get_tile_offsets(fb_helper, modes, offsets,
-					     i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
+			drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
+						    connector->tile_h_loc, connector->tile_v_loc);
 		}
 		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
-			      fb_helper_conn->connector->base.id);
+			      connector->base.id);
 
 		/* got for command line mode first */
-		modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
 		if (!modes[i]) {
 			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
-				      fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
-			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
+				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
 		}
 		/* No preferred modes, pick one off the list */
-		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
-			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			list_for_each_entry(modes[i], &connector->modes, head)
 				break;
 		}
 		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
@@ -2192,40 +1990,41 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
 	return false;
 }
 
-static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
-			  struct drm_crtc **best_crtcs,
-			  struct drm_display_mode **modes,
-			  int n, int width, int height)
+static int drm_client_pick_crtcs(struct drm_client_dev *client,
+				 struct drm_connector **connectors,
+				 unsigned int connector_count,
+				 struct drm_crtc **best_crtcs,
+				 struct drm_display_mode **modes,
+				 int n, int width, int height)
 {
-	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_device *dev = client->dev;
 	struct drm_connector *connector;
 	int my_score, best_score, score;
 	struct drm_crtc **crtcs, *crtc;
 	struct drm_mode_set *modeset;
-	struct drm_fb_helper_connector *fb_helper_conn;
 	int o;
 
-	if (n == fb_helper->connector_count)
+	if (n == connector_count)
 		return 0;
 
-	fb_helper_conn = fb_helper->connector_info[n];
-	connector = fb_helper_conn->connector;
+	connector = connectors[n];
 
 	best_crtcs[n] = NULL;
-	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
+	best_score = drm_client_pick_crtcs(client, connectors, connector_count,
+					   best_crtcs, modes, n + 1, width, height);
 	if (modes[n] == NULL)
 		return best_score;
 
-	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
 	if (!crtcs)
 		return best_score;
 
 	my_score = 1;
 	if (connector->status == connector_status_connected)
 		my_score++;
-	if (drm_has_cmdline_mode(fb_helper_conn))
+	if (connector->cmdline_mode.specified)
 		my_score++;
-	if (drm_has_preferred_mode(fb_helper_conn, width, height))
+	if (drm_connector_has_preferred_mode(connector, width, height))
 		my_score++;
 
 	/*
@@ -2244,7 +2043,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 		if (o < n) {
 			/* ignore cloning unless only a single crtc */
-			if (fb_helper->dev->mode_config.num_crtc > 1)
+			if (dev->mode_config.num_crtc > 1)
 				continue;
 
 			if (!drm_mode_equal(modes[o], modes[n]))
@@ -2253,12 +2052,11 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 
 		crtcs[n] = crtc;
 		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
-		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
-						  width, height);
+		score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,
+							 crtcs, modes, n + 1, width, height);
 		if (score > best_score) {
 			best_score = score;
-			memcpy(best_crtcs, crtcs,
-			       fb_helper->connector_count * sizeof(*crtcs));
+			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
 		}
 	}
 
@@ -2267,15 +2065,17 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 }
 
 /* Try to read the BIOS display configuration and use it for the initial config */
-static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
-					  struct drm_crtc **crtcs,
-					  struct drm_display_mode **modes,
-					  struct drm_fb_offset *offsets,
-					  bool *enabled, int width, int height)
+static bool drm_client_firmware_config(struct drm_client_dev *client,
+				       struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_crtc **crtcs,
+				       struct drm_display_mode **modes,
+				       struct drm_fb_offset *offsets,
+				       bool *enabled, int width, int height)
 {
-	struct drm_device *dev = fb_helper->dev;
-	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
+	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
 	unsigned long conn_configured, conn_seq;
+	struct drm_device *dev = client->dev;
 	int i, j;
 	bool *save_enabled;
 	bool fallback = true, ret = true;
@@ -2297,13 +2097,11 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 	conn_configured = 0;
 retry:
 	for (i = 0; i < count; i++) {
-		struct drm_fb_helper_connector *fb_conn;
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
 		struct drm_crtc *new_crtc;
 
-		fb_conn = fb_helper->connector_info[i];
-		connector = fb_conn->connector;
+		connector = connectors[i];
 
 		if (conn_configured & BIT(i))
 			continue;
@@ -2361,14 +2159,13 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 			      connector->name);
 
 		/* go for command line mode first */
-		modes[i] = drm_pick_cmdline_mode(fb_conn);
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
 
 		/* try for preferred next */
 		if (!modes[i]) {
 			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
 				      connector->name, connector->has_tile);
-			modes[i] = drm_has_preferred_mode(fb_conn, width,
-							  height);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
 		}
 
 		/* No preferred mode marked by the EDID? Are there any modes? */
@@ -2445,8 +2242,12 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
+	struct drm_connector *connector, **connectors = NULL;
 	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_connector_list_iter conn_iter;
 	struct drm_device *dev = fb_helper->dev;
+	unsigned int total_modes_count = 0;
+	unsigned int connector_count = 0;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
 	struct drm_crtc **crtcs;
@@ -2454,16 +2255,28 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	int i;
 
 	DRM_DEBUG_KMS("\n");
-	/* prevent concurrent modification of connector_count by hotplug */
-	lockdep_assert_held(&fb_helper->lock);
 
-	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
-	modes = kcalloc(fb_helper->connector_count,
-			sizeof(struct drm_display_mode *), GFP_KERNEL);
-	offsets = kcalloc(fb_helper->connector_count,
-			  sizeof(struct drm_fb_offset), GFP_KERNEL);
-	enabled = kcalloc(fb_helper->connector_count,
-			  sizeof(bool), GFP_KERNEL);
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
+		struct drm_connector **tmp;
+
+		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
+		if (!tmp)
+			goto free_connectors;
+
+		connectors = tmp;
+		drm_connector_get(connector);
+		connectors[connector_count++] = connector;
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	if (!connector_count)
+		return;
+
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
+	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
 	if (!crtcs || !modes || !enabled || !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
 		goto out;
@@ -2472,40 +2285,42 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	mutex_lock(&client->modeset_mutex);
 
 	mutex_lock(&fb_helper->dev->mode_config.mutex);
-	if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
+	for (i = 0; i < connector_count; i++)
+		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
+	if (!total_modes_count)
 		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-	drm_enable_connectors(fb_helper, enabled);
+	drm_client_connectors_enabled(connectors, connector_count, enabled);
 
-	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
-					   enabled, width, height)) {
-		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
-		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
-		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
+	if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,
+					modes, offsets, enabled, width, height)) {
+		memset(modes, 0, connector_count * sizeof(*modes));
+		memset(crtcs, 0, connector_count * sizeof(*crtcs));
+		memset(offsets, 0, connector_count * sizeof(*offsets));
 
-		if (!drm_target_cloned(fb_helper, modes, offsets,
-				       enabled, width, height) &&
-		    !drm_target_preferred(fb_helper, modes, offsets,
-					  enabled, width, height))
+		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
+					      offsets, enabled, width, height) &&
+		    !drm_client_target_preferred(connectors, connector_count, modes,
+						 offsets, enabled, width, height))
 			DRM_ERROR("Unable to find initial modes\n");
 
 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
 			      width, height);
 
-		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
+		drm_client_pick_crtcs(client, connectors, connector_count,
+				      crtcs, modes, 0, width, height);
 	}
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
 	drm_client_modeset_release(client);
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_crtc *crtc = crtcs[i];
 		struct drm_fb_offset *offset = &offsets[i];
 
 		if (mode && crtc) {
 			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
-			struct drm_connector *connector =
-				fb_helper->connector_info[i]->connector;
+			struct drm_connector *connector = connectors[i];
 
 			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
 				      mode->name, crtc->base.id, offset->x, offset->y);
@@ -2528,6 +2343,10 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	kfree(modes);
 	kfree(offsets);
 	kfree(enabled);
+free_connectors:
+	for (i = 0; i < connector_count; i++)
+		drm_connector_put(connectors[i]);
+	kfree(connectors);
 }
 
 /*
@@ -2540,10 +2359,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
 	struct drm_client_dev *client = &fb_helper->client;
+	struct drm_connector_list_iter conn_iter;
 	struct fb_info *info = fb_helper->fbdev;
 	unsigned int rotation, sw_rotations = 0;
+	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
-	int i;
 
 	mutex_lock(&client->modeset_mutex);
 	drm_client_for_each_modeset(modeset, client) {
@@ -2560,10 +2380,8 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 	}
 	mutex_unlock(&client->modeset_mutex);
 
-	mutex_lock(&fb_helper->dev->mode_config.mutex);
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_connector *connector =
-					fb_helper->connector_info[i]->connector;
+	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
 
 		/* use first connected connector for the physical dimensions */
 		if (connector->status == connector_status_connected) {
@@ -2572,7 +2390,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 			break;
 		}
 	}
-	mutex_unlock(&fb_helper->dev->mode_config.mutex);
+	drm_connector_list_iter_end(&conn_iter);
 
 	switch (sw_rotations) {
 	case DRM_MODE_ROTATE_0:
@@ -2811,12 +2629,6 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
 		return ret;
 	}
 
-	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-	if (ret < 0) {
-		DRM_DEV_ERROR(dev->dev, "fbdev: Failed to add connectors (ret=%d)\n", ret);
-		goto err_drm_fb_helper_fini;
-	}
-
 	if (!drm_drv_uses_atomic_modeset(dev))
 		drm_helper_disable_unused_functions(dev);
 
@@ -3122,10 +2934,6 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
 	if (ret)
 		goto err;
 
-	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-	if (ret)
-		goto err_cleanup;
-
 	if (!drm_drv_uses_atomic_modeset(dev))
 		drm_helper_disable_unused_functions(dev);
 
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 64b725b318f2..6bb5e0412877 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -6,6 +6,7 @@
 #include <linux/mutex.h>
 #include <linux/types.h>
 
+#include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 
 struct drm_client_dev;
@@ -167,6 +168,20 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
 #define drm_client_for_each_modeset(modeset, client) \
 	for (modeset = (client)->modesets; modeset && modeset->crtc; modeset++)
 
+/**
+ * drm_client_for_each_connector_iter - connector_list iterator macro
+ * @connector: &struct drm_connector pointer used as cursor
+ * @iter: &struct drm_connector_list_iter
+ *
+ * This iterates the connectors that are useable for internal clients (excludes
+ * writeback connectors).
+ *
+ * For more info see drm_for_each_connector_iter().
+ */
+#define drm_client_for_each_connector_iter(connector, iter) \
+	drm_for_each_connector_iter(connector, iter) \
+		if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+
 int drm_client_debugfs_init(struct drm_minor *minor);
 
 #endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 8d0ddea74a9e..10481178e7e0 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -96,16 +96,10 @@ struct drm_fb_helper_funcs {
 			struct drm_fb_helper_surface_size *sizes);
 };
 
-struct drm_fb_helper_connector {
-	struct drm_connector *connector;
-};
-
 /**
  * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
  * @fb: Scanout framebuffer object
  * @dev: DRM device
- * @connector_count: number of connected connectors
- * @connector_info_alloc_count: size of connector_info
  * @funcs: driver callbacks for fb helper
  * @fbdev: emulated fbdev device info struct
  * @pseudo_palette: fake palette of 16 colors
@@ -137,15 +131,6 @@ struct drm_fb_helper {
 
 	struct drm_framebuffer *fb;
 	struct drm_device *dev;
-	int connector_count;
-	int connector_info_alloc_count;
-	/**
-	 * @connector_info:
-	 *
-	 * Array of per-connector information. Do not iterate directly, but use
-	 * drm_fb_helper_for_each_connector.
-	 */
-	struct drm_fb_helper_connector **connector_info;
 	const struct drm_fb_helper_funcs *funcs;
 	struct fb_info *fbdev;
 	u32 pseudo_palette[17];
@@ -285,18 +270,8 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
 
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
-int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_debug_enter(struct fb_info *info);
 int drm_fb_helper_debug_leave(struct fb_info *info);
-struct drm_display_mode *
-drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
-			int width, int height);
-struct drm_display_mode *
-drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn);
-
-int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector);
-int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-				       struct drm_connector *connector);
 
 int drm_fb_helper_fbdev_setup(struct drm_device *dev,
 			      struct drm_fb_helper *fb_helper,
@@ -471,12 +446,6 @@ static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper,
 	return 0;
 }
 
-static inline int
-drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
-{
-	return 0;
-}
-
 static inline int drm_fb_helper_debug_enter(struct fb_info *info)
 {
 	return 0;
@@ -487,34 +456,6 @@ static inline int drm_fb_helper_debug_leave(struct fb_info *info)
 	return 0;
 }
 
-static inline struct drm_display_mode *
-drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
-		       int width, int height)
-{
-	return NULL;
-}
-
-static inline struct drm_display_mode *
-drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
-		      int width, int height)
-{
-	return NULL;
-}
-
-static inline int
-drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-				struct drm_connector *connector)
-{
-	return 0;
-}
-
-static inline int
-drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-				   struct drm_connector *connector)
-{
-	return 0;
-}
-
 static inline int
 drm_fb_helper_fbdev_setup(struct drm_device *dev,
 			  struct drm_fb_helper *fb_helper,
@@ -556,6 +497,27 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
 
 #endif
 
+/* TODO: There's a todo entry to remove these three */
+static inline int
+drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
+{
+	return 0;
+}
+
+static inline int
+drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
+				struct drm_connector *connector)
+{
+	return 0;
+}
+
+static inline int
+drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
+				   struct drm_connector *connector)
+{
+	return 0;
+}
+
 /**
  * drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
  * @a: memory range, users of which are to be removed
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 10/12] drm/fb-helper: Prepare to move out modeset config code
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (8 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  9:43   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 11/12] drm/fb-helper: Move " Noralf Trønnes
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx

This prepares the modeset code so it can be moved out as-is in the next
patch.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 63 +++++++++++++++++++++++----------
 include/drm/drm_fb_helper.h     |  4 ---
 2 files changed, 45 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index e13026724b2c..9287ff4ae2d8 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -43,6 +43,10 @@
 
 #include "drm_internal.h"
 
+struct drm_client_offset {
+	int x, y;
+};
+
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
 MODULE_PARM_DESC(fbdev_emulation,
@@ -1794,7 +1798,7 @@ static bool drm_client_target_cloned(struct drm_device *dev,
 				     struct drm_connector **connectors,
 				     unsigned int connector_count,
 				     struct drm_display_mode **modes,
-				     struct drm_fb_offset *offsets,
+				     struct drm_client_offset *offsets,
 				     bool *enabled, int width, int height)
 {
 	int count, i, j;
@@ -1873,7 +1877,7 @@ static bool drm_client_target_cloned(struct drm_device *dev,
 static int drm_client_get_tile_offsets(struct drm_connector **connectors,
 				       unsigned int connector_count,
 				       struct drm_display_mode **modes,
-				       struct drm_fb_offset *offsets,
+				       struct drm_client_offset *offsets,
 				       int idx,
 				       int h_idx, int v_idx)
 {
@@ -1906,7 +1910,7 @@ static int drm_client_get_tile_offsets(struct drm_connector **connectors,
 static bool drm_client_target_preferred(struct drm_connector **connectors,
 					unsigned int connector_count,
 					struct drm_display_mode **modes,
-					struct drm_fb_offset *offsets,
+					struct drm_client_offset *offsets,
 					bool *enabled, int width, int height)
 {
 	const u64 mask = BIT_ULL(connector_count) - 1;
@@ -2070,7 +2074,7 @@ static bool drm_client_firmware_config(struct drm_client_dev *client,
 				       unsigned int connector_count,
 				       struct drm_crtc **crtcs,
 				       struct drm_display_mode **modes,
-				       struct drm_fb_offset *offsets,
+				       struct drm_client_offset *offsets,
 				       bool *enabled, int width, int height)
 {
 	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
@@ -2239,30 +2243,48 @@ static bool drm_client_firmware_config(struct drm_client_dev *client,
 	return ret;
 }
 
-static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
-			    u32 width, u32 height)
+/**
+ * drm_client_modeset_probe() - Probe for displays
+ * @client: DRM client
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function sets up display pipelines for enabled connectors and stores the
+ * config in the client's modeset array.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+
+int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height)
 {
 	struct drm_connector *connector, **connectors = NULL;
-	struct drm_client_dev *client = &fb_helper->client;
 	struct drm_connector_list_iter conn_iter;
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = client->dev;
 	unsigned int total_modes_count = 0;
+	struct drm_client_offset *offsets;
 	unsigned int connector_count = 0;
 	struct drm_display_mode **modes;
-	struct drm_fb_offset *offsets;
 	struct drm_crtc **crtcs;
+	int i, ret = 0;
 	bool *enabled;
-	int i;
 
 	DRM_DEBUG_KMS("\n");
 
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
 	drm_connector_list_iter_begin(dev, &conn_iter);
 	drm_client_for_each_connector_iter(connector, &conn_iter) {
 		struct drm_connector **tmp;
 
 		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
-		if (!tmp)
+		if (!tmp) {
+			ret = -ENOMEM;
 			goto free_connectors;
+		}
 
 		connectors = tmp;
 		drm_connector_get(connector);
@@ -2271,7 +2293,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	drm_connector_list_iter_end(&conn_iter);
 
 	if (!connector_count)
-		return;
+		return 0;
 
 	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
 	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
@@ -2279,12 +2301,13 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
 	if (!crtcs || !modes || !enabled || !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
+		ret = -ENOMEM;
 		goto out;
 	}
 
 	mutex_lock(&client->modeset_mutex);
 
-	mutex_lock(&fb_helper->dev->mode_config.mutex);
+	mutex_lock(&dev->mode_config.mutex);
 	for (i = 0; i < connector_count; i++)
 		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
 	if (!total_modes_count)
@@ -2309,14 +2332,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		drm_client_pick_crtcs(client, connectors, connector_count,
 				      crtcs, modes, 0, width, height);
 	}
-	mutex_unlock(&fb_helper->dev->mode_config.mutex);
+	mutex_unlock(&dev->mode_config.mutex);
 
 	drm_client_modeset_release(client);
 
 	for (i = 0; i < connector_count; i++) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_crtc *crtc = crtcs[i];
-		struct drm_fb_offset *offset = &offsets[i];
+		struct drm_client_offset *offset = &offsets[i];
 
 		if (mode && crtc) {
 			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
@@ -2326,8 +2349,10 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 				      mode->name, crtc->base.id, offset->x, offset->y);
 
 			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
-					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {
+				ret = -EINVAL;
 				break;
+			}
 
 			modeset->mode = drm_mode_duplicate(dev, mode);
 			drm_connector_get(connector);
@@ -2347,6 +2372,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	for (i = 0; i < connector_count; i++)
 		drm_connector_put(connectors[i]);
 	kfree(connectors);
+
+	return ret;
 }
 
 /*
@@ -2428,7 +2455,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
 	width = dev->mode_config.max_width;
 	height = dev->mode_config.max_height;
 
-	drm_setup_crtcs(fb_helper, width, height);
+	drm_client_modeset_probe(&fb_helper->client, width, height);
 	ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 	if (ret < 0) {
 		if (ret == -EAGAIN) {
@@ -2576,7 +2603,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
 	DRM_DEBUG_KMS("\n");
 
-	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
+	drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height);
 	drm_setup_crtcs_fb(fb_helper);
 	mutex_unlock(&fb_helper->lock);
 
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 10481178e7e0..80591bc02de7 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -42,10 +42,6 @@ enum mode_set_atomic {
 	ENTER_ATOMIC_MODE_SET,
 };
 
-struct drm_fb_offset {
-	int x, y;
-};
-
 /**
  * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
  * @fb_width: fbdev width
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 11/12] drm/fb-helper: Move out modeset config code
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (9 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 10/12] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-16  9:43   ` Maxime Ripard
  2019-04-07 16:52 ` [PATCH v2 12/12] drm/client: Hack: Add bootsplash example Noralf Trønnes
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx

No functional changes, just moving code as-is and fixing includes.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client_modeset.c | 703 ++++++++++++++++++++++++++-
 drivers/gpu/drm/drm_fb_helper.c      | 692 --------------------------
 include/drm/drm_client.h             |   4 +-
 3 files changed, 701 insertions(+), 698 deletions(-)

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index 94b52f97c06b..2a428ac00930 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -13,13 +13,22 @@
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_client.h>
+#include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_print.h>
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
+#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
+
+struct drm_client_offset {
+	int x, y;
+};
+
 /* Used by drm_client and drm_fb_helper */
 int drm_client_modeset_create(struct drm_client_dev *client)
 {
@@ -93,7 +102,8 @@ void drm_client_modeset_release(struct drm_client_dev *client)
 }
 EXPORT_SYMBOL(drm_client_modeset_release);
 
-struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
+static struct drm_mode_set *
+drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
 {
 	struct drm_mode_set *modeset;
 
@@ -103,8 +113,695 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, stru
 
 	return NULL;
 }
-/* TODO: Remove export when modeset code has been moved over */
-EXPORT_SYMBOL(drm_client_find_modeset);
+
+static struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
+{
+	struct drm_display_mode *mode;
+
+	list_for_each_entry(mode, &connector->modes, head) {
+		if (mode->hdisplay > width ||
+		    mode->vdisplay > height)
+			continue;
+		if (mode->type & DRM_MODE_TYPE_PREFERRED)
+			return mode;
+	}
+	return NULL;
+}
+
+static struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector)
+{
+	struct drm_cmdline_mode *cmdline_mode;
+	struct drm_display_mode *mode;
+	bool prefer_non_interlace;
+
+	cmdline_mode = &connector->cmdline_mode;
+	if (cmdline_mode->specified == false)
+		return NULL;
+
+	/* attempt to find a matching mode in the list of modes
+	 *  we have gotten so far, if not add a CVT mode that conforms
+	 */
+	if (cmdline_mode->rb || cmdline_mode->margins)
+		goto create_mode;
+
+	prefer_non_interlace = !cmdline_mode->interlace;
+again:
+	list_for_each_entry(mode, &connector->modes, head) {
+		/* check width/height */
+		if (mode->hdisplay != cmdline_mode->xres ||
+		    mode->vdisplay != cmdline_mode->yres)
+			continue;
+
+		if (cmdline_mode->refresh_specified) {
+			if (mode->vrefresh != cmdline_mode->refresh)
+				continue;
+		}
+
+		if (cmdline_mode->interlace) {
+			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
+				continue;
+		} else if (prefer_non_interlace) {
+			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+				continue;
+		}
+		return mode;
+	}
+
+	if (prefer_non_interlace) {
+		prefer_non_interlace = false;
+		goto again;
+	}
+
+create_mode:
+	mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
+	list_add(&mode->head, &connector->modes);
+
+	return mode;
+}
+
+static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
+{
+	bool enable;
+
+	if (connector->display_info.non_desktop)
+		return false;
+
+	if (strict)
+		enable = connector->status == connector_status_connected;
+	else
+		enable = connector->status != connector_status_disconnected;
+
+	return enable;
+}
+
+static void drm_client_connectors_enabled(struct drm_connector **connectors,
+					  unsigned int connector_count,
+					  bool *enabled)
+{
+	bool any_enabled = false;
+	struct drm_connector *connector;
+	int i = 0;
+
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+		enabled[i] = drm_connector_enabled(connector, true);
+		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
+			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
+
+		any_enabled |= enabled[i];
+	}
+
+	if (any_enabled)
+		return;
+
+	for (i = 0; i < connector_count; i++)
+		enabled[i] = drm_connector_enabled(connectors[i], false);
+}
+
+static bool drm_client_target_cloned(struct drm_device *dev,
+				     struct drm_connector **connectors,
+				     unsigned int connector_count,
+				     struct drm_display_mode **modes,
+				     struct drm_client_offset *offsets,
+				     bool *enabled, int width, int height)
+{
+	int count, i, j;
+	bool can_clone = false;
+	struct drm_display_mode *dmt_mode, *mode;
+
+	/* only contemplate cloning in the single crtc case */
+	if (dev->mode_config.num_crtc > 1)
+		return false;
+
+	count = 0;
+	for (i = 0; i < connector_count; i++) {
+		if (enabled[i])
+			count++;
+	}
+
+	/* only contemplate cloning if more than one connector is enabled */
+	if (count <= 1)
+		return false;
+
+	/* check the command line or if nothing common pick 1024x768 */
+	can_clone = true;
+	for (i = 0; i < connector_count; i++) {
+		if (!enabled[i])
+			continue;
+		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
+		if (!modes[i]) {
+			can_clone = false;
+			break;
+		}
+		for (j = 0; j < i; j++) {
+			if (!enabled[j])
+				continue;
+			if (!drm_mode_match(modes[j], modes[i],
+					    DRM_MODE_MATCH_TIMINGS |
+					    DRM_MODE_MATCH_CLOCK |
+					    DRM_MODE_MATCH_FLAGS |
+					    DRM_MODE_MATCH_3D_FLAGS))
+				can_clone = false;
+		}
+	}
+
+	if (can_clone) {
+		DRM_DEBUG_KMS("can clone using command line\n");
+		return true;
+	}
+
+	/* try and find a 1024x768 mode on each connector */
+	can_clone = true;
+	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
+
+	for (i = 0; i < connector_count; i++) {
+		if (!enabled[i])
+			continue;
+
+		list_for_each_entry(mode, &connectors[i]->modes, head) {
+			if (drm_mode_match(mode, dmt_mode,
+					   DRM_MODE_MATCH_TIMINGS |
+					   DRM_MODE_MATCH_CLOCK |
+					   DRM_MODE_MATCH_FLAGS |
+					   DRM_MODE_MATCH_3D_FLAGS))
+				modes[i] = mode;
+		}
+		if (!modes[i])
+			can_clone = false;
+	}
+
+	if (can_clone) {
+		DRM_DEBUG_KMS("can clone using 1024x768\n");
+		return true;
+	}
+	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
+	return false;
+}
+
+static int drm_client_get_tile_offsets(struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_display_mode **modes,
+				       struct drm_client_offset *offsets,
+				       int idx,
+				       int h_idx, int v_idx)
+{
+	struct drm_connector *connector;
+	int i;
+	int hoffset = 0, voffset = 0;
+
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+		if (!connector->has_tile)
+			continue;
+
+		if (!modes[i] && (h_idx || v_idx)) {
+			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
+				      connector->base.id);
+			continue;
+		}
+		if (connector->tile_h_loc < h_idx)
+			hoffset += modes[i]->hdisplay;
+
+		if (connector->tile_v_loc < v_idx)
+			voffset += modes[i]->vdisplay;
+	}
+	offsets[idx].x = hoffset;
+	offsets[idx].y = voffset;
+	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
+	return 0;
+}
+
+static bool drm_client_target_preferred(struct drm_connector **connectors,
+					unsigned int connector_count,
+					struct drm_display_mode **modes,
+					struct drm_client_offset *offsets,
+					bool *enabled, int width, int height)
+{
+	const u64 mask = BIT_ULL(connector_count) - 1;
+	struct drm_connector *connector;
+	u64 conn_configured = 0;
+	int tile_pass = 0;
+	int i;
+
+retry:
+	for (i = 0; i < connector_count; i++) {
+		connector = connectors[i];
+
+		if (conn_configured & BIT_ULL(i))
+			continue;
+
+		if (enabled[i] == false) {
+			conn_configured |= BIT_ULL(i);
+			continue;
+		}
+
+		/* first pass over all the untiled connectors */
+		if (tile_pass == 0 && connector->has_tile)
+			continue;
+
+		if (tile_pass == 1) {
+			if (connector->tile_h_loc != 0 ||
+			    connector->tile_v_loc != 0)
+				continue;
+
+		} else {
+			if (connector->tile_h_loc != tile_pass - 1 &&
+			    connector->tile_v_loc != tile_pass - 1)
+			/* if this tile_pass doesn't cover any of the tiles - keep going */
+				continue;
+
+			/*
+			 * find the tile offsets for this pass - need to find
+			 * all tiles left and above
+			 */
+			drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
+						    connector->tile_h_loc, connector->tile_v_loc);
+		}
+		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
+			      connector->base.id);
+
+		/* got for command line mode first */
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
+		if (!modes[i]) {
+			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
+				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
+		}
+		/* No preferred modes, pick one off the list */
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			list_for_each_entry(modes[i], &connector->modes, head)
+				break;
+		}
+		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
+			  "none");
+		conn_configured |= BIT_ULL(i);
+	}
+
+	if ((conn_configured & mask) != mask) {
+		tile_pass++;
+		goto retry;
+	}
+	return true;
+}
+
+static bool connector_has_possible_crtc(struct drm_connector *connector,
+					struct drm_crtc *crtc)
+{
+	struct drm_encoder *encoder;
+	int i;
+
+	drm_connector_for_each_possible_encoder(connector, encoder, i) {
+		if (encoder->possible_crtcs & drm_crtc_mask(crtc))
+			return true;
+	}
+
+	return false;
+}
+
+static int drm_client_pick_crtcs(struct drm_client_dev *client,
+				 struct drm_connector **connectors,
+				 unsigned int connector_count,
+				 struct drm_crtc **best_crtcs,
+				 struct drm_display_mode **modes,
+				 int n, int width, int height)
+{
+	struct drm_device *dev = client->dev;
+	struct drm_connector *connector;
+	int my_score, best_score, score;
+	struct drm_crtc **crtcs, *crtc;
+	struct drm_mode_set *modeset;
+	int o;
+
+	if (n == connector_count)
+		return 0;
+
+	connector = connectors[n];
+
+	best_crtcs[n] = NULL;
+	best_score = drm_client_pick_crtcs(client, connectors, connector_count,
+					   best_crtcs, modes, n + 1, width, height);
+	if (modes[n] == NULL)
+		return best_score;
+
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	if (!crtcs)
+		return best_score;
+
+	my_score = 1;
+	if (connector->status == connector_status_connected)
+		my_score++;
+	if (connector->cmdline_mode.specified)
+		my_score++;
+	if (drm_connector_has_preferred_mode(connector, width, height))
+		my_score++;
+
+	/*
+	 * select a crtc for this connector and then attempt to configure
+	 * remaining connectors
+	 */
+	drm_client_for_each_modeset(modeset, client) {
+		crtc = modeset->crtc;
+
+		if (!connector_has_possible_crtc(connector, crtc))
+			continue;
+
+		for (o = 0; o < n; o++)
+			if (best_crtcs[o] == crtc)
+				break;
+
+		if (o < n) {
+			/* ignore cloning unless only a single crtc */
+			if (dev->mode_config.num_crtc > 1)
+				continue;
+
+			if (!drm_mode_equal(modes[o], modes[n]))
+				continue;
+		}
+
+		crtcs[n] = crtc;
+		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
+		score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,
+							 crtcs, modes, n + 1, width, height);
+		if (score > best_score) {
+			best_score = score;
+			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
+		}
+	}
+
+	kfree(crtcs);
+	return best_score;
+}
+
+/* Try to read the BIOS display configuration and use it for the initial config */
+static bool drm_client_firmware_config(struct drm_client_dev *client,
+				       struct drm_connector **connectors,
+				       unsigned int connector_count,
+				       struct drm_crtc **crtcs,
+				       struct drm_display_mode **modes,
+				       struct drm_client_offset *offsets,
+				       bool *enabled, int width, int height)
+{
+	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
+	unsigned long conn_configured, conn_seq;
+	struct drm_device *dev = client->dev;
+	int i, j;
+	bool *save_enabled;
+	bool fallback = true, ret = true;
+	int num_connectors_enabled = 0;
+	int num_connectors_detected = 0;
+	struct drm_modeset_acquire_ctx ctx;
+
+	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
+	if (!save_enabled)
+		return false;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
+		drm_modeset_backoff(&ctx);
+
+	memcpy(save_enabled, enabled, count);
+	conn_seq = GENMASK(count - 1, 0);
+	conn_configured = 0;
+retry:
+	for (i = 0; i < count; i++) {
+		struct drm_connector *connector;
+		struct drm_encoder *encoder;
+		struct drm_crtc *new_crtc;
+
+		connector = connectors[i];
+
+		if (conn_configured & BIT(i))
+			continue;
+
+		/* First pass, only consider tiled connectors */
+		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
+			continue;
+
+		if (connector->status == connector_status_connected)
+			num_connectors_detected++;
+
+		if (!enabled[i]) {
+			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
+				      connector->name);
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		if (connector->force == DRM_FORCE_OFF) {
+			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			continue;
+		}
+
+		encoder = connector->state->best_encoder;
+		if (!encoder || WARN_ON(!connector->state->crtc)) {
+			if (connector->force > DRM_FORCE_OFF)
+				goto bail;
+
+			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
+				      connector->name);
+			enabled[i] = false;
+			conn_configured |= BIT(i);
+			continue;
+		}
+
+		num_connectors_enabled++;
+
+		new_crtc = connector->state->crtc;
+
+		/*
+		 * Make sure we're not trying to drive multiple connectors
+		 * with a single CRTC, since our cloning support may not
+		 * match the BIOS.
+		 */
+		for (j = 0; j < count; j++) {
+			if (crtcs[j] == new_crtc) {
+				DRM_DEBUG_KMS("fallback: cloned configuration\n");
+				goto bail;
+			}
+		}
+
+		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
+			      connector->name);
+
+		/* go for command line mode first */
+		modes[i] = drm_connector_pick_cmdline_mode(connector);
+
+		/* try for preferred next */
+		if (!modes[i]) {
+			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
+				      connector->name, connector->has_tile);
+			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
+		}
+
+		/* No preferred mode marked by the EDID? Are there any modes? */
+		if (!modes[i] && !list_empty(&connector->modes)) {
+			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
+				      connector->name);
+			modes[i] = list_first_entry(&connector->modes,
+						    struct drm_display_mode,
+						    head);
+		}
+
+		/* last resort: use current mode */
+		if (!modes[i]) {
+			/*
+			 * IMPORTANT: We want to use the adjusted mode (i.e.
+			 * after the panel fitter upscaling) as the initial
+			 * config, not the input mode, which is what crtc->mode
+			 * usually contains. But since our current
+			 * code puts a mode derived from the post-pfit timings
+			 * into crtc->mode this works out correctly.
+			 *
+			 * This is crtc->mode and not crtc->state->mode for the
+			 * fastboot check to work correctly.
+			 */
+			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
+				      connector->name);
+			modes[i] = &connector->state->crtc->mode;
+		}
+		crtcs[i] = new_crtc;
+
+		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
+			      connector->name,
+			      connector->state->crtc->base.id,
+			      connector->state->crtc->name,
+			      modes[i]->hdisplay, modes[i]->vdisplay,
+			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
+
+		fallback = false;
+		conn_configured |= BIT(i);
+	}
+
+	if (conn_configured != conn_seq) { /* repeat until no more are found */
+		conn_seq = conn_configured;
+		goto retry;
+	}
+
+	/*
+	 * If the BIOS didn't enable everything it could, fall back to have the
+	 * same user experiencing of lighting up as much as possible like the
+	 * fbdev helper library.
+	 */
+	if (num_connectors_enabled != num_connectors_detected &&
+	    num_connectors_enabled < dev->mode_config.num_crtc) {
+		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
+		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
+			      num_connectors_detected);
+		fallback = true;
+	}
+
+	if (fallback) {
+bail:
+		DRM_DEBUG_KMS("Not using firmware configuration\n");
+		memcpy(enabled, save_enabled, count);
+		ret = false;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	kfree(save_enabled);
+	return ret;
+}
+
+/**
+ * drm_client_modeset_probe() - Probe for displays
+ * @client: DRM client
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function sets up display pipelines for enabled connectors and stores the
+ * config in the client's modeset array.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+
+int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height)
+{
+	struct drm_connector *connector, **connectors = NULL;
+	struct drm_connector_list_iter conn_iter;
+	struct drm_device *dev = client->dev;
+	unsigned int total_modes_count = 0;
+	struct drm_client_offset *offsets;
+	unsigned int connector_count = 0;
+	struct drm_display_mode **modes;
+	struct drm_crtc **crtcs;
+	int i, ret = 0;
+	bool *enabled;
+
+	DRM_DEBUG_KMS("\n");
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_client_for_each_connector_iter(connector, &conn_iter) {
+		struct drm_connector **tmp;
+
+		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
+		if (!tmp) {
+			ret = -ENOMEM;
+			goto free_connectors;
+		}
+
+		connectors = tmp;
+		drm_connector_get(connector);
+		connectors[connector_count++] = connector;
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	if (!connector_count)
+		return 0;
+
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
+	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
+	if (!crtcs || !modes || !enabled || !offsets) {
+		DRM_ERROR("Memory allocation failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	mutex_lock(&client->modeset_mutex);
+
+	mutex_lock(&dev->mode_config.mutex);
+	for (i = 0; i < connector_count; i++)
+		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
+	if (!total_modes_count)
+		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+	drm_client_connectors_enabled(connectors, connector_count, enabled);
+
+	if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,
+					modes, offsets, enabled, width, height)) {
+		memset(modes, 0, connector_count * sizeof(*modes));
+		memset(crtcs, 0, connector_count * sizeof(*crtcs));
+		memset(offsets, 0, connector_count * sizeof(*offsets));
+
+		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
+					      offsets, enabled, width, height) &&
+		    !drm_client_target_preferred(connectors, connector_count, modes,
+						 offsets, enabled, width, height))
+			DRM_ERROR("Unable to find initial modes\n");
+
+		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
+			      width, height);
+
+		drm_client_pick_crtcs(client, connectors, connector_count,
+				      crtcs, modes, 0, width, height);
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
+	drm_client_modeset_release(client);
+
+	for (i = 0; i < connector_count; i++) {
+		struct drm_display_mode *mode = modes[i];
+		struct drm_crtc *crtc = crtcs[i];
+		struct drm_client_offset *offset = &offsets[i];
+
+		if (mode && crtc) {
+			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
+			struct drm_connector *connector = connectors[i];
+
+			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
+				      mode->name, crtc->base.id, offset->x, offset->y);
+
+			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {
+				ret = -EINVAL;
+				break;
+			}
+
+			modeset->mode = drm_mode_duplicate(dev, mode);
+			drm_connector_get(connector);
+			modeset->connectors[modeset->num_connectors++] = connector;
+			modeset->x = offset->x;
+			modeset->y = offset->y;
+		}
+	}
+
+	mutex_unlock(&client->modeset_mutex);
+out:
+	kfree(crtcs);
+	kfree(modes);
+	kfree(offsets);
+	kfree(enabled);
+free_connectors:
+	for (i = 0; i < connector_count; i++)
+		drm_connector_put(connectors[i]);
+	kfree(connectors);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_client_modeset_probe);
 
 /**
  * drm_client_panel_rotation() - Check panel orientation
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 9287ff4ae2d8..e6486d9c0381 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -43,10 +43,6 @@
 
 #include "drm_internal.h"
 
-struct drm_client_offset {
-	int x, y;
-};
-
 static bool drm_fbdev_emulation = true;
 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
 MODULE_PARM_DESC(fbdev_emulation,
@@ -1688,694 +1684,6 @@ void drm_fb_helper_fill_info(struct fb_info *info,
 }
 EXPORT_SYMBOL(drm_fb_helper_fill_info);
 
-static struct drm_display_mode *
-drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
-{
-	struct drm_display_mode *mode;
-
-	list_for_each_entry(mode, &connector->modes, head) {
-		if (mode->hdisplay > width ||
-		    mode->vdisplay > height)
-			continue;
-		if (mode->type & DRM_MODE_TYPE_PREFERRED)
-			return mode;
-	}
-	return NULL;
-}
-
-static struct drm_display_mode *
-drm_connector_pick_cmdline_mode(struct drm_connector *connector)
-{
-	struct drm_cmdline_mode *cmdline_mode;
-	struct drm_display_mode *mode;
-	bool prefer_non_interlace;
-
-	cmdline_mode = &connector->cmdline_mode;
-	if (cmdline_mode->specified == false)
-		return NULL;
-
-	/* attempt to find a matching mode in the list of modes
-	 *  we have gotten so far, if not add a CVT mode that conforms
-	 */
-	if (cmdline_mode->rb || cmdline_mode->margins)
-		goto create_mode;
-
-	prefer_non_interlace = !cmdline_mode->interlace;
-again:
-	list_for_each_entry(mode, &connector->modes, head) {
-		/* check width/height */
-		if (mode->hdisplay != cmdline_mode->xres ||
-		    mode->vdisplay != cmdline_mode->yres)
-			continue;
-
-		if (cmdline_mode->refresh_specified) {
-			if (mode->vrefresh != cmdline_mode->refresh)
-				continue;
-		}
-
-		if (cmdline_mode->interlace) {
-			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
-				continue;
-		} else if (prefer_non_interlace) {
-			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-				continue;
-		}
-		return mode;
-	}
-
-	if (prefer_non_interlace) {
-		prefer_non_interlace = false;
-		goto again;
-	}
-
-create_mode:
-	mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
-	list_add(&mode->head, &connector->modes);
-
-	return mode;
-}
-
-static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
-{
-	bool enable;
-
-	if (connector->display_info.non_desktop)
-		return false;
-
-	if (strict)
-		enable = connector->status == connector_status_connected;
-	else
-		enable = connector->status != connector_status_disconnected;
-
-	return enable;
-}
-
-static void drm_client_connectors_enabled(struct drm_connector **connectors,
-					  unsigned int connector_count,
-					  bool *enabled)
-{
-	bool any_enabled = false;
-	struct drm_connector *connector;
-	int i = 0;
-
-	for (i = 0; i < connector_count; i++) {
-		connector = connectors[i];
-		enabled[i] = drm_connector_enabled(connector, true);
-		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
-			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
-
-		any_enabled |= enabled[i];
-	}
-
-	if (any_enabled)
-		return;
-
-	for (i = 0; i < connector_count; i++)
-		enabled[i] = drm_connector_enabled(connectors[i], false);
-}
-
-static bool drm_client_target_cloned(struct drm_device *dev,
-				     struct drm_connector **connectors,
-				     unsigned int connector_count,
-				     struct drm_display_mode **modes,
-				     struct drm_client_offset *offsets,
-				     bool *enabled, int width, int height)
-{
-	int count, i, j;
-	bool can_clone = false;
-	struct drm_display_mode *dmt_mode, *mode;
-
-	/* only contemplate cloning in the single crtc case */
-	if (dev->mode_config.num_crtc > 1)
-		return false;
-
-	count = 0;
-	for (i = 0; i < connector_count; i++) {
-		if (enabled[i])
-			count++;
-	}
-
-	/* only contemplate cloning if more than one connector is enabled */
-	if (count <= 1)
-		return false;
-
-	/* check the command line or if nothing common pick 1024x768 */
-	can_clone = true;
-	for (i = 0; i < connector_count; i++) {
-		if (!enabled[i])
-			continue;
-		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
-		if (!modes[i]) {
-			can_clone = false;
-			break;
-		}
-		for (j = 0; j < i; j++) {
-			if (!enabled[j])
-				continue;
-			if (!drm_mode_match(modes[j], modes[i],
-					    DRM_MODE_MATCH_TIMINGS |
-					    DRM_MODE_MATCH_CLOCK |
-					    DRM_MODE_MATCH_FLAGS |
-					    DRM_MODE_MATCH_3D_FLAGS))
-				can_clone = false;
-		}
-	}
-
-	if (can_clone) {
-		DRM_DEBUG_KMS("can clone using command line\n");
-		return true;
-	}
-
-	/* try and find a 1024x768 mode on each connector */
-	can_clone = true;
-	dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
-
-	for (i = 0; i < connector_count; i++) {
-		if (!enabled[i])
-			continue;
-
-		list_for_each_entry(mode, &connectors[i]->modes, head) {
-			if (drm_mode_match(mode, dmt_mode,
-					   DRM_MODE_MATCH_TIMINGS |
-					   DRM_MODE_MATCH_CLOCK |
-					   DRM_MODE_MATCH_FLAGS |
-					   DRM_MODE_MATCH_3D_FLAGS))
-				modes[i] = mode;
-		}
-		if (!modes[i])
-			can_clone = false;
-	}
-
-	if (can_clone) {
-		DRM_DEBUG_KMS("can clone using 1024x768\n");
-		return true;
-	}
-	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
-	return false;
-}
-
-static int drm_client_get_tile_offsets(struct drm_connector **connectors,
-				       unsigned int connector_count,
-				       struct drm_display_mode **modes,
-				       struct drm_client_offset *offsets,
-				       int idx,
-				       int h_idx, int v_idx)
-{
-	struct drm_connector *connector;
-	int i;
-	int hoffset = 0, voffset = 0;
-
-	for (i = 0; i < connector_count; i++) {
-		connector = connectors[i];
-		if (!connector->has_tile)
-			continue;
-
-		if (!modes[i] && (h_idx || v_idx)) {
-			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
-				      connector->base.id);
-			continue;
-		}
-		if (connector->tile_h_loc < h_idx)
-			hoffset += modes[i]->hdisplay;
-
-		if (connector->tile_v_loc < v_idx)
-			voffset += modes[i]->vdisplay;
-	}
-	offsets[idx].x = hoffset;
-	offsets[idx].y = voffset;
-	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
-	return 0;
-}
-
-static bool drm_client_target_preferred(struct drm_connector **connectors,
-					unsigned int connector_count,
-					struct drm_display_mode **modes,
-					struct drm_client_offset *offsets,
-					bool *enabled, int width, int height)
-{
-	const u64 mask = BIT_ULL(connector_count) - 1;
-	struct drm_connector *connector;
-	u64 conn_configured = 0;
-	int tile_pass = 0;
-	int i;
-
-retry:
-	for (i = 0; i < connector_count; i++) {
-		connector = connectors[i];
-
-		if (conn_configured & BIT_ULL(i))
-			continue;
-
-		if (enabled[i] == false) {
-			conn_configured |= BIT_ULL(i);
-			continue;
-		}
-
-		/* first pass over all the untiled connectors */
-		if (tile_pass == 0 && connector->has_tile)
-			continue;
-
-		if (tile_pass == 1) {
-			if (connector->tile_h_loc != 0 ||
-			    connector->tile_v_loc != 0)
-				continue;
-
-		} else {
-			if (connector->tile_h_loc != tile_pass - 1 &&
-			    connector->tile_v_loc != tile_pass - 1)
-			/* if this tile_pass doesn't cover any of the tiles - keep going */
-				continue;
-
-			/*
-			 * find the tile offsets for this pass - need to find
-			 * all tiles left and above
-			 */
-			drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
-						    connector->tile_h_loc, connector->tile_v_loc);
-		}
-		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
-			      connector->base.id);
-
-		/* got for command line mode first */
-		modes[i] = drm_connector_pick_cmdline_mode(connector);
-		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
-				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
-			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
-		}
-		/* No preferred modes, pick one off the list */
-		if (!modes[i] && !list_empty(&connector->modes)) {
-			list_for_each_entry(modes[i], &connector->modes, head)
-				break;
-		}
-		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
-			  "none");
-		conn_configured |= BIT_ULL(i);
-	}
-
-	if ((conn_configured & mask) != mask) {
-		tile_pass++;
-		goto retry;
-	}
-	return true;
-}
-
-static bool connector_has_possible_crtc(struct drm_connector *connector,
-					struct drm_crtc *crtc)
-{
-	struct drm_encoder *encoder;
-	int i;
-
-	drm_connector_for_each_possible_encoder(connector, encoder, i) {
-		if (encoder->possible_crtcs & drm_crtc_mask(crtc))
-			return true;
-	}
-
-	return false;
-}
-
-static int drm_client_pick_crtcs(struct drm_client_dev *client,
-				 struct drm_connector **connectors,
-				 unsigned int connector_count,
-				 struct drm_crtc **best_crtcs,
-				 struct drm_display_mode **modes,
-				 int n, int width, int height)
-{
-	struct drm_device *dev = client->dev;
-	struct drm_connector *connector;
-	int my_score, best_score, score;
-	struct drm_crtc **crtcs, *crtc;
-	struct drm_mode_set *modeset;
-	int o;
-
-	if (n == connector_count)
-		return 0;
-
-	connector = connectors[n];
-
-	best_crtcs[n] = NULL;
-	best_score = drm_client_pick_crtcs(client, connectors, connector_count,
-					   best_crtcs, modes, n + 1, width, height);
-	if (modes[n] == NULL)
-		return best_score;
-
-	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
-	if (!crtcs)
-		return best_score;
-
-	my_score = 1;
-	if (connector->status == connector_status_connected)
-		my_score++;
-	if (connector->cmdline_mode.specified)
-		my_score++;
-	if (drm_connector_has_preferred_mode(connector, width, height))
-		my_score++;
-
-	/*
-	 * select a crtc for this connector and then attempt to configure
-	 * remaining connectors
-	 */
-	drm_client_for_each_modeset(modeset, client) {
-		crtc = modeset->crtc;
-
-		if (!connector_has_possible_crtc(connector, crtc))
-			continue;
-
-		for (o = 0; o < n; o++)
-			if (best_crtcs[o] == crtc)
-				break;
-
-		if (o < n) {
-			/* ignore cloning unless only a single crtc */
-			if (dev->mode_config.num_crtc > 1)
-				continue;
-
-			if (!drm_mode_equal(modes[o], modes[n]))
-				continue;
-		}
-
-		crtcs[n] = crtc;
-		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
-		score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,
-							 crtcs, modes, n + 1, width, height);
-		if (score > best_score) {
-			best_score = score;
-			memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
-		}
-	}
-
-	kfree(crtcs);
-	return best_score;
-}
-
-/* Try to read the BIOS display configuration and use it for the initial config */
-static bool drm_client_firmware_config(struct drm_client_dev *client,
-				       struct drm_connector **connectors,
-				       unsigned int connector_count,
-				       struct drm_crtc **crtcs,
-				       struct drm_display_mode **modes,
-				       struct drm_client_offset *offsets,
-				       bool *enabled, int width, int height)
-{
-	unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
-	unsigned long conn_configured, conn_seq;
-	struct drm_device *dev = client->dev;
-	int i, j;
-	bool *save_enabled;
-	bool fallback = true, ret = true;
-	int num_connectors_enabled = 0;
-	int num_connectors_detected = 0;
-	struct drm_modeset_acquire_ctx ctx;
-
-	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
-	if (!save_enabled)
-		return false;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
-		drm_modeset_backoff(&ctx);
-
-	memcpy(save_enabled, enabled, count);
-	conn_seq = GENMASK(count - 1, 0);
-	conn_configured = 0;
-retry:
-	for (i = 0; i < count; i++) {
-		struct drm_connector *connector;
-		struct drm_encoder *encoder;
-		struct drm_crtc *new_crtc;
-
-		connector = connectors[i];
-
-		if (conn_configured & BIT(i))
-			continue;
-
-		/* First pass, only consider tiled connectors */
-		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
-			continue;
-
-		if (connector->status == connector_status_connected)
-			num_connectors_detected++;
-
-		if (!enabled[i]) {
-			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
-				      connector->name);
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		if (connector->force == DRM_FORCE_OFF) {
-			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			continue;
-		}
-
-		encoder = connector->state->best_encoder;
-		if (!encoder || WARN_ON(!connector->state->crtc)) {
-			if (connector->force > DRM_FORCE_OFF)
-				goto bail;
-
-			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
-				      connector->name);
-			enabled[i] = false;
-			conn_configured |= BIT(i);
-			continue;
-		}
-
-		num_connectors_enabled++;
-
-		new_crtc = connector->state->crtc;
-
-		/*
-		 * Make sure we're not trying to drive multiple connectors
-		 * with a single CRTC, since our cloning support may not
-		 * match the BIOS.
-		 */
-		for (j = 0; j < count; j++) {
-			if (crtcs[j] == new_crtc) {
-				DRM_DEBUG_KMS("fallback: cloned configuration\n");
-				goto bail;
-			}
-		}
-
-		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
-			      connector->name);
-
-		/* go for command line mode first */
-		modes[i] = drm_connector_pick_cmdline_mode(connector);
-
-		/* try for preferred next */
-		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
-				      connector->name, connector->has_tile);
-			modes[i] = drm_connector_has_preferred_mode(connector, width, height);
-		}
-
-		/* No preferred mode marked by the EDID? Are there any modes? */
-		if (!modes[i] && !list_empty(&connector->modes)) {
-			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
-				      connector->name);
-			modes[i] = list_first_entry(&connector->modes,
-						    struct drm_display_mode,
-						    head);
-		}
-
-		/* last resort: use current mode */
-		if (!modes[i]) {
-			/*
-			 * IMPORTANT: We want to use the adjusted mode (i.e.
-			 * after the panel fitter upscaling) as the initial
-			 * config, not the input mode, which is what crtc->mode
-			 * usually contains. But since our current
-			 * code puts a mode derived from the post-pfit timings
-			 * into crtc->mode this works out correctly.
-			 *
-			 * This is crtc->mode and not crtc->state->mode for the
-			 * fastboot check to work correctly.
-			 */
-			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
-				      connector->name);
-			modes[i] = &connector->state->crtc->mode;
-		}
-		crtcs[i] = new_crtc;
-
-		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
-			      connector->name,
-			      connector->state->crtc->base.id,
-			      connector->state->crtc->name,
-			      modes[i]->hdisplay, modes[i]->vdisplay,
-			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
-
-		fallback = false;
-		conn_configured |= BIT(i);
-	}
-
-	if (conn_configured != conn_seq) { /* repeat until no more are found */
-		conn_seq = conn_configured;
-		goto retry;
-	}
-
-	/*
-	 * If the BIOS didn't enable everything it could, fall back to have the
-	 * same user experiencing of lighting up as much as possible like the
-	 * fbdev helper library.
-	 */
-	if (num_connectors_enabled != num_connectors_detected &&
-	    num_connectors_enabled < dev->mode_config.num_crtc) {
-		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
-		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
-			      num_connectors_detected);
-		fallback = true;
-	}
-
-	if (fallback) {
-bail:
-		DRM_DEBUG_KMS("Not using firmware configuration\n");
-		memcpy(enabled, save_enabled, count);
-		ret = false;
-	}
-
-	drm_modeset_drop_locks(&ctx);
-	drm_modeset_acquire_fini(&ctx);
-
-	kfree(save_enabled);
-	return ret;
-}
-
-/**
- * drm_client_modeset_probe() - Probe for displays
- * @client: DRM client
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function sets up display pipelines for enabled connectors and stores the
- * config in the client's modeset array.
- *
- * Returns:
- * Zero on success or negative error code on failure.
- */
-
-int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height)
-{
-	struct drm_connector *connector, **connectors = NULL;
-	struct drm_connector_list_iter conn_iter;
-	struct drm_device *dev = client->dev;
-	unsigned int total_modes_count = 0;
-	struct drm_client_offset *offsets;
-	unsigned int connector_count = 0;
-	struct drm_display_mode **modes;
-	struct drm_crtc **crtcs;
-	int i, ret = 0;
-	bool *enabled;
-
-	DRM_DEBUG_KMS("\n");
-
-	if (!width)
-		width = dev->mode_config.max_width;
-	if (!height)
-		height = dev->mode_config.max_height;
-
-	drm_connector_list_iter_begin(dev, &conn_iter);
-	drm_client_for_each_connector_iter(connector, &conn_iter) {
-		struct drm_connector **tmp;
-
-		tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
-		if (!tmp) {
-			ret = -ENOMEM;
-			goto free_connectors;
-		}
-
-		connectors = tmp;
-		drm_connector_get(connector);
-		connectors[connector_count++] = connector;
-	}
-	drm_connector_list_iter_end(&conn_iter);
-
-	if (!connector_count)
-		return 0;
-
-	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
-	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
-	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
-	enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
-	if (!crtcs || !modes || !enabled || !offsets) {
-		DRM_ERROR("Memory allocation failed\n");
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	mutex_lock(&client->modeset_mutex);
-
-	mutex_lock(&dev->mode_config.mutex);
-	for (i = 0; i < connector_count; i++)
-		total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
-	if (!total_modes_count)
-		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-	drm_client_connectors_enabled(connectors, connector_count, enabled);
-
-	if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,
-					modes, offsets, enabled, width, height)) {
-		memset(modes, 0, connector_count * sizeof(*modes));
-		memset(crtcs, 0, connector_count * sizeof(*crtcs));
-		memset(offsets, 0, connector_count * sizeof(*offsets));
-
-		if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
-					      offsets, enabled, width, height) &&
-		    !drm_client_target_preferred(connectors, connector_count, modes,
-						 offsets, enabled, width, height))
-			DRM_ERROR("Unable to find initial modes\n");
-
-		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
-			      width, height);
-
-		drm_client_pick_crtcs(client, connectors, connector_count,
-				      crtcs, modes, 0, width, height);
-	}
-	mutex_unlock(&dev->mode_config.mutex);
-
-	drm_client_modeset_release(client);
-
-	for (i = 0; i < connector_count; i++) {
-		struct drm_display_mode *mode = modes[i];
-		struct drm_crtc *crtc = crtcs[i];
-		struct drm_client_offset *offset = &offsets[i];
-
-		if (mode && crtc) {
-			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
-			struct drm_connector *connector = connectors[i];
-
-			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
-				      mode->name, crtc->base.id, offset->x, offset->y);
-
-			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
-					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {
-				ret = -EINVAL;
-				break;
-			}
-
-			modeset->mode = drm_mode_duplicate(dev, mode);
-			drm_connector_get(connector);
-			modeset->connectors[modeset->num_connectors++] = connector;
-			modeset->x = offset->x;
-			modeset->y = offset->y;
-		}
-	}
-
-	mutex_unlock(&client->modeset_mutex);
-out:
-	kfree(crtcs);
-	kfree(modes);
-	kfree(offsets);
-	kfree(enabled);
-free_connectors:
-	for (i = 0; i < connector_count; i++)
-		drm_connector_put(connectors[i]);
-	kfree(connectors);
-
-	return ret;
-}
-
 /*
  * This is a continuation of drm_setup_crtcs() that sets up anything related
  * to the framebuffer. During initialization, drm_setup_crtcs() is called before
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 6bb5e0412877..515f0f783ff8 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -17,8 +17,6 @@ struct drm_gem_object;
 struct drm_minor;
 struct module;
 
-#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
-
 /**
  * struct drm_client_funcs - DRM client callbacks
  */
@@ -154,7 +152,7 @@ void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
 int drm_client_modeset_create(struct drm_client_dev *client);
 void drm_client_modeset_free(struct drm_client_dev *client);
 void drm_client_modeset_release(struct drm_client_dev *client);
-struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
+int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height);
 bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
 int drm_client_modeset_commit_force(struct drm_client_dev *client);
 int drm_client_modeset_commit(struct drm_client_dev *client);
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v2 12/12] drm/client: Hack: Add bootsplash example
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (10 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 11/12] drm/fb-helper: Move " Noralf Trønnes
@ 2019-04-07 16:52 ` Noralf Trønnes
  2019-04-07 17:02 ` ✗ Fi.CI.CHECKPATCH: warning for drm/fb-helper: Move modesetting code to drm_client (rev2) Patchwork
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-07 16:52 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx

An example to showcase the client API.

TODO:
A bootsplash client needs a way to tell drm_fb_helper to stay away,
otherwise it will chime in on setup and hotplug.
Most DRM drivers register fbdev before calling drm_dev_register() (the
generic emulation is an exception). This have to be reversed for
bootsplash to fend off fbdev.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Kconfig          |   5 +
 drivers/gpu/drm/Makefile         |   1 +
 drivers/gpu/drm/drm_bootsplash.c | 359 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_client.c     |   7 +
 drivers/gpu/drm/drm_drv.c        |   4 +
 include/drm/drm_client.h         |   3 +
 6 files changed, 379 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_bootsplash.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 98e9ac8498c0..d61de804068a 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -65,6 +65,11 @@ config DRM_DEBUG_SELFTEST
 
 	  If in doubt, say "N".
 
+config DRM_CLIENT_BOOTSPLASH
+	bool "DRM Bootsplash"
+	help
+	  DRM Bootsplash
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 08c77c10ccbb..ae42c9a91c57 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -32,6 +32,7 @@ drm-$(CONFIG_OF) += drm_of.o
 drm-$(CONFIG_AGP) += drm_agpsupport.o
 drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
 drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
+drm-$(CONFIG_DRM_CLIENT_BOOTSPLASH) += drm_bootsplash.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
diff --git a/drivers/gpu/drm/drm_bootsplash.c b/drivers/gpu/drm/drm_bootsplash.c
new file mode 100644
index 000000000000..37f3ac3fce95
--- /dev/null
+++ b/drivers/gpu/drm/drm_bootsplash.c
@@ -0,0 +1,359 @@
+/* DRM internal client example */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/keyboard.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_print.h>
+
+// drm_lastclose()
+#include "drm_internal.h"
+
+static bool drm_bootsplash_enabled = true;
+module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0600);
+MODULE_PARM_DESC(bootsplash_enabled, "Enable bootsplash client [default=true]");
+
+struct drm_bootsplash {
+	struct drm_client_dev client;
+	struct mutex lock;
+	struct work_struct worker;
+	bool started;
+	bool stop;
+
+	unsigned int modeset_mask;
+	struct drm_client_buffer *buffers[2];
+};
+
+static bool drm_bootsplash_key_pressed;
+
+static int drm_bootsplash_keyboard_notifier_call(struct notifier_block *blk,
+						 unsigned long code, void *_param)
+{
+	/* Any key is good */
+	drm_bootsplash_key_pressed = true;
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block drm_bootsplash_keyboard_notifier_block = {
+	.notifier_call = drm_bootsplash_keyboard_notifier_call,
+};
+
+static void drm_bootsplash_buffer_delete(struct drm_bootsplash *splash)
+{
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		if (!IS_ERR_OR_NULL(splash->buffers[i]))
+			drm_client_framebuffer_delete(splash->buffers[i]);
+		splash->buffers[i] = NULL;
+	}
+}
+
+static int drm_bootsplash_buffer_create(struct drm_bootsplash *splash, u32 width, u32 height)
+{
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		splash->buffers[i] = drm_client_framebuffer_create(&splash->client, width, height, DRM_FORMAT_XRGB8888);
+		if (IS_ERR(splash->buffers[i])) {
+			drm_bootsplash_buffer_delete(splash);
+			return PTR_ERR(splash->buffers[i]);
+		}
+	}
+
+	return 0;
+}
+
+static int drm_bootsplash_display_probe(struct drm_bootsplash *splash)
+{
+	struct drm_client_dev *client = &splash->client;
+	unsigned int width = 0, height = 0;
+	unsigned int num_non_tiled = 0, i;
+	struct drm_mode_set *modeset;
+	bool tiled = false;
+	int ret;
+
+	splash->modeset_mask = 0;
+
+	ret = drm_client_modeset_probe(client, 0, 0);
+	if (ret)
+		return ret;
+
+	mutex_lock(&client->modeset_mutex);
+
+	drm_client_for_each_modeset(modeset, client) {
+		if (!modeset->mode)
+			continue;
+
+		if (modeset->connectors[0]->has_tile)
+			tiled = true;
+		else
+			num_non_tiled++;
+	}
+
+	if (!tiled && !num_non_tiled) {
+		drm_bootsplash_buffer_delete(splash);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	/* Assume only one tiled monitor is possible */
+	if (tiled) {
+		int hdisplay = 0, vdisplay = 0;
+
+		i = 0;
+		drm_client_for_each_modeset(modeset, client) {
+			i++;
+			if (!modeset->connectors[0]->has_tile)
+				continue;
+
+			if (!modeset->y)
+				hdisplay += modeset->mode->hdisplay;
+			if (!modeset->x)
+				vdisplay += modeset->mode->vdisplay;
+			splash->modeset_mask |= BIT(i - 1);
+		}
+
+		width = hdisplay;
+		height = vdisplay;
+
+		goto trim;
+	}
+
+	/* The rest have one display per modeset, pick the largest */
+	i = 0;
+	drm_client_for_each_modeset(modeset, client) {
+		i++;
+		if (!modeset->mode || modeset->connectors[0]->has_tile)
+			continue;
+
+		if (modeset->mode->hdisplay * modeset->mode->vdisplay > width * height) {
+			width = modeset->mode->hdisplay;
+			height = modeset->mode->vdisplay;
+			splash->modeset_mask = BIT(i - 1);
+		}
+	}
+
+trim:
+	/* Remove unused modesets (warning in __drm_atomic_helper_set_config()) */
+	i = 0;
+	drm_client_for_each_modeset(modeset, client) {
+		unsigned int j;
+
+		if (splash->modeset_mask & BIT(i++))
+			continue;
+
+		drm_mode_destroy(client->dev, modeset->mode);
+		modeset->mode = NULL;
+
+		for (j = 0; j < modeset->num_connectors; j++) {
+			drm_connector_put(modeset->connectors[j]);
+			modeset->connectors[j] = NULL;
+		}
+		modeset->num_connectors = 0;
+	}
+
+	if (!splash->buffers[0] ||
+	    splash->buffers[0]->fb->width != width || splash->buffers[0]->fb->height != height) {
+		drm_bootsplash_buffer_delete(splash);
+		ret = drm_bootsplash_buffer_create(splash, width, height);
+	}
+
+out:
+	mutex_unlock(&client->modeset_mutex);
+
+	return ret;
+}
+
+static int drm_bootsplash_display_commit_buffer(struct drm_bootsplash *splash, unsigned int num)
+{
+	struct drm_mode_set *modeset;
+	unsigned int i = 0;
+
+	drm_client_for_each_modeset(modeset, &splash->client) {
+		if (splash->modeset_mask & BIT(i++))
+			modeset->fb = splash->buffers[num]->fb;
+	}
+
+	return drm_client_modeset_commit(&splash->client);
+}
+
+static u32 drm_bootsplash_color_table[3] = {
+	0x00ff0000, 0x0000ff00, 0x000000ff,
+};
+
+/* Draw a box with changing colors */
+static void drm_bootsplash_draw_box(struct drm_client_buffer *buffer, unsigned int sequence)
+{
+	unsigned int width = buffer->fb->width;
+	unsigned int height = buffer->fb->height;
+	unsigned int x, y;
+	u32 *pix;
+
+	pix = buffer->vaddr;
+	pix += ((height / 2) - 50) * width;
+	pix += (width / 2) - 50;
+
+	for (y = 0; y < 100; y++) {
+		for (x = 0; x < 100; x++)
+			*pix++ = drm_bootsplash_color_table[sequence];
+		pix += width - 100;
+	}
+}
+
+static int drm_bootsplash_draw(struct drm_bootsplash *splash, unsigned int sequence, unsigned int buffer_num)
+{
+	if (!splash->buffers[buffer_num])
+		return -ENOENT;
+
+	DRM_DEBUG_KMS("draw: buffer_num=%u, sequence=%u\n", buffer_num, sequence);
+
+	drm_bootsplash_draw_box(splash->buffers[buffer_num], sequence);
+
+	return drm_bootsplash_display_commit_buffer(splash, buffer_num);
+}
+
+static void drm_bootsplash_worker(struct work_struct *work)
+{
+	struct drm_bootsplash *splash = container_of(work, struct drm_bootsplash, worker);
+	struct drm_client_dev *client = &splash->client;
+	struct drm_device *dev = client->dev;
+	unsigned int buffer_num = 0, sequence = 0;
+	bool stop = false;
+	int ret = 0;
+
+	while (!drm_bootsplash_key_pressed) {
+		mutex_lock(&splash->lock);
+
+		stop = splash->stop;
+
+		buffer_num = !buffer_num;
+
+		ret = drm_bootsplash_draw(splash, sequence, buffer_num);
+
+		mutex_unlock(&splash->lock);
+
+		if (stop || ret == -ENOENT || ret == -EBUSY)
+			break;
+
+		if (++sequence == 3)
+			sequence = 0;
+
+		msleep(500);
+	}
+
+	/* Restore fbdev (or other) on key press. */
+	/* TODO: Check if it's OK to call drm_lastclose here. */
+	if (drm_bootsplash_key_pressed && !splash->stop)
+		drm_lastclose(dev);
+
+	drm_bootsplash_buffer_delete(splash);
+
+	DRM_DEV_DEBUG_KMS(dev->dev, "Bootsplash has stopped (key=%u stop=%u, ret=%d).\n",
+			  drm_bootsplash_key_pressed, splash->stop, ret);
+}
+
+static int drm_bootsplash_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client);
+	int ret = 0;
+
+	if (drm_bootsplash_key_pressed)
+		return 0;
+
+	mutex_lock(&splash->lock);
+
+	if (splash->stop)
+		goto out_unlock;
+
+	ret = drm_bootsplash_display_probe(splash);
+	if (ret < 0) {
+		if (splash->started && ret == -ENOENT)
+			splash->stop = true;
+		goto out_unlock;
+	}
+
+	/*
+	 * TODO: Deal with rotated panels, might have to sw rotate
+	if (drm_client_panel_rotation(...))
+	 */
+
+	if (!splash->started) {
+		splash->started = true;
+		schedule_work(&splash->worker);
+	}
+
+out_unlock:
+	mutex_unlock(&splash->lock);
+
+	return ret;
+}
+
+static void drm_bootsplash_client_unregister(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client);
+
+	DRM_DEBUG_KMS("%s: IN\n", __func__);
+
+	mutex_lock(&splash->lock);
+	splash->stop = true;
+	mutex_unlock(&splash->lock);
+
+	flush_work(&splash->worker);
+
+	drm_client_release(client);
+	kfree(splash);
+
+	unregister_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+
+	DRM_DEBUG_KMS("%s: OUT\n", __func__);
+}
+
+static const struct drm_client_funcs drm_bootsplash_client_funcs = {
+	.owner		= THIS_MODULE,
+	.unregister	= drm_bootsplash_client_unregister,
+	.hotplug	= drm_bootsplash_client_hotplug,
+};
+
+void drm_bootsplash_client_register(struct drm_device *dev)
+{
+	struct drm_bootsplash *splash;
+	int ret;
+
+	if (!drm_bootsplash_enabled)
+		return;
+
+	splash = kzalloc(sizeof(*splash), GFP_KERNEL);
+	if (!splash)
+		return;
+
+	ret = drm_client_init(dev, &splash->client, "bootsplash", &drm_bootsplash_client_funcs);
+	if (ret) {
+		DRM_DEV_ERROR(dev->dev, "Failed to create client, ret=%d\n", ret);
+		kfree(splash);
+		return;
+	}
+
+	/* For this simple example only allow the first */
+	drm_bootsplash_enabled = false;
+
+	mutex_init(&splash->lock);
+
+	INIT_WORK(&splash->worker, drm_bootsplash_worker);
+
+	drm_client_add(&splash->client);
+
+	register_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+
+	drm_bootsplash_client_hotplug(&splash->client);
+}
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 3ad5b57c1419..1f9eb28a27e5 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -162,6 +162,13 @@ void drm_client_release(struct drm_client_dev *client)
 }
 EXPORT_SYMBOL(drm_client_release);
 
+void drm_client_dev_register(struct drm_device *dev)
+{
+#if CONFIG_DRM_CLIENT_BOOTSPLASH
+	drm_bootsplash_client_register(dev);
+#endif
+}
+
 void drm_client_dev_unregister(struct drm_device *dev)
 {
 	struct drm_client_dev *client, *tmp;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 50d849d1bc6e..fbbb5f998baf 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -1018,6 +1018,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 out_unlock:
 	mutex_unlock(&drm_global_mutex);
+
+	if (!ret)
+		drm_client_dev_register(dev);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_dev_register);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 515f0f783ff8..ac72fa514e67 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -106,6 +106,7 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
 void drm_client_release(struct drm_client_dev *client);
 void drm_client_add(struct drm_client_dev *client);
 
+void drm_client_dev_register(struct drm_device *dev);
 void drm_client_dev_unregister(struct drm_device *dev);
 void drm_client_dev_hotplug(struct drm_device *dev);
 void drm_client_dev_restore(struct drm_device *dev);
@@ -182,4 +183,6 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
 
 int drm_client_debugfs_init(struct drm_minor *minor);
 
+void drm_bootsplash_client_register(struct drm_device *dev);
+
 #endif
-- 
2.20.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* ✗ Fi.CI.CHECKPATCH: warning for drm/fb-helper: Move modesetting code to drm_client (rev2)
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (11 preceding siblings ...)
  2019-04-07 16:52 ` [PATCH v2 12/12] drm/client: Hack: Add bootsplash example Noralf Trønnes
@ 2019-04-07 17:02 ` Patchwork
  2019-04-07 17:10 ` ✗ Fi.CI.SPARSE: " Patchwork
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 41+ messages in thread
From: Patchwork @ 2019-04-07 17:02 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm/fb-helper: Move modesetting code to drm_client (rev2)
URL   : https://patchwork.freedesktop.org/series/58597/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
60e07d9925cc drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
0b30c352ab25 drm/fb-helper: Avoid race with DRM userspace
0fbd680b5973 drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
92a17a2eaf09 drm/fb-helper: No need to cache rotation and sw_rotations
c29ff7942699 drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
bbe8261ada7c drm/fb-helper: Remove drm_fb_helper_crtc
-:104: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#104: 
new file mode 100644

-:209: CHECK:LINE_SPACING: Please use a blank line after function/struct/union/enum declarations
#209: FILE: drivers/gpu/drm/drm_client_modeset.c:101:
+}
+/* TODO: Remove export when modeset code has been moved over */

-:903: WARNING:LONG_LINE: line over 100 characters
#903: FILE: drivers/gpu/drm/drm_fb_helper.c:2755:
+			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||

-:904: WARNING:LONG_LINE: line over 100 characters
#904: FILE: drivers/gpu/drm/drm_fb_helper.c:2756:
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))

-:1037: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'modeset' - possible side-effects?
#1037: FILE: include/drm/drm_client.h:163:
+#define drm_client_for_each_modeset(modeset, client) \
+	for (modeset = (client)->modesets; modeset && modeset->crtc; modeset++)

total: 0 errors, 3 warnings, 2 checks, 946 lines checked
4f0a9df0c515 drm/fb-helper: Prepare to move out commit code
9f4f3682bd7b drm/fb-helper: Move out commit code
-:152: WARNING:LONG_LINE: line over 100 characters
#152: FILE: drivers/gpu/drm/drm_client_modeset.c:221:
+			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);

-:285: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#285: FILE: drivers/gpu/drm/drm_client_modeset.c:354:
+			drm_object_property_set_value(&connector->base,
+				dev->mode_config.dpms_property, dpms_mode);

total: 0 errors, 1 warnings, 1 checks, 610 lines checked
e9458956045c drm/fb-helper: Remove drm_fb_helper_connector
-:588: WARNING:LONG_LINE: line over 100 characters
#588: FILE: drivers/gpu/drm/drm_fb_helper.c:1959:
+				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);

-:945: ERROR:COMPLEX_MACRO: Macros with complex values should be enclosed in parentheses
#945: FILE: include/drm/drm_client.h:181:
+#define drm_client_for_each_connector_iter(connector, iter) \
+	drm_for_each_connector_iter(connector, iter) \
+		if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)

-:945: CHECK:MACRO_ARG_REUSE: Macro argument reuse 'connector' - possible side-effects?
#945: FILE: include/drm/drm_client.h:181:
+#define drm_client_for_each_connector_iter(connector, iter) \
+	drm_for_each_connector_iter(connector, iter) \
+		if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)

total: 1 errors, 1 warnings, 1 checks, 1006 lines checked
d9c4bc11e19d drm/fb-helper: Prepare to move out modeset config code
-:167: WARNING:LONG_LINE: line over 100 characters
#167: FILE: drivers/gpu/drm/drm_fb_helper.c:2352:
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {

total: 0 errors, 1 warnings, 0 checks, 180 lines checked
0293a7f31f3f drm/fb-helper: Move out modeset config code
-:80: CHECK:BOOL_COMPARISON: Using comparison to false is error prone
#80: FILE: drivers/gpu/drm/drm_client_modeset.c:140:
+	if (cmdline_mode->specified == false)

-:151: WARNING:LONG_LINE: line over 100 characters
#151: FILE: drivers/gpu/drm/drm_client_modeset.c:211:
+			      connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");

-:295: CHECK:BOOL_COMPARISON: Using comparison to false is error prone
#295: FILE: drivers/gpu/drm/drm_client_modeset.c:355:
+		if (enabled[i] == false) {

-:329: WARNING:LONG_LINE: line over 100 characters
#329: FILE: drivers/gpu/drm/drm_client_modeset.c:389:
+				      connector->base.id, connector->tile_group ? connector->tile_group->id : 0);

-:385: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "!modes[n]"
#385: FILE: drivers/gpu/drm/drm_client_modeset.c:445:
+	if (modes[n] == NULL)

-:717: WARNING:LONG_LINE: line over 100 characters
#717: FILE: drivers/gpu/drm/drm_client_modeset.c:777:
+			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||

-:718: WARNING:LONG_LINE: line over 100 characters
#718: FILE: drivers/gpu/drm/drm_client_modeset.c:778:
+					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) {

-:1476: WARNING:LONG_LINE: line over 100 characters
#1476: FILE: include/drm/drm_client.h:155:
+int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height);

total: 0 errors, 5 warnings, 3 checks, 1448 lines checked
7d54fde89981 drm/client: Hack: Add bootsplash example
-:28: WARNING:CONFIG_DESCRIPTION: please write a paragraph that describes the config symbol fully
#28: FILE: drivers/gpu/drm/Kconfig:68:
+config DRM_CLIENT_BOOTSPLASH

-:49: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#49: 
new file mode 100644

-:54: WARNING:SPDX_LICENSE_TAG: Missing or malformed SPDX-License-Identifier tag in line 1
#54: FILE: drivers/gpu/drm/drm_bootsplash.c:1:
+/* DRM internal client example */

-:80: CHECK:UNCOMMENTED_DEFINITION: struct mutex definition without comment
#80: FILE: drivers/gpu/drm/drm_bootsplash.c:27:
+	struct mutex lock;

-:120: WARNING:LONG_LINE: line over 100 characters
#120: FILE: drivers/gpu/drm/drm_bootsplash.c:67:
+		splash->buffers[i] = drm_client_framebuffer_create(&splash->client, width, height, DRM_FORMAT_XRGB8888);

-:267: WARNING:LONG_LINE: line over 100 characters
#267: FILE: drivers/gpu/drm/drm_bootsplash.c:214:
+static int drm_bootsplash_draw(struct drm_bootsplash *splash, unsigned int sequence, unsigned int buffer_num)

total: 0 errors, 5 warnings, 1 checks, 413 lines checked

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* ✗ Fi.CI.SPARSE: warning for drm/fb-helper: Move modesetting code to drm_client (rev2)
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (12 preceding siblings ...)
  2019-04-07 17:02 ` ✗ Fi.CI.CHECKPATCH: warning for drm/fb-helper: Move modesetting code to drm_client (rev2) Patchwork
@ 2019-04-07 17:10 ` Patchwork
  2019-04-07 17:21 ` ✓ Fi.CI.BAT: success " Patchwork
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 41+ messages in thread
From: Patchwork @ 2019-04-07 17:10 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm/fb-helper: Move modesetting code to drm_client (rev2)
URL   : https://patchwork.freedesktop.org/series/58597/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Sparse version: v0.5.2
Commit: drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
Okay!

Commit: drm/fb-helper: Avoid race with DRM userspace
Okay!

Commit: drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
+drivers/gpu/drm/drm_fb_helper.c:2579:30: warning: expression using sizeof(void)
-O:drivers/gpu/drm/i915/intel_fbdev.c:333:30: warning: expression using sizeof(void)
+./include/linux/slab.h:666:13: error: not a function <noident>
-./include/linux/slab.h:666:13: error: undefined identifier '__builtin_mul_overflow'
-./include/linux/slab.h:666:13: warning: call with no type!

Commit: drm/fb-helper: No need to cache rotation and sw_rotations
Okay!

Commit: drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
-O:drivers/gpu/drm/drm_fb_helper.c:2035:40: warning: expression using sizeof(void)
-O:drivers/gpu/drm/drm_fb_helper.c:2035:40: warning: expression using sizeof(void)
-O:drivers/gpu/drm/drm_fb_helper.c:2036:40: warning: expression using sizeof(void)
-O:drivers/gpu/drm/drm_fb_helper.c:2036:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2035:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2035:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2036:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2036:40: warning: expression using sizeof(void)

Commit: drm/fb-helper: Remove drm_fb_helper_crtc
-O:drivers/gpu/drm/drm_fb_helper.c:2052:43: warning: expression using sizeof(void)
-O:drivers/gpu/drm/drm_fb_helper.c:2052:43: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2015:43: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2015:43: warning: expression using sizeof(void)
-./include/linux/slab.h:666:13: error: not a function <noident>
+./include/linux/slab.h:666:13: error: undefined identifier '__builtin_mul_overflow'
+./include/linux/slab.h:666:13: warning: call with no type!

Commit: drm/fb-helper: Prepare to move out commit code
+drivers/gpu/drm/drm_fb_helper.c:404:6: warning: symbol 'drm_client_panel_rotation' was not declared. Should it be static?
+drivers/gpu/drm/drm_fb_helper.c:579:5: warning: symbol 'drm_client_modeset_commit_force' was not declared. Should it be static?
+drivers/gpu/drm/drm_fb_helper.c:603:5: warning: symbol 'drm_client_modeset_commit' was not declared. Should it be static?
+drivers/gpu/drm/drm_fb_helper.c:739:5: warning: symbol 'drm_client_modeset_dpms' was not declared. Should it be static?

Commit: drm/fb-helper: Move out commit code
+drivers/gpu/drm/drm_fb_helper.c:1756:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1756:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1757:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1757:40: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1771:43: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1771:43: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1773:43: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:1773:43: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2277:30: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:3223:12: warning: symbol 'drm_fb_helper_modinit' was not declared. Should it be static?
-drivers/gpu/drm/drm_fb_helper.c:1756:40: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1756:40: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1757:40: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1757:40: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1771:43: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1771:43: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1773:43: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:1773:43: warning: expression using sizeof(void)
-drivers/gpu/drm/drm_fb_helper.c:2277:30: warning: expression using sizeof(void)
-O:drivers/gpu/drm/drm_fb_helper.c:404:6: warning: symbol 'drm_client_panel_rotation' was not declared. Should it be static?
-O:drivers/gpu/drm/drm_fb_helper.c:579:5: warning: symbol 'drm_client_modeset_commit_force' was not declared. Should it be static?
-O:drivers/gpu/drm/drm_fb_helper.c:603:5: warning: symbol 'drm_client_modeset_commit' was not declared. Should it be static?
-O:drivers/gpu/drm/drm_fb_helper.c:739:5: warning: symbol 'drm_client_modeset_dpms' was not declared. Should it be static?

Commit: drm/fb-helper: Remove drm_fb_helper_connector
-O:drivers/gpu/drm/drm_fb_helper.c:2277:30: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2076:30: warning: expression using sizeof(void)
-./include/linux/slab.h:666:13: error: not a function <noident>

Commit: drm/fb-helper: Prepare to move out modeset config code
-O:drivers/gpu/drm/drm_fb_helper.c:2076:30: warning: expression using sizeof(void)
+drivers/gpu/drm/drm_fb_helper.c:2080:30: warning: expression using sizeof(void)

Commit: drm/fb-helper: Move out modeset config code
+drivers/gpu/drm/drm_client_modeset.c:506:30: warning: expression using sizeof(void)
-O:drivers/gpu/drm/drm_fb_helper.c:2080:30: warning: expression using sizeof(void)
+./include/linux/slab.h:666:13: error: not a function <noident>
-./include/linux/slab.h:666:13: error: undefined identifier '__builtin_mul_overflow'
-./include/linux/slab.h:666:13: warning: call with no type!

Commit: drm/client: Hack: Add bootsplash example
+
+     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+drivers/gpu/drm/drm_client.c:167:5: warning: "CONFIG_DRM_CLIENT_BOOTSPLASH" is not defined, evaluates to 0 [-Wundef]
+drivers/gpu/drm/drm_client.c:167:5: warning: undefined preprocessor identifier 'CONFIG_DRM_CLIENT_BOOTSPLASH'
+drivers/gpu/drm/drm_client.c: In function ‘drm_client_dev_register’:
+Error in reading or end of file.
+ #if CONFIG_DRM_CLIENT_BOOTSPLASH

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* ✓ Fi.CI.BAT: success for drm/fb-helper: Move modesetting code to drm_client (rev2)
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (13 preceding siblings ...)
  2019-04-07 17:10 ` ✗ Fi.CI.SPARSE: " Patchwork
@ 2019-04-07 17:21 ` Patchwork
  2019-04-07 18:29 ` ✓ Fi.CI.IGT: " Patchwork
  2019-04-16  8:41 ` [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Daniel Vetter
  16 siblings, 0 replies; 41+ messages in thread
From: Patchwork @ 2019-04-07 17:21 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm/fb-helper: Move modesetting code to drm_client (rev2)
URL   : https://patchwork.freedesktop.org/series/58597/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5884 -> Patchwork_12720
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/58597/revisions/2/mbox/

Known issues
------------

  Here are the changes found in Patchwork_12720 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_cs_nop@fork-gfx0:
    - fi-icl-u2:          NOTRUN -> SKIP [fdo#109315] +17

  * igt@gem_exec_basic@basic-vebox:
    - fi-ivb-3770:        NOTRUN -> SKIP [fdo#109271] +48

  * igt@gem_exec_basic@readonly-bsd1:
    - fi-icl-u2:          NOTRUN -> SKIP [fdo#109276] +7

  * igt@gem_exec_parse@basic-allowed:
    - fi-icl-u2:          NOTRUN -> SKIP [fdo#109289] +1

  * igt@gem_exec_suspend@basic-s4-devices:
    - fi-icl-y:           PASS -> DMESG-WARN [fdo#109638]

  * igt@i915_selftest@live_contexts:
    - fi-icl-u2:          NOTRUN -> DMESG-FAIL [fdo#108569]

  * igt@kms_chamelium@dp-edid-read:
    - fi-icl-u2:          NOTRUN -> SKIP [fdo#109316] +2

  * igt@kms_chamelium@vga-edid-read:
    - fi-hsw-4770r:       NOTRUN -> SKIP [fdo#109271] +45

  * igt@kms_chamelium@vga-hpd-fast:
    - fi-icl-u2:          NOTRUN -> SKIP [fdo#109309] +1

  * igt@kms_force_connector_basic@prune-stale-modes:
    - fi-icl-u2:          NOTRUN -> SKIP [fdo#109285] +3

  * igt@kms_frontbuffer_tracking@basic:
    - fi-icl-u2:          NOTRUN -> FAIL [fdo#103167]

  * igt@runner@aborted:
    - fi-apl-guc:         NOTRUN -> FAIL [fdo#108622] / [fdo#109720]

  
#### Possible fixes ####

  * igt@i915_selftest@live_hangcheck:
    - fi-skl-iommu:       INCOMPLETE [fdo#108602] / [fdo#108744] -> PASS

  * igt@kms_frontbuffer_tracking@basic:
    - {fi-icl-u3}:        FAIL [fdo#103167] -> PASS
    - fi-byt-clapper:     FAIL [fdo#103167] -> PASS

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#108569]: https://bugs.freedesktop.org/show_bug.cgi?id=108569
  [fdo#108602]: https://bugs.freedesktop.org/show_bug.cgi?id=108602
  [fdo#108622]: https://bugs.freedesktop.org/show_bug.cgi?id=108622
  [fdo#108744]: https://bugs.freedesktop.org/show_bug.cgi?id=108744
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276
  [fdo#109285]: https://bugs.freedesktop.org/show_bug.cgi?id=109285
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109309]: https://bugs.freedesktop.org/show_bug.cgi?id=109309
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#109316]: https://bugs.freedesktop.org/show_bug.cgi?id=109316
  [fdo#109593]: https://bugs.freedesktop.org/show_bug.cgi?id=109593
  [fdo#109638]: https://bugs.freedesktop.org/show_bug.cgi?id=109638
  [fdo#109720]: https://bugs.freedesktop.org/show_bug.cgi?id=109720


Participating hosts (43 -> 41)
------------------------------

  Additional (4): fi-hsw-4770r fi-icl-dsi fi-icl-u2 fi-ivb-3770 
  Missing    (6): fi-kbl-soraka fi-ilk-m540 fi-bsw-n3050 fi-byt-squawks fi-bsw-cyan fi-bdw-samus 


Build changes
-------------

    * Linux: CI_DRM_5884 -> Patchwork_12720

  CI_DRM_5884: 2207e0443a52e545d5f62fcd5e14aadbf3830b6e @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4932: 08cf63a8fac11e3594b57580331fb319241a0d69 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_12720: 7d54fde899814324440c3b7a4a44782e3cf66eba @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

7d54fde89981 drm/client: Hack: Add bootsplash example
0293a7f31f3f drm/fb-helper: Move out modeset config code
d9c4bc11e19d drm/fb-helper: Prepare to move out modeset config code
e9458956045c drm/fb-helper: Remove drm_fb_helper_connector
9f4f3682bd7b drm/fb-helper: Move out commit code
4f0a9df0c515 drm/fb-helper: Prepare to move out commit code
bbe8261ada7c drm/fb-helper: Remove drm_fb_helper_crtc
c29ff7942699 drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
92a17a2eaf09 drm/fb-helper: No need to cache rotation and sw_rotations
0fbd680b5973 drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
0b30c352ab25 drm/fb-helper: Avoid race with DRM userspace
60e07d9925cc drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_12720/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* ✓ Fi.CI.IGT: success for drm/fb-helper: Move modesetting code to drm_client (rev2)
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (14 preceding siblings ...)
  2019-04-07 17:21 ` ✓ Fi.CI.BAT: success " Patchwork
@ 2019-04-07 18:29 ` Patchwork
  2019-04-16  8:41 ` [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Daniel Vetter
  16 siblings, 0 replies; 41+ messages in thread
From: Patchwork @ 2019-04-07 18:29 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx

== Series Details ==

Series: drm/fb-helper: Move modesetting code to drm_client (rev2)
URL   : https://patchwork.freedesktop.org/series/58597/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_5884_full -> Patchwork_12720_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  

Known issues
------------

  Here are the changes found in Patchwork_12720_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_create@create-clear:
    - shard-snb:          PASS -> INCOMPLETE [fdo#105411]

  * igt@gem_exec_schedule@independent-bsd1:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109276] +3

  * igt@gem_tiled_pread_pwrite:
    - shard-iclb:         PASS -> TIMEOUT [fdo#109673]

  * igt@gen3_render_tiledy_blits:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109289]

  * igt@i915_pm_rpm@pc8-residency:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109293]

  * igt@i915_selftest@live_workarounds:
    - shard-iclb:         PASS -> DMESG-FAIL [fdo#108954]

  * igt@kms_atomic_transition@4x-modeset-transitions-nonblocking:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_busy@extended-modeset-hang-newfb-render-a:
    - shard-skl:          NOTRUN -> DMESG-WARN [fdo#110222] +2

  * igt@kms_busy@extended-pageflip-modeset-hang-oldfb-render-a:
    - shard-snb:          PASS -> DMESG-WARN [fdo#110222]

  * igt@kms_chamelium@hdmi-edid-read:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109284] +2

  * igt@kms_color@pipe-a-ctm-max:
    - shard-skl:          NOTRUN -> FAIL [fdo#108147]

  * igt@kms_color@pipe-b-degamma:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] +39

  * igt@kms_content_protection@legacy:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109300]

  * igt@kms_cursor_crc@cursor-128x128-sliding:
    - shard-skl:          PASS -> FAIL [fdo#103232]

  * igt@kms_cursor_crc@cursor-256x256-suspend:
    - shard-skl:          PASS -> FAIL [fdo#103191] / [fdo#103232]

  * igt@kms_cursor_crc@cursor-512x512-rapid-movement:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109279]

  * igt@kms_cursor_crc@cursor-64x64-sliding:
    - shard-skl:          NOTRUN -> FAIL [fdo#103232]

  * igt@kms_cursor_crc@cursor-64x64-suspend:
    - shard-skl:          PASS -> INCOMPLETE [fdo#104108] / [fdo#107773]

  * igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109274]

  * igt@kms_cursor_legacy@cursor-vs-flip-varying-size:
    - shard-iclb:         PASS -> FAIL [fdo#103355]

  * igt@kms_flip@2x-flip-vs-expired-vblank-interruptible:
    - shard-glk:          PASS -> FAIL [fdo#105363]

  * igt@kms_flip@2x-flip-vs-panning-vs-hang:
    - shard-apl:          NOTRUN -> SKIP [fdo#109271] +6

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-spr-indfb-draw-render:
    - shard-snb:          PASS -> SKIP [fdo#109271]

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-blt:
    - shard-iclb:         PASS -> FAIL [fdo#109247] +11

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-render:
    - shard-skl:          NOTRUN -> FAIL [fdo#103167]

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-render:
    - shard-iclb:         PASS -> FAIL [fdo#103167] +3

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-pwrite:
    - shard-iclb:         NOTRUN -> FAIL [fdo#109247] +2

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-move:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109280] +3

  * igt@kms_frontbuffer_tracking@fbcpsr-rgb101010-draw-mmap-gtt:
    - shard-iclb:         PASS -> FAIL [fdo#105682] / [fdo#109247]

  * igt@kms_frontbuffer_tracking@fbcpsr-suspend:
    - shard-skl:          PASS -> INCOMPLETE [fdo#104108] / [fdo#106978]

  * igt@kms_frontbuffer_tracking@psr-rgb565-draw-render:
    - shard-skl:          PASS -> FAIL [fdo#103167] +1

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-d:
    - shard-skl:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +11

  * igt@kms_plane@pixel-format-pipe-b-planes-source-clamping:
    - shard-glk:          PASS -> SKIP [fdo#109271]

  * igt@kms_plane_alpha_blend@pipe-a-alpha-7efc:
    - shard-skl:          NOTRUN -> FAIL [fdo#107815] / [fdo#108145] +1

  * igt@kms_plane_alpha_blend@pipe-a-alpha-opaque-fb:
    - shard-skl:          NOTRUN -> FAIL [fdo#108145]

  * igt@kms_plane_alpha_blend@pipe-b-alpha-opaque-fb:
    - shard-snb:          NOTRUN -> SKIP [fdo#109271] / [fdo#109278] +3

  * igt@kms_plane_alpha_blend@pipe-b-coverage-7efc:
    - shard-skl:          NOTRUN -> FAIL [fdo#107815]

  * igt@kms_plane_alpha_blend@pipe-c-constant-alpha-min:
    - shard-skl:          PASS -> FAIL [fdo#108145] +1

  * igt@kms_plane_scaling@pipe-a-scaler-with-rotation:
    - shard-glk:          PASS -> SKIP [fdo#109271] / [fdo#109278]

  * igt@kms_psr@no_drrs:
    - shard-iclb:         PASS -> FAIL [fdo#108341]

  * igt@kms_psr@psr2_primary_mmap_cpu:
    - shard-iclb:         PASS -> SKIP [fdo#109441]

  * igt@kms_psr@sprite_plane_move:
    - shard-iclb:         PASS -> FAIL [fdo#107383] / [fdo#110215] +1

  * igt@kms_rotation_crc@multiplane-rotation:
    - shard-kbl:          PASS -> FAIL [fdo#109016]

  * igt@kms_vblank@pipe-b-ts-continuation-suspend:
    - shard-iclb:         PASS -> FAIL [fdo#104894]

  * igt@perf_pmu@busy-accuracy-50-vcs1:
    - shard-skl:          NOTRUN -> SKIP [fdo#109271] +174

  * igt@prime_nv_test@i915_import_gtt_mmap:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109291]

  * igt@v3d_get_param@get-bad-flags:
    - shard-iclb:         NOTRUN -> SKIP [fdo#109315]

  
#### Possible fixes ####

  * igt@gem_exec_reloc@basic-cpu-wc-active:
    - shard-iclb:         INCOMPLETE -> PASS

  * igt@gem_ppgtt@blt-vs-render-ctx0:
    - shard-iclb:         INCOMPLETE [fdo#109801] -> PASS

  * igt@gem_softpin@noreloc-s3:
    - shard-skl:          INCOMPLETE [fdo#104108] / [fdo#107773] -> PASS

  * igt@i915_pm_rpm@fences:
    - shard-skl:          INCOMPLETE [fdo#107807] -> PASS

  * igt@kms_atomic_transition@plane-all-modeset-transition-fencing:
    - shard-apl:          INCOMPLETE [fdo#103927] -> PASS

  * igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-blt:
    - shard-iclb:         FAIL [fdo#103167] -> PASS +3

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-cur-indfb-onoff:
    - shard-iclb:         FAIL [fdo#109247] -> PASS +11

  * igt@kms_plane_scaling@pipe-b-scaler-with-rotation:
    - shard-glk:          SKIP [fdo#109271] / [fdo#109278] -> PASS

  * igt@kms_psr@primary_mmap_cpu:
    - shard-iclb:         FAIL [fdo#107383] / [fdo#110215] -> PASS

  * igt@kms_psr@psr2_sprite_mmap_cpu:
    - shard-iclb:         SKIP [fdo#109441] -> PASS +1

  * igt@kms_rotation_crc@multiplane-rotation-cropping-bottom:
    - shard-kbl:          DMESG-FAIL [fdo#105763] -> PASS

  * igt@kms_setmode@basic:
    - shard-kbl:          FAIL [fdo#99912] -> PASS

  * igt@kms_vblank@pipe-a-ts-continuation-dpms-rpm:
    - shard-apl:          FAIL [fdo#104894] -> PASS

  * igt@perf@polling:
    - shard-iclb:         FAIL [fdo#108587] -> PASS

  
  [fdo#103167]: https://bugs.freedesktop.org/show_bug.cgi?id=103167
  [fdo#103191]: https://bugs.freedesktop.org/show_bug.cgi?id=103191
  [fdo#103232]: https://bugs.freedesktop.org/show_bug.cgi?id=103232
  [fdo#103355]: https://bugs.freedesktop.org/show_bug.cgi?id=103355
  [fdo#103927]: https://bugs.freedesktop.org/show_bug.cgi?id=103927
  [fdo#104108]: https://bugs.freedesktop.org/show_bug.cgi?id=104108
  [fdo#104894]: https://bugs.freedesktop.org/show_bug.cgi?id=104894
  [fdo#105363]: https://bugs.freedesktop.org/show_bug.cgi?id=105363
  [fdo#105411]: https://bugs.freedesktop.org/show_bug.cgi?id=105411
  [fdo#105682]: https://bugs.freedesktop.org/show_bug.cgi?id=105682
  [fdo#105763]: https://bugs.freedesktop.org/show_bug.cgi?id=105763
  [fdo#106978]: https://bugs.freedesktop.org/show_bug.cgi?id=106978
  [fdo#107383]: https://bugs.freedesktop.org/show_bug.cgi?id=107383
  [fdo#107773]: https://bugs.freedesktop.org/show_bug.cgi?id=107773
  [fdo#107807]: https://bugs.freedesktop.org/show_bug.cgi?id=107807
  [fdo#107815]: https://bugs.freedesktop.org/show_bug.cgi?id=107815
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#108147]: https://bugs.freedesktop.org/show_bug.cgi?id=108147
  [fdo#108341]: https://bugs.freedesktop.org/show_bug.cgi?id=108341
  [fdo#108587]: https://bugs.freedesktop.org/show_bug.cgi?id=108587
  [fdo#108954]: https://bugs.freedesktop.org/show_bug.cgi?id=108954
  [fdo#109016]: https://bugs.freedesktop.org/show_bug.cgi?id=109016
  [fdo#109247]: https://bugs.freedesktop.org/show_bug.cgi?id=109247
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109274]: https://bugs.freedesktop.org/show_bug.cgi?id=109274
  [fdo#109276]: https://bugs.freedesktop.org/show_bug.cgi?id=109276
  [fdo#109278]: https://bugs.freedesktop.org/show_bug.cgi?id=109278
  [fdo#109279]: https://bugs.freedesktop.org/show_bug.cgi?id=109279
  [fdo#109280]: https://bugs.freedesktop.org/show_bug.cgi?id=109280
  [fdo#109284]: https://bugs.freedesktop.org/show_bug.cgi?id=109284
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109291]: https://bugs.freedesktop.org/show_bug.cgi?id=109291
  [fdo#109293]: https://bugs.freedesktop.org/show_bug.cgi?id=109293
  [fdo#109300]: https://bugs.freedesktop.org/show_bug.cgi?id=109300
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#109673]: https://bugs.freedesktop.org/show_bug.cgi?id=109673
  [fdo#109801]: https://bugs.freedesktop.org/show_bug.cgi?id=109801
  [fdo#110215]: https://bugs.freedesktop.org/show_bug.cgi?id=110215
  [fdo#110222]: https://bugs.freedesktop.org/show_bug.cgi?id=110222
  [fdo#99912]: https://bugs.freedesktop.org/show_bug.cgi?id=99912


Participating hosts (10 -> 9)
------------------------------

  Missing    (1): shard-hsw 


Build changes
-------------

    * Linux: CI_DRM_5884 -> Patchwork_12720

  CI_DRM_5884: 2207e0443a52e545d5f62fcd5e14aadbf3830b6e @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4932: 08cf63a8fac11e3594b57580331fb319241a0d69 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_12720: 7d54fde899814324440c3b7a4a44782e3cf66eba @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_12720/
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-04-07 16:52 ` [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
@ 2019-04-11 14:25   ` Noralf Trønnes
  2019-04-23 14:17   ` Thomas Zimmermann
  1 sibling, 0 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-11 14:25 UTC (permalink / raw)
  To: dri-devel; +Cc: Jani Nikula, daniel.vetter, intel-gfx, Rodrigo Vivi



Den 07.04.2019 18.52, skrev Noralf Trønnes:
> It is generic code and having it in the helper will let other drivers
> benefit from it.
> 
> One change was necessary assuming this to be true:
> INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc
> 
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: intel-gfx@lists.freedesktop.org
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Reviewed-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
>  include/drm/drm_fb_helper.h        |  23 ---
>  3 files changed, 190 insertions(+), 245 deletions(-)
> 

Applied to drm-misc-next.

Noralf.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-07 16:52 ` [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
@ 2019-04-16  7:59   ` Daniel Vetter
  2019-04-16 18:46     ` Noralf Trønnes
  2019-04-16  9:26   ` Maxime Ripard
  1 sibling, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2019-04-16  7:59 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

On Sun, Apr 07, 2019 at 06:52:33PM +0200, Noralf Trønnes wrote:
> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
> This is done by looking at the fb on the primary plane. By the time
> fb-helper gets around to committing, it's possible that the facts have
> changed.
> 
> Avoid this race by holding the drm_device->master_mutex lock while
> committing. When DRM userspace does its first open, it will now wait
> until fb-helper is done. The helper will stay away if there's a master.
> 
> Locking rule: Always take the fb-helper lock first.
> 
> v2:
> - Remove drm_fb_helper_is_bound() (Daniel Vetter)
> - No need to check fb_helper->dev->master in
>   drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.
> 
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++
>  drivers/gpu/drm/drm_fb_helper.c | 90 ++++++++++++++++-----------------
>  drivers/gpu/drm/drm_internal.h  |  2 +
>  3 files changed, 67 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> index 1669c42c40ed..db199807b7dc 100644
> --- a/drivers/gpu/drm/drm_auth.c
> +++ b/drivers/gpu/drm/drm_auth.c
> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
>  	*master = NULL;
>  }
>  EXPORT_SYMBOL(drm_master_put);
> +
> +/* Used by drm_client and drm_fb_helper */
> +bool drm_master_internal_acquire(struct drm_device *dev)
> +{
> +	mutex_lock(&dev->master_mutex);
> +	if (dev->master) {
> +		mutex_unlock(&dev->master_mutex);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +EXPORT_SYMBOL(drm_master_internal_acquire);
> +
> +/* Used by drm_client and drm_fb_helper */
> +void drm_master_internal_release(struct drm_device *dev)
> +{
> +	mutex_unlock(&dev->master_mutex);
> +}
> +EXPORT_SYMBOL(drm_master_internal_release);
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 84791dd4a90d..a6be09ae899b 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -44,6 +44,7 @@
>  
>  #include "drm_crtc_internal.h"
>  #include "drm_crtc_helper_internal.h"
> +#include "drm_internal.h"
>  
>  static bool drm_fbdev_emulation = true;
>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
> @@ -509,7 +510,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
>  	return ret;
>  }
>  
> -static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> +static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)

Bikeshed: usually the function variant that's run with locks already taken
is called _locked or has a __ prefix. _force feels a bit misplaced.
>  {
>  	struct drm_device *dev = fb_helper->dev;
>  
> @@ -519,6 +520,21 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>  		return restore_fbdev_mode_legacy(fb_helper);
>  }
>  
> +static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> +{
> +	struct drm_device *dev = fb_helper->dev;
> +	int ret;
> +
> +	if (!drm_master_internal_acquire(dev))
> +		return -EBUSY;
> +
> +	ret = restore_fbdev_mode_force(fb_helper);
> +
> +	drm_master_internal_release(dev);
> +
> +	return ret;
> +}
> +
>  /**
>   * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
>   * @fb_helper: driver-allocated fbdev helper, can be NULL
> @@ -556,34 +572,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>  }
>  EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
>  
> -static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
> -{
> -	struct drm_device *dev = fb_helper->dev;
> -	struct drm_crtc *crtc;
> -	int bound = 0, crtcs_bound = 0;
> -
> -	/*
> -	 * Sometimes user space wants everything disabled, so don't steal the
> -	 * display if there's a master.
> -	 */
> -	if (READ_ONCE(dev->master))
> -		return false;
> -
> -	drm_for_each_crtc(crtc, dev) {
> -		drm_modeset_lock(&crtc->mutex, NULL);
> -		if (crtc->primary->fb)
> -			crtcs_bound++;
> -		if (crtc->primary->fb == fb_helper->fb)
> -			bound++;
> -		drm_modeset_unlock(&crtc->mutex);
> -	}
> -
> -	if (bound < crtcs_bound)
> -		return false;
> -
> -	return true;
> -}
> -
>  #ifdef CONFIG_MAGIC_SYSRQ
>  /*
>   * restore fbcon display for all kms driver's using this helper, used for sysrq
> @@ -604,7 +592,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
>  			continue;
>  
>  		mutex_lock(&helper->lock);
> -		ret = restore_fbdev_mode(helper);
> +		ret = restore_fbdev_mode_force(helper);

I'd leave this as-is, because:
a) I'm too lazy to review the locking of our open/close calls to convince
myself that lastclose can't race with the next open
b) it won't hurt
c) leaves the door open to easily make our open/close more concurrent in
the future

>  		if (ret)
>  			error = true;
>  		mutex_unlock(&helper->lock);
> @@ -663,20 +651,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
>  
>  	/*
>  	 * For each CRTC in this fb, turn the connectors on/off.
>  	 */
>  	mutex_lock(&fb_helper->lock);
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> -		mutex_unlock(&fb_helper->lock);
> -		return;
> -	}
> +	if (!drm_master_internal_acquire(dev))
> +		goto unlock;
>  
> -	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
> +	if (drm_drv_uses_atomic_modeset(dev))
>  		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
>  	else
>  		dpms_legacy(fb_helper, dpms_mode);
> +
> +	drm_master_internal_release(dev);
> +unlock:
>  	mutex_unlock(&fb_helper->lock);
>  }
>  
> @@ -1509,6 +1499,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
>  	int ret;
>  
>  	if (oops_in_progress)
> @@ -1516,9 +1507,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  
>  	mutex_lock(&fb_helper->lock);
>  
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> +	if (!drm_master_internal_acquire(dev)) {
>  		ret = -EBUSY;
> -		goto out;
> +		goto unlock;
>  	}
>  
>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
> @@ -1528,7 +1519,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  	else
>  		ret = setcmap_legacy(cmap, info);
>  
> -out:
> +	drm_master_internal_release(dev);
> +unlock:
>  	mutex_unlock(&fb_helper->lock);
>  
>  	return ret;
> @@ -1548,12 +1540,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>  			unsigned long arg)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
>  	struct drm_mode_set *mode_set;
>  	struct drm_crtc *crtc;
>  	int ret = 0;
>  
>  	mutex_lock(&fb_helper->lock);
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> +	if (!drm_master_internal_acquire(dev)) {
>  		ret = -EBUSY;
>  		goto unlock;
>  	}
> @@ -1591,11 +1584,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>  		}
>  
>  		ret = 0;
> -		goto unlock;
> +		break;
>  	default:
>  		ret = -ENOTTY;
>  	}
>  
> +	drm_master_internal_release(dev);
>  unlock:
>  	mutex_unlock(&fb_helper->lock);
>  	return ret;
> @@ -1847,15 +1841,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
>  		return -EBUSY;
>  
>  	mutex_lock(&fb_helper->lock);
> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> -		mutex_unlock(&fb_helper->lock);
> -		return -EBUSY;
> +	if (!drm_master_internal_acquire(dev)) {
> +		ret = -EBUSY;
> +		goto unlock;
>  	}
>  
>  	if (drm_drv_uses_atomic_modeset(dev))
>  		ret = pan_display_atomic(var, info);
>  	else
>  		ret = pan_display_legacy(var, info);
> +
> +	drm_master_internal_release(dev);
> +unlock:
>  	mutex_unlock(&fb_helper->lock);
>  
>  	return ret;
> @@ -2014,7 +2011,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		DRM_INFO("Cannot find any crtc or sizes\n");
>  
>  		/* First time: disable all crtc's.. */
> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
> +		if (!fb_helper->deferred_setup)
>  			restore_fbdev_mode(fb_helper);

I think we need to return the errno here, since without that the higher
levels won't reprobe correctly. Plus we need to remap -EBUSY to -EAGAIN
(or change the check in __drm_fb_helper_initial_config_and_unlock to also
retry on -EBUSY).

>  		return -EAGAIN;
>  	}
> @@ -2842,6 +2839,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
>   */
>  int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
>  {
> +	struct drm_device *dev = fb_helper->dev;
>  	int err = 0;
>  
>  	if (!drm_fbdev_emulation || !fb_helper)
> @@ -2854,12 +2852,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
>  		return err;
>  	}
>  
> -	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
> +	if (!fb_helper->fb || !drm_master_internal_acquire(dev)) {
>  		fb_helper->delayed_hotplug = true;
>  		mutex_unlock(&fb_helper->lock);
>  		return err;
>  	}
>  
> +	drm_master_internal_release(dev);
> +
>  	DRM_DEBUG_KMS("\n");
>  
>  	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index d9a483a5fce0..3ee97c9998a2 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
>  			 struct drm_file *file_priv);
>  int drm_master_open(struct drm_file *file_priv);
>  void drm_master_release(struct drm_file *file_priv);
> +bool drm_master_internal_acquire(struct drm_device *dev);
> +void drm_master_internal_release(struct drm_device *dev);
>  
>  /* drm_sysfs.c */
>  extern struct class *drm_class;

With the nits addressed:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> -- 
> 2.20.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 06/12] drm/fb-helper: Remove drm_fb_helper_crtc
  2019-04-07 16:52 ` [PATCH v2 06/12] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
@ 2019-04-16  8:34   ` Daniel Vetter
  0 siblings, 0 replies; 41+ messages in thread
From: Daniel Vetter @ 2019-04-16  8:34 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

On Sun, Apr 07, 2019 at 06:52:37PM +0200, Noralf Trønnes wrote:
> It now only contains the modeset so use that directly instead and attach
> a modeset array to drm_client_dev. drm_fb_helper will use this array.
> Code will later be moved to drm_client, so add code there in a new file
> drm_client_modeset.c with MIT license to match drm_fb_helper.c.
> 
> The modeset connector array size is hardcoded for the cloned case to avoid
> having to pass in a value from the driver. A value of 8 is chosen to err
> on the safe side. This means that the max connector argument for
> drm_fb_helper_init() and drm_fb_helper_fbdev_setup() isn't used anymore,
> a todo entry for this is added.
> 
> In pan_display_atomic() restore_fbdev_mode_force() is used instead of
> restore_fbdev_mode_atomic() because that one will later become internal
> to drm_client_modeset.
> 
> Locking order:
> 1. drm_fb_helper->lock
> 2. drm_master_internal_acquire
> 3. drm_client_dev->modeset_mutex
> 
> v2:
> - Add modesets array to drm_client (Daniel Vetter)
> - Use a new file for the modeset code (Daniel Vetter)
> - File has to be MIT licensed (Emmanuel Vadot)
> - Add copyrights from drm_fb_helper.c
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  Documentation/gpu/todo.rst           |   7 +
>  drivers/gpu/drm/Makefile             |   2 +-
>  drivers/gpu/drm/drm_client.c         |  10 +-
>  drivers/gpu/drm/drm_client_modeset.c | 102 +++++++++
>  drivers/gpu/drm/drm_fb_helper.c      | 301 +++++++++++----------------
>  include/drm/drm_client.h             |  28 +++
>  include/drm/drm_fb_helper.h          |   8 -
>  7 files changed, 272 insertions(+), 186 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_client_modeset.c
> 
> diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
> index 1528ad2d598b..8fa08b5feab7 100644
> --- a/Documentation/gpu/todo.rst
> +++ b/Documentation/gpu/todo.rst
> @@ -300,6 +300,13 @@ it to use drm_mode_hsync() instead.
>  
>  Contact: Sean Paul
>  
> +drm_fb_helper cleanup tasks
> +---------------------------
> +
> +- The max connector argument for drm_fb_helper_init() and
> +  drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
> +
> +
>  Core refactorings
>  =================
>  
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 6c7e8d162b4e..08c77c10ccbb 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -19,7 +19,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
>  		drm_plane.o drm_color_mgmt.o drm_print.o \
>  		drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
>  		drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
> -		drm_atomic_uapi.o
> +		drm_client_modeset.o drm_atomic_uapi.o
>  
>  drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
>  drm-$(CONFIG_DRM_VM) += drm_vm.o
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index 9b2bd28dde0a..3ad5b57c1419 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -91,14 +91,20 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
>  	client->name = name;
>  	client->funcs = funcs;
>  
> -	ret = drm_client_open(client);
> +	ret = drm_client_modeset_create(client);
>  	if (ret)
>  		goto err_put_module;
>  
> +	ret = drm_client_open(client);
> +	if (ret)
> +		goto err_free;
> +
>  	drm_dev_get(dev);
>  
>  	return 0;
>  
> +err_free:
> +	drm_client_modeset_free(client);
>  err_put_module:
>  	if (funcs)
>  		module_put(funcs->owner);
> @@ -147,6 +153,8 @@ void drm_client_release(struct drm_client_dev *client)
>  
>  	DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
>  
> +	drm_client_modeset_release(client);
> +	drm_client_modeset_free(client);
>  	drm_client_close(client);
>  	drm_dev_put(dev);
>  	if (client->funcs)
> diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
> new file mode 100644
> index 000000000000..bb34222c9db8
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_client_modeset.c
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright 2018 Noralf Trønnes
> + * Copyright (c) 2006-2009 Red Hat Inc.
> + * Copyright (c) 2006-2008 Intel Corporation
> + *   Jesse Barnes <jesse.barnes@intel.com>
> + * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +#include <drm/drm_client.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_device.h>
> +
> +/* Used by drm_client and drm_fb_helper */
> +int drm_client_modeset_create(struct drm_client_dev *client)
> +{
> +	struct drm_device *dev = client->dev;
> +	unsigned int num_crtc = dev->mode_config.num_crtc;
> +	unsigned int max_connector_count = 1;
> +	struct drm_mode_set *modeset;
> +	struct drm_crtc *crtc;
> +	unsigned int i = 0;
> +
> +	/* Add terminating zero entry to enable index less iteration */
> +	client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL);
> +	if (!client->modesets)
> +		return -ENOMEM;
> +
> +	mutex_init(&client->modeset_mutex);
> +
> +	drm_for_each_crtc(crtc, dev)
> +		client->modesets[i++].crtc = crtc;
> +
> +	/* Cloning is only supported in the single crtc case. */
> +	if (num_crtc == 1)
> +		max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS;
> +
> +	drm_client_for_each_modeset(modeset, client) {
> +		modeset->connectors = kcalloc(max_connector_count,
> +					      sizeof(*modeset->connectors), GFP_KERNEL);
> +		if (!modeset->connectors)
> +			goto err_free;
> +	}
> +
> +	return 0;
> +
> +err_free:
> +	drm_client_modeset_free(client);
> +
> +	return -ENOMEM;
> +}
> +EXPORT_SYMBOL(drm_client_modeset_create);
> +
> +/* Used by drm_client and drm_fb_helper */
> +void drm_client_modeset_free(struct drm_client_dev *client)
> +{
> +	struct drm_mode_set *modeset;
> +
> +	mutex_destroy(&client->modeset_mutex);
> +
> +	drm_client_for_each_modeset(modeset, client)
> +		kfree(modeset->connectors);
> +	kfree(client->modesets);
> +}
> +EXPORT_SYMBOL(drm_client_modeset_free);
> +
> +/* Used by drm_client and drm_fb_helper */
> +void drm_client_modeset_release(struct drm_client_dev *client)
> +{
> +	struct drm_mode_set *modeset;
> +	unsigned int i;
> +
> +	drm_client_for_each_modeset(modeset, client) {
> +		drm_mode_destroy(client->dev, modeset->mode);
> +		modeset->mode = NULL;
> +		modeset->fb = NULL;
> +
> +		for (i = 0; i < modeset->num_connectors; i++) {
> +			drm_connector_put(modeset->connectors[i]);
> +			modeset->connectors[i] = NULL;
> +		}
> +		modeset->num_connectors = 0;
> +	}
> +}
> +EXPORT_SYMBOL(drm_client_modeset_release);
> +
> +struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc)
> +{
> +	struct drm_mode_set *modeset;
> +
> +	drm_client_for_each_modeset(modeset, client)
> +		if (modeset->crtc == crtc)
> +			return modeset;
> +
> +	return NULL;
> +}
> +/* TODO: Remove export when modeset code has been moved over */
> +EXPORT_SYMBOL(drm_client_find_modeset);
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 69dddc4a9231..b65edfc99feb 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -317,13 +317,11 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
>  {
>  	struct drm_fb_helper *helper = info->par;
>  	const struct drm_crtc_helper_funcs *funcs;
> -	int i;
> +	struct drm_mode_set *mode_set;
>  
>  	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
> -		for (i = 0; i < helper->crtc_count; i++) {
> -			struct drm_mode_set *mode_set =
> -				&helper->crtc_info[i].mode_set;
> -
> +		mutex_lock(&helper->client.modeset_mutex);
> +		drm_client_for_each_modeset(mode_set, &helper->client) {
>  			if (!mode_set->crtc->enabled)
>  				continue;
>  
> @@ -340,6 +338,7 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
>  						    mode_set->y,
>  						    ENTER_ATOMIC_MODE_SET);
>  		}
> +		mutex_unlock(&helper->client.modeset_mutex);
>  	}
>  
>  	return 0;
> @@ -353,14 +352,14 @@ EXPORT_SYMBOL(drm_fb_helper_debug_enter);
>  int drm_fb_helper_debug_leave(struct fb_info *info)
>  {
>  	struct drm_fb_helper *helper = info->par;
> +	struct drm_client_dev *client = &helper->client;
>  	struct drm_crtc *crtc;
>  	const struct drm_crtc_helper_funcs *funcs;
> +	struct drm_mode_set *mode_set;
>  	struct drm_framebuffer *fb;
> -	int i;
> -
> -	for (i = 0; i < helper->crtc_count; i++) {
> -		struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
>  
> +	mutex_lock(&client->modeset_mutex);
> +	drm_client_for_each_modeset(mode_set, client) {
>  		crtc = mode_set->crtc;
>  		if (drm_drv_uses_atomic_modeset(crtc->dev))
>  			continue;
> @@ -383,6 +382,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
>  		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
>  					    crtc->y, LEAVE_ATOMIC_MODE_SET);
>  	}
> +	mutex_unlock(&client->modeset_mutex);
>  
>  	return 0;
>  }
> @@ -433,12 +433,14 @@ static bool drm_fb_helper_panel_rotation(struct drm_mode_set *modeset,
>  
>  static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
>  {
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_device *dev = fb_helper->dev;
>  	struct drm_plane_state *plane_state;
>  	struct drm_plane *plane;
>  	struct drm_atomic_state *state;
> -	int i, ret;
>  	struct drm_modeset_acquire_ctx ctx;
> +	struct drm_mode_set *mode_set;
> +	int ret;
>  
>  	drm_modeset_acquire_init(&ctx, 0);
>  
> @@ -468,8 +470,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
>  			goto out_state;
>  	}
>  
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
> +	drm_client_for_each_modeset(mode_set, client) {
>  		struct drm_plane *primary = mode_set->crtc->primary;
>  		unsigned int rotation;
>  
> @@ -517,9 +518,11 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
>  
>  static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
>  {
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_device *dev = fb_helper->dev;
> +	struct drm_mode_set *mode_set;
>  	struct drm_plane *plane;
> -	int i, ret = 0;
> +	int ret = 0;
>  
>  	drm_modeset_lock_all(fb_helper->dev);
>  	drm_for_each_plane(plane, dev) {
> @@ -532,8 +535,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
>  						    DRM_MODE_ROTATE_0);
>  	}
>  
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
> +	drm_client_for_each_modeset(mode_set, client) {
>  		struct drm_crtc *crtc = mode_set->crtc;
>  
>  		if (crtc->funcs->cursor_set2) {
> @@ -559,11 +561,16 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
>  static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
>  {
>  	struct drm_device *dev = fb_helper->dev;
> +	int ret;
>  
> +	mutex_lock(&fb_helper->client.modeset_mutex);
>  	if (drm_drv_uses_atomic_modeset(dev))
> -		return restore_fbdev_mode_atomic(fb_helper, true);
> +		ret = restore_fbdev_mode_atomic(fb_helper, true);
>  	else
> -		return restore_fbdev_mode_legacy(fb_helper);
> +		ret = restore_fbdev_mode_legacy(fb_helper);
> +	mutex_unlock(&fb_helper->client.modeset_mutex);
> +
> +	return ret;
>  }
>  
>  static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> @@ -672,15 +679,14 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
>  
>  static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
>  {
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_device *dev = fb_helper->dev;
>  	struct drm_connector *connector;
>  	struct drm_mode_set *modeset;
> -	int i, j;
> +	int j;
>  
>  	drm_modeset_lock_all(dev);
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		modeset = &fb_helper->crtc_info[i].mode_set;
> -
> +	drm_client_for_each_modeset(modeset, client) {
>  		if (!modeset->crtc->enabled)
>  			continue;
>  
> @@ -697,6 +703,7 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_device *dev = fb_helper->dev;
>  
>  	/*
> @@ -706,10 +713,12 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>  	if (!drm_master_internal_acquire(dev))
>  		goto unlock;
>  
> +	mutex_lock(&client->modeset_mutex);
>  	if (drm_drv_uses_atomic_modeset(dev))
>  		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
>  	else
>  		dpms_legacy(fb_helper, dpms_mode);
> +	mutex_unlock(&client->modeset_mutex);
>  
>  	drm_master_internal_release(dev);
>  unlock:
> @@ -752,43 +761,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
>  }
>  EXPORT_SYMBOL(drm_fb_helper_blank);
>  
> -static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
> -					  struct drm_mode_set *modeset)
> -{
> -	int i;
> -
> -	for (i = 0; i < modeset->num_connectors; i++) {
> -		drm_connector_put(modeset->connectors[i]);
> -		modeset->connectors[i] = NULL;
> -	}
> -	modeset->num_connectors = 0;
> -
> -	drm_mode_destroy(helper->dev, modeset->mode);
> -	modeset->mode = NULL;
> -
> -	/* FIXME should hold a ref? */
> -	modeset->fb = NULL;
> -}
> -
> -static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
> -{
> -	int i;
> -
> -	for (i = 0; i < helper->connector_count; i++) {
> -		drm_connector_put(helper->connector_info[i]->connector);
> -		kfree(helper->connector_info[i]);
> -	}
> -	kfree(helper->connector_info);
> -
> -	for (i = 0; i < helper->crtc_count; i++) {
> -		struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
> -
> -		drm_fb_helper_modeset_release(helper, modeset);
> -		kfree(modeset->connectors);
> -	}
> -	kfree(helper->crtc_info);
> -}
> -
>  static void drm_fb_helper_resume_worker(struct work_struct *work)
>  {
>  	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
> @@ -867,7 +839,7 @@ EXPORT_SYMBOL(drm_fb_helper_prepare);
>   * drm_fb_helper_init - initialize a &struct drm_fb_helper
>   * @dev: drm device
>   * @fb_helper: driver-allocated fbdev helper structure to initialize
> - * @max_conn_count: max connector count
> + * @max_conn_count: max connector count (not used)
>   *
>   * This allocates the structures for the fbdev helper with the given limits.
>   * Note that this won't yet touch the hardware (through the driver interfaces)
> @@ -883,53 +855,34 @@ int drm_fb_helper_init(struct drm_device *dev,
>  		       struct drm_fb_helper *fb_helper,
>  		       int max_conn_count)
>  {
> -	struct drm_crtc *crtc;
> -	struct drm_mode_config *config = &dev->mode_config;
> -	int i;
> +	int ret;
>  
>  	if (!drm_fbdev_emulation) {
>  		dev->fb_helper = fb_helper;
>  		return 0;
>  	}
>  
> -	if (!max_conn_count)
> -		return -EINVAL;
> -
> -	fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
> -	if (!fb_helper->crtc_info)
> -		return -ENOMEM;
> -
> -	fb_helper->crtc_count = config->num_crtc;
> -	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
> -	if (!fb_helper->connector_info) {
> -		kfree(fb_helper->crtc_info);
> -		return -ENOMEM;
> +	/* The generic fbdev client has already done this */
> +	if (!fb_helper->client.funcs) {
> +		fb_helper->client.dev = dev;
> +		ret = drm_client_modeset_create(&fb_helper->client);
> +		if (ret)
> +			return ret;

Hm, this is a bit annoying since it's the only reason we need to
EXPORT_SYMBOL all the new functions. What I had in mind is to call
drm_client_init here, with a no-op ->unregister function because the
lifetimes of the embedded drm_client_dev in the drm_fb_helper (which
drivers usually embedded somewhere else outside of our control) differs
from a real drm_client.

>  	}
> +
> +	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
> +	if (!fb_helper->connector_info)
> +		goto out_free;
> +
>  	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
>  	fb_helper->connector_count = 0;
>  
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		fb_helper->crtc_info[i].mode_set.connectors =
> -			kcalloc(max_conn_count,
> -				sizeof(struct drm_connector *),
> -				GFP_KERNEL);
> -
> -		if (!fb_helper->crtc_info[i].mode_set.connectors)
> -			goto out_free;
> -		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
> -	}
> -
> -	i = 0;
> -	drm_for_each_crtc(crtc, dev) {
> -		fb_helper->crtc_info[i].mode_set.crtc = crtc;
> -		i++;
> -	}
> -
>  	dev->fb_helper = fb_helper;
>  
>  	return 0;
>  out_free:
> -	drm_fb_helper_crtc_free(fb_helper);
> +	drm_client_modeset_free(&fb_helper->client);
> +
>  	return -ENOMEM;
>  }
>  EXPORT_SYMBOL(drm_fb_helper_init);
> @@ -1005,6 +958,7 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
>  void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
>  {
>  	struct fb_info *info;
> +	int i;
>  
>  	if (!fb_helper)
>  		return;
> @@ -1034,8 +988,17 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
>  	mutex_unlock(&kernel_fb_helper_lock);
>  
>  	mutex_destroy(&fb_helper->lock);
> -	drm_fb_helper_crtc_free(fb_helper);
>  
> +	if (!fb_helper->client.funcs) {
> +		drm_client_modeset_release(&fb_helper->client);
> +		drm_client_modeset_free(&fb_helper->client);
> +	}

We should then also be able to call drm_client_release here if funcs
matches our fake client functions. Since we won't call drm_client_register
there's not going to be an issue with client->list I think.

> +
> +	for (i = 0; i < fb_helper->connector_count; i++) {
> +		drm_connector_put(fb_helper->connector_info[i]->connector);
> +		kfree(fb_helper->connector_info[i]);
> +	}
> +	kfree(fb_helper->connector_info);
>  }
>  EXPORT_SYMBOL(drm_fb_helper_fini);
>  
> @@ -1380,13 +1343,14 @@ static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
>  static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_mode_set *modeset;
>  	struct drm_crtc *crtc;
>  	u16 *r, *g, *b;
> -	int i, ret = 0;
> +	int ret = 0;
>  
>  	drm_modeset_lock_all(fb_helper->dev);
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		crtc = fb_helper->crtc_info[i].mode_set.crtc;
> +	drm_client_for_each_modeset(modeset, &fb_helper->client) {
> +		crtc = modeset->crtc;
>  		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
>  			return -EINVAL;
>  
> @@ -1462,10 +1426,11 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>  	struct drm_modeset_acquire_ctx ctx;
>  	struct drm_crtc_state *crtc_state;
>  	struct drm_atomic_state *state;
> +	struct drm_mode_set *modeset;
>  	struct drm_crtc *crtc;
>  	u16 *r, *g, *b;
> -	int i, ret = 0;
>  	bool replaced;
> +	int ret = 0;
>  
>  	drm_modeset_acquire_init(&ctx, 0);
>  
> @@ -1477,8 +1442,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>  
>  	state->acquire_ctx = &ctx;
>  retry:
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		crtc = fb_helper->crtc_info[i].mode_set.crtc;
> +	drm_client_for_each_modeset(modeset, &fb_helper->client) {
> +		crtc = modeset->crtc;
>  
>  		if (!gamma_lut)
>  			gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
> @@ -1506,8 +1471,8 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>  	if (ret)
>  		goto out_state;
>  
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		crtc = fb_helper->crtc_info[i].mode_set.crtc;
> +	drm_client_for_each_modeset(modeset, &fb_helper->client) {
> +		crtc = modeset->crtc;
>  
>  		r = crtc->gamma_store;
>  		g = r + crtc->gamma_size;
> @@ -1557,12 +1522,14 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>  		goto unlock;
>  	}
>  
> +	mutex_lock(&fb_helper->client.modeset_mutex);
>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
>  		ret = setcmap_pseudo_palette(cmap, info);
>  	else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
>  		ret = setcmap_atomic(cmap, info);
>  	else
>  		ret = setcmap_legacy(cmap, info);
> +	mutex_unlock(&fb_helper->client.modeset_mutex);
>  
>  	drm_master_internal_release(dev);
>  unlock:
> @@ -1586,7 +1553,6 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
>  	struct drm_device *dev = fb_helper->dev;
> -	struct drm_mode_set *mode_set;
>  	struct drm_crtc *crtc;
>  	int ret = 0;
>  
> @@ -1614,8 +1580,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>  		 * make. If we're not smart enough here, one should
>  		 * just consider switch the userspace to KMS.
>  		 */
> -		mode_set = &fb_helper->crtc_info[0].mode_set;
> -		crtc = mode_set->crtc;
> +		crtc = fb_helper->client.modesets[0].crtc;
>  
>  		/*
>  		 * Only wait for a vblank event if the CRTC is
> @@ -1812,16 +1777,14 @@ EXPORT_SYMBOL(drm_fb_helper_set_par);
>  
>  static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
>  {
> -	int i;
> -
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		struct drm_mode_set *mode_set;
> -
> -		mode_set = &fb_helper->crtc_info[i].mode_set;
> +	struct drm_mode_set *mode_set;
>  
> +	mutex_lock(&fb_helper->client.modeset_mutex);
> +	drm_client_for_each_modeset(mode_set, &fb_helper->client) {
>  		mode_set->x = x;
>  		mode_set->y = y;
>  	}
> +	mutex_unlock(&fb_helper->client.modeset_mutex);
>  }
>  
>  static int pan_display_atomic(struct fb_var_screeninfo *var,
> @@ -1832,7 +1795,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
>  
>  	pan_set(fb_helper, var->xoffset, var->yoffset);
>  
> -	ret = restore_fbdev_mode_atomic(fb_helper, true);
> +	ret = restore_fbdev_mode_force(fb_helper);
>  	if (!ret) {
>  		info->var.xoffset = var->xoffset;
>  		info->var.yoffset = var->yoffset;
> @@ -1846,14 +1809,13 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
>  			      struct fb_info *info)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_mode_set *modeset;
>  	int ret = 0;
> -	int i;
>  
>  	drm_modeset_lock_all(fb_helper->dev);
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		modeset = &fb_helper->crtc_info[i].mode_set;
> -
> +	mutex_lock(&client->modeset_mutex);
> +	drm_client_for_each_modeset(modeset, client) {
>  		modeset->x = var->xoffset;
>  		modeset->y = var->yoffset;
>  
> @@ -1865,6 +1827,7 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
>  			}
>  		}
>  	}
> +	mutex_unlock(&client->modeset_mutex);
>  	drm_modeset_unlock_all(fb_helper->dev);
>  
>  	return ret;
> @@ -1911,10 +1874,12 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
>  static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  					 int preferred_bpp)
>  {
> +	struct drm_client_dev *client = &fb_helper->client;
>  	int ret = 0;
>  	int crtc_count = 0;
>  	int i;
>  	struct drm_fb_helper_surface_size sizes;
> +	struct drm_mode_set *mode_set;
>  	int best_depth = 0;
>  
>  	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
> @@ -1965,13 +1930,13 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  	 * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
>  	 * 16) we need to scale down the depth of the sizes we request.
>  	 */
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
> +	mutex_lock(&client->modeset_mutex);
> +	drm_client_for_each_modeset(mode_set, client) {
>  		struct drm_crtc *crtc = mode_set->crtc;
>  		struct drm_plane *plane = crtc->primary;
>  		int j;
>  
> -		DRM_DEBUG("test CRTC %d primary plane\n", i);
> +		DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc));
>  
>  		for (j = 0; j < plane->format_count; j++) {
>  			const struct drm_format_info *fmt;
> @@ -2011,9 +1976,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  
>  	/* first up get a count of crtcs now in use and new min/maxes width/heights */
>  	crtc_count = 0;
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> +	drm_client_for_each_modeset(mode_set, client) {
>  		struct drm_display_mode *desired_mode;
> -		struct drm_mode_set *mode_set;
>  		int x, y, j;
>  		/* in case of tile group, are we the last tile vert or horiz?
>  		 * If no tile group you are always the last one both vertically
> @@ -2021,7 +1985,6 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		 */
>  		bool lastv = true, lasth = true;
>  
> -		mode_set = &fb_helper->crtc_info[i].mode_set;
>  		desired_mode = mode_set->mode;
>  
>  		if (!desired_mode)
> @@ -2051,6 +2014,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  		if (lastv)
>  			sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
>  	}
> +	mutex_unlock(&client->modeset_mutex);
>  
>  	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
>  		DRM_INFO("Cannot find any crtc or sizes\n");
> @@ -2282,7 +2246,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
>  	struct drm_display_mode *dmt_mode, *mode;
>  
>  	/* only contemplate cloning in the single crtc case */
> -	if (fb_helper->crtc_count > 1)
> +	if (fb_helper->dev->mode_config.num_crtc > 1)
>  		return false;
>  
>  	count = 0;
> @@ -2471,15 +2435,17 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
>  }
>  
>  static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
> -			  struct drm_fb_helper_crtc **best_crtcs,
> +			  struct drm_crtc **best_crtcs,
>  			  struct drm_display_mode **modes,
>  			  int n, int width, int height)
>  {
> -	int c, o;
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_connector *connector;
>  	int my_score, best_score, score;
> -	struct drm_fb_helper_crtc **crtcs, *crtc;
> +	struct drm_crtc **crtcs, *crtc;
> +	struct drm_mode_set *modeset;
>  	struct drm_fb_helper_connector *fb_helper_conn;
> +	int o;
>  
>  	if (n == fb_helper->connector_count)
>  		return 0;
> @@ -2492,8 +2458,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  	if (modes[n] == NULL)
>  		return best_score;
>  
> -	crtcs = kcalloc(fb_helper->connector_count,
> -			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
> +	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
>  	if (!crtcs)
>  		return best_score;
>  
> @@ -2509,11 +2474,10 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  	 * select a crtc for this connector and then attempt to configure
>  	 * remaining connectors
>  	 */
> -	for (c = 0; c < fb_helper->crtc_count; c++) {
> -		crtc = &fb_helper->crtc_info[c];
> +	drm_client_for_each_modeset(modeset, client) {
> +		crtc = modeset->crtc;
>  
> -		if (!connector_has_possible_crtc(connector,
> -						 crtc->mode_set.crtc))
> +		if (!connector_has_possible_crtc(connector, crtc))
>  			continue;
>  
>  		for (o = 0; o < n; o++)
> @@ -2522,7 +2486,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  
>  		if (o < n) {
>  			/* ignore cloning unless only a single crtc */
> -			if (fb_helper->crtc_count > 1)
> +			if (fb_helper->dev->mode_config.num_crtc > 1)
>  				continue;
>  
>  			if (!drm_mode_equal(modes[o], modes[n]))
> @@ -2530,14 +2494,13 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  		}
>  
>  		crtcs[n] = crtc;
> -		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
> +		memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
>  		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
>  						  width, height);
>  		if (score > best_score) {
>  			best_score = score;
>  			memcpy(best_crtcs, crtcs,
> -			       fb_helper->connector_count *
> -			       sizeof(struct drm_fb_helper_crtc *));
> +			       fb_helper->connector_count * sizeof(*crtcs));
>  		}
>  	}
>  
> @@ -2545,21 +2508,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
>  	return best_score;
>  }
>  
> -static struct drm_fb_helper_crtc *
> -drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
> -{
> -	int i;
> -
> -	for (i = 0; i < fb_helper->crtc_count; i++)
> -		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
> -			return &fb_helper->crtc_info[i];
> -
> -	return NULL;
> -}
> -
>  /* Try to read the BIOS display configuration and use it for the initial config */
>  static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
> -					  struct drm_fb_helper_crtc **crtcs,
> +					  struct drm_crtc **crtcs,
>  					  struct drm_display_mode **modes,
>  					  struct drm_fb_offset *offsets,
>  					  bool *enabled, int width, int height)
> @@ -2591,7 +2542,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
>  		struct drm_fb_helper_connector *fb_conn;
>  		struct drm_connector *connector;
>  		struct drm_encoder *encoder;
> -		struct drm_fb_helper_crtc *new_crtc;
> +		struct drm_crtc *new_crtc;
>  
>  		fb_conn = fb_helper->connector_info[i];
>  		connector = fb_conn->connector;
> @@ -2634,7 +2585,7 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
>  
>  		num_connectors_enabled++;
>  
> -		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
> +		new_crtc = connector->state->crtc;
>  
>  		/*
>  		 * Make sure we're not trying to drive multiple connectors
> @@ -2736,10 +2687,11 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
>  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			    u32 width, u32 height)
>  {
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct drm_device *dev = fb_helper->dev;
> -	struct drm_fb_helper_crtc **crtcs;
>  	struct drm_display_mode **modes;
>  	struct drm_fb_offset *offsets;
> +	struct drm_crtc **crtcs;
>  	bool *enabled;
>  	int i;
>  
> @@ -2747,8 +2699,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  	/* prevent concurrent modification of connector_count by hotplug */
>  	lockdep_assert_held(&fb_helper->lock);
>  
> -	crtcs = kcalloc(fb_helper->connector_count,
> -			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
> +	crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
>  	modes = kcalloc(fb_helper->connector_count,
>  			sizeof(struct drm_display_mode *), GFP_KERNEL);
>  	offsets = kcalloc(fb_helper->connector_count,
> @@ -2760,6 +2711,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  		goto out;
>  	}
>  
> +	mutex_lock(&client->modeset_mutex);
> +
>  	mutex_lock(&fb_helper->dev->mode_config.mutex);
>  	if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
>  		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
> @@ -2784,24 +2737,24 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  	}
>  	mutex_unlock(&fb_helper->dev->mode_config.mutex);
>  
> -	/* need to set the modesets up here for use later */
> -	/* fill out the connector<->crtc mappings into the modesets */
> -	for (i = 0; i < fb_helper->crtc_count; i++)
> -		drm_fb_helper_modeset_release(fb_helper,
> -					      &fb_helper->crtc_info[i].mode_set);
> +	drm_client_modeset_release(client);
>  
>  	drm_fb_helper_for_each_connector(fb_helper, i) {
>  		struct drm_display_mode *mode = modes[i];
> -		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
> +		struct drm_crtc *crtc = crtcs[i];
>  		struct drm_fb_offset *offset = &offsets[i];
>  
> -		if (mode && fb_crtc) {
> -			struct drm_mode_set *modeset = &fb_crtc->mode_set;
> +		if (mode && crtc) {
> +			struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
>  			struct drm_connector *connector =
>  				fb_helper->connector_info[i]->connector;
>  
>  			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
> -				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
> +				      mode->name, crtc->base.id, offset->x, offset->y);
> +
> +			if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS ||
> +					 (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1)))
> +				break;
>  
>  			modeset->mode = drm_mode_duplicate(dev, mode);
>  			drm_connector_get(connector);
> @@ -2810,6 +2763,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			modeset->y = offset->y;
>  		}
>  	}
> +
> +	mutex_unlock(&client->modeset_mutex);
>  out:
>  	kfree(crtcs);
>  	kfree(modes);
> @@ -2826,13 +2781,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>   */
>  static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
>  {
> +	struct drm_client_dev *client = &fb_helper->client;
>  	struct fb_info *info = fb_helper->fbdev;
>  	unsigned int rotation, sw_rotations = 0;
> +	struct drm_mode_set *modeset;
>  	int i;
>  
> -	for (i = 0; i < fb_helper->crtc_count; i++) {
> -		struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set;
> -
> +	mutex_lock(&client->modeset_mutex);
> +	drm_client_for_each_modeset(modeset, client) {
>  		if (!modeset->num_connectors)
>  			continue;
>  
> @@ -2844,6 +2800,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
>  		else
>  			sw_rotations |= rotation;
>  	}
> +	mutex_unlock(&client->modeset_mutex);
>  
>  	mutex_lock(&fb_helper->dev->mode_config.mutex);
>  	drm_fb_helper_for_each_connector(fb_helper, i) {
> @@ -3060,8 +3017,7 @@ EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
>   * @funcs: fbdev helper functions
>   * @preferred_bpp: Preferred bits per pixel for the device.
>   *                 @dev->mode_config.preferred_depth is used if this is zero.
> - * @max_conn_count: Maximum number of connectors.
> - *                  @dev->mode_config.num_connector is used if this is zero.
> + * @max_conn_count: Maximum number of connectors (not used)
>   *
>   * This function sets up fbdev emulation and registers fbdev for access by
>   * userspace. If all connectors are disconnected, setup is deferred to the next
> @@ -3089,16 +3045,9 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
>  	if (!preferred_bpp)
>  		preferred_bpp = 32;
>  
> -	if (!max_conn_count)
> -		max_conn_count = dev->mode_config.num_connector;
> -	if (!max_conn_count) {
> -		DRM_DEV_ERROR(dev->dev, "fbdev: No connectors\n");
> -		return -EINVAL;
> -	}
> -
>  	drm_fb_helper_prepare(dev, fb_helper, funcs);
>  
> -	ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
> +	ret = drm_fb_helper_init(dev, fb_helper, 0);
>  	if (ret < 0) {
>  		DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret);
>  		return ret;
> @@ -3411,7 +3360,7 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
>  
>  	drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
>  
> -	ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector);
> +	ret = drm_fb_helper_init(dev, fb_helper, 0);
>  	if (ret)
>  		goto err;
>  
> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
> index 8b552b1a6ce9..858c8be70870 100644
> --- a/include/drm/drm_client.h
> +++ b/include/drm/drm_client.h
> @@ -3,8 +3,11 @@
>  #ifndef _DRM_CLIENT_H_
>  #define _DRM_CLIENT_H_
>  
> +#include <linux/mutex.h>
>  #include <linux/types.h>
>  
> +#include <drm/drm_crtc.h>
> +
>  struct drm_client_dev;
>  struct drm_device;
>  struct drm_file;
> @@ -13,6 +16,8 @@ struct drm_gem_object;
>  struct drm_minor;
>  struct module;
>  
> +#define DRM_CLIENT_MAX_CLONED_CONNECTORS	8
> +
>  /**
>   * struct drm_client_funcs - DRM client callbacks
>   */
> @@ -85,6 +90,16 @@ struct drm_client_dev {
>  	 * @file: DRM file
>  	 */
>  	struct drm_file *file;
> +
> +	/**
> +	 * @modeset_mutex: Protects @modesets.
> +	 */
> +	struct mutex modeset_mutex;

Bit on the fence about doing locking automatically, but definitely makes
it easier to use drm_client_modeset functions.

> +
> +	/**
> +	 * @modesets: CRTC configurations
> +	 */
> +	struct drm_mode_set *modesets;
>  };
>  
>  int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
> @@ -135,6 +150,19 @@ struct drm_client_buffer *
>  drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
>  void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
>  
> +int drm_client_modeset_create(struct drm_client_dev *client);
> +void drm_client_modeset_free(struct drm_client_dev *client);
> +void drm_client_modeset_release(struct drm_client_dev *client);
> +struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
> +
> +/**
> + * drm_client_for_each_modeset() - Iterate over client modesets
> + * @modeset: &drm_mode_set loop cursor
> + * @client: DRM client
> + */
> +#define drm_client_for_each_modeset(modeset, client) \
> +	for (modeset = (client)->modesets; modeset && modeset->crtc; modeset++)

Would be good to add a assert_lock_held here, i.e.
	for (assert_lock_held(client->modeset_mutex), modeset = (client)->modesets;
		modeset && modeset->crtc; modeset++)

Cheers, Daniel
> +
>  int drm_client_debugfs_init(struct drm_minor *minor);
>  
>  #endif
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 0d6d23a15b42..8d0ddea74a9e 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -46,10 +46,6 @@ struct drm_fb_offset {
>  	int x, y;
>  };
>  
> -struct drm_fb_helper_crtc {
> -	struct drm_mode_set mode_set;
> -};
> -
>  /**
>   * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
>   * @fb_width: fbdev width
> @@ -108,8 +104,6 @@ struct drm_fb_helper_connector {
>   * struct drm_fb_helper - main structure to emulate fbdev on top of KMS
>   * @fb: Scanout framebuffer object
>   * @dev: DRM device
> - * @crtc_count: number of possible CRTCs
> - * @crtc_info: per-CRTC helper state (mode, x/y offset, etc)
>   * @connector_count: number of connected connectors
>   * @connector_info_alloc_count: size of connector_info
>   * @funcs: driver callbacks for fb helper
> @@ -143,8 +137,6 @@ struct drm_fb_helper {
>  
>  	struct drm_framebuffer *fb;
>  	struct drm_device *dev;
> -	int crtc_count;
> -	struct drm_fb_helper_crtc *crtc_info;
>  	int connector_count;
>  	int connector_info_alloc_count;
>  	/**
> -- 
> 2.20.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/12] drm/fb-helper: Move out commit code
  2019-04-07 16:52 ` [PATCH v2 08/12] drm/fb-helper: Move " Noralf Trønnes
@ 2019-04-16  8:38   ` Daniel Vetter
  2019-04-17 17:56     ` Noralf Trønnes
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2019-04-16  8:38 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

On Sun, Apr 07, 2019 at 06:52:39PM +0200, Noralf Trønnes wrote:
> Move the modeset commit code to drm_client_modeset.
> No changes except exporting API.
> 
> v2: Move to drm_client_modeset.c instead of drm_client.c
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_client_modeset.c | 287 +++++++++++++++++++++++++++

Please add a new chapter in Documentation/gpu to pull in all the nice new
kerneldoc you've typed.

>  drivers/gpu/drm/drm_fb_helper.c      | 282 --------------------------
>  include/drm/drm_client.h             |   4 +
>  3 files changed, 291 insertions(+), 282 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
> index bb34222c9db8..94b52f97c06b 100644
> --- a/drivers/gpu/drm/drm_client_modeset.c
> +++ b/drivers/gpu/drm/drm_client_modeset.c
> @@ -11,9 +11,14 @@
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
>  
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_client.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_device.h>
> +#include <drm/drm_drv.h>
> +
> +#include "drm_crtc_internal.h"
> +#include "drm_internal.h"
>  
>  /* Used by drm_client and drm_fb_helper */
>  int drm_client_modeset_create(struct drm_client_dev *client)
> @@ -100,3 +105,285 @@ struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, stru
>  }
>  /* TODO: Remove export when modeset code has been moved over */
>  EXPORT_SYMBOL(drm_client_find_modeset);
> +
> +/**
> + * drm_client_panel_rotation() - Check panel orientation
> + * @modeset: DRM modeset
> + * @rotation: Returned rotation value
> + *
> + * This function checks if the primary plane in @modeset can hw rotate to match
> + * the panel orientation on its connector.
> + *
> + * Note: Currently only 0 and 180 degrees are supported.
> + *
> + * Return:
> + * True if the plane can do the rotation, false otherwise.
> + */
> +bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
> +{
> +	struct drm_connector *connector = modeset->connectors[0];
> +	struct drm_plane *plane = modeset->crtc->primary;
> +	u64 valid_mask = 0;
> +	unsigned int i;
> +
> +	if (!modeset->num_connectors)
> +		return false;
> +
> +	switch (connector->display_info.panel_orientation) {
> +	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
> +		*rotation = DRM_MODE_ROTATE_180;
> +		break;
> +	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
> +		*rotation = DRM_MODE_ROTATE_90;
> +		break;
> +	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
> +		*rotation = DRM_MODE_ROTATE_270;
> +		break;
> +	default:
> +		*rotation = DRM_MODE_ROTATE_0;
> +	}
> +
> +	/*
> +	 * TODO: support 90 / 270 degree hardware rotation,
> +	 * depending on the hardware this may require the framebuffer
> +	 * to be in a specific tiling format.
> +	 */
> +	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
> +		return false;
> +
> +	for (i = 0; i < plane->rotation_property->num_values; i++)
> +		valid_mask |= (1ULL << plane->rotation_property->values[i]);
> +
> +	if (!(*rotation & valid_mask))
> +		return false;
> +
> +	return true;
> +}
> +
> +static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
> +{
> +	struct drm_device *dev = client->dev;
> +	struct drm_plane_state *plane_state;
> +	struct drm_plane *plane;
> +	struct drm_atomic_state *state;
> +	struct drm_modeset_acquire_ctx ctx;
> +	struct drm_mode_set *mode_set;
> +	int ret;
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +
> +	state = drm_atomic_state_alloc(dev);
> +	if (!state) {
> +		ret = -ENOMEM;
> +		goto out_ctx;
> +	}
> +
> +	state->acquire_ctx = &ctx;
> +retry:
> +	drm_for_each_plane(plane, dev) {
> +		plane_state = drm_atomic_get_plane_state(state, plane);
> +		if (IS_ERR(plane_state)) {
> +			ret = PTR_ERR(plane_state);
> +			goto out_state;
> +		}
> +
> +		plane_state->rotation = DRM_MODE_ROTATE_0;
> +
> +		/* disable non-primary: */
> +		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
> +			continue;
> +
> +		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
> +		if (ret != 0)
> +			goto out_state;
> +	}
> +
> +	drm_client_for_each_modeset(mode_set, client) {
> +		struct drm_plane *primary = mode_set->crtc->primary;
> +		unsigned int rotation;
> +
> +		if (drm_client_panel_rotation(mode_set, &rotation)) {
> +			/* Cannot fail as we've already gotten the plane state above */
> +			plane_state = drm_atomic_get_new_plane_state(state, primary);
> +			plane_state->rotation = rotation;
> +		}
> +
> +		ret = __drm_atomic_helper_set_config(mode_set, state);
> +		if (ret != 0)
> +			goto out_state;
> +
> +		/*
> +		 * __drm_atomic_helper_set_config() sets active when a
> +		 * mode is set, unconditionally clear it if we force DPMS off
> +		 */
> +		if (!active) {
> +			struct drm_crtc *crtc = mode_set->crtc;
> +			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> +
> +			crtc_state->active = false;
> +		}
> +	}
> +
> +	ret = drm_atomic_commit(state);
> +
> +out_state:
> +	if (ret == -EDEADLK)
> +		goto backoff;
> +
> +	drm_atomic_state_put(state);
> +out_ctx:
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +
> +	return ret;
> +
> +backoff:
> +	drm_atomic_state_clear(state);
> +	drm_modeset_backoff(&ctx);
> +
> +	goto retry;
> +}
> +
> +static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
> +{
> +	struct drm_device *dev = client->dev;
> +	struct drm_mode_set *mode_set;
> +	struct drm_plane *plane;
> +	int ret = 0;
> +
> +	drm_modeset_lock_all(dev);
> +	drm_for_each_plane(plane, dev) {
> +		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> +			drm_plane_force_disable(plane);
> +
> +		if (plane->rotation_property)
> +			drm_mode_plane_set_obj_prop(plane,
> +						    plane->rotation_property,
> +						    DRM_MODE_ROTATE_0);
> +	}
> +
> +	drm_client_for_each_modeset(mode_set, client) {
> +		struct drm_crtc *crtc = mode_set->crtc;
> +
> +		if (crtc->funcs->cursor_set2) {
> +			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
> +			if (ret)
> +				goto out;
> +		} else if (crtc->funcs->cursor_set) {
> +			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
> +			if (ret)
> +				goto out;
> +		}
> +
> +		ret = drm_mode_set_config_internal(mode_set);
> +		if (ret)
> +			goto out;
> +	}
> +out:
> +	drm_modeset_unlock_all(dev);
> +
> +	return ret;
> +}
> +
> +/**
> + * drm_client_modeset_commit_force() - Force commit CRTC configuration
> + * @client: DRM client
> + *
> + * Commit modeset configuration to crtcs without checking if there is a DRM master.
> + *
> + * Returns:
> + * Zero on success or negative error code on failure.
> + */
> +int drm_client_modeset_commit_force(struct drm_client_dev *client)
> +{
> +	struct drm_device *dev = client->dev;
> +	int ret;
> +
> +	mutex_lock(&client->modeset_mutex);
> +	if (drm_drv_uses_atomic_modeset(dev))
> +		ret = drm_client_modeset_commit_atomic(client, true);
> +	else
> +		ret = drm_client_modeset_commit_legacy(client);
> +	mutex_unlock(&client->modeset_mutex);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_client_modeset_commit_force);
> +
> +/**
> + * drm_client_modeset_commit() - Commit CRTC configuration
> + * @client: DRM client
> + *
> + * Commit modeset configuration to crtcs.
> + *
> + * Returns:
> + * Zero on success or negative error code on failure.
> + */
> +int drm_client_modeset_commit(struct drm_client_dev *client)
> +{
> +	struct drm_device *dev = client->dev;
> +	int ret;
> +
> +	if (!drm_master_internal_acquire(dev))
> +		return -EBUSY;
> +
> +	ret = drm_client_modeset_commit_force(client);
> +
> +	drm_master_internal_release(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_client_modeset_commit);
> +
> +static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
> +{
> +	struct drm_device *dev = client->dev;
> +	struct drm_connector *connector;
> +	struct drm_mode_set *modeset;
> +	int j;
> +
> +	drm_modeset_lock_all(dev);
> +	drm_client_for_each_modeset(modeset, client) {
> +		if (!modeset->crtc->enabled)
> +			continue;
> +
> +		for (j = 0; j < modeset->num_connectors; j++) {
> +			connector = modeset->connectors[j];
> +			connector->funcs->dpms(connector, dpms_mode);
> +			drm_object_property_set_value(&connector->base,
> +				dev->mode_config.dpms_property, dpms_mode);
> +		}
> +	}
> +	drm_modeset_unlock_all(dev);
> +}
> +
> +/**
> + * drm_client_modeset_dpms() - Set DPMS mode
> + * @client: DRM client
> + * @mode: DPMS mode
> + *
> + * Note: For atomic drivers @mode is reduced to on/off.
> + *
> + * Returns:
> + * Zero on success or negative error code on failure.
> + */
> +int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
> +{
> +	struct drm_device *dev = client->dev;
> +	int ret = 0;
> +
> +	if (!drm_master_internal_acquire(dev))
> +		return -EBUSY;
> +
> +	mutex_lock(&client->modeset_mutex);
> +	if (drm_drv_uses_atomic_modeset(dev))
> +		ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON);
> +	else
> +		drm_client_modeset_dpms_legacy(client, mode);
> +	mutex_unlock(&client->modeset_mutex);
> +
> +	drm_master_internal_release(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_client_modeset_dpms);
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 0229e187e6de..73fbcd748ddd 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -40,10 +40,7 @@
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_crtc_helper.h>
>  #include <drm/drm_atomic.h>
> -#include <drm/drm_atomic_helper.h>
>  
> -#include "drm_crtc_internal.h"
> -#include "drm_crtc_helper_internal.h"
>  #include "drm_internal.h"
>  
>  static bool drm_fbdev_emulation = true;
> @@ -388,233 +385,6 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
>  }
>  EXPORT_SYMBOL(drm_fb_helper_debug_leave);
>  
> -/**
> - * drm_client_panel_rotation() - Check panel orientation
> - * @modeset: DRM modeset
> - * @rotation: Returned rotation value
> - *
> - * This function checks if the primary plane in @modeset can hw rotate to match
> - * the panel orientation on its connector.
> - *
> - * Note: Currently only 0 and 180 degrees are supported.
> - *
> - * Return:
> - * True if the plane can do the rotation, false otherwise.
> - */
> -bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)

Why not static? Doesn't seem to be used by anything outside of
drm_client_modeset.c.

> -{
> -	struct drm_connector *connector = modeset->connectors[0];
> -	struct drm_plane *plane = modeset->crtc->primary;
> -	u64 valid_mask = 0;
> -	unsigned int i;
> -
> -	if (!modeset->num_connectors)
> -		return false;
> -
> -	switch (connector->display_info.panel_orientation) {
> -	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
> -		*rotation = DRM_MODE_ROTATE_180;
> -		break;
> -	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
> -		*rotation = DRM_MODE_ROTATE_90;
> -		break;
> -	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
> -		*rotation = DRM_MODE_ROTATE_270;
> -		break;
> -	default:
> -		*rotation = DRM_MODE_ROTATE_0;
> -	}
> -
> -	/*
> -	 * TODO: support 90 / 270 degree hardware rotation,
> -	 * depending on the hardware this may require the framebuffer
> -	 * to be in a specific tiling format.
> -	 */
> -	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
> -		return false;
> -
> -	for (i = 0; i < plane->rotation_property->num_values; i++)
> -		valid_mask |= (1ULL << plane->rotation_property->values[i]);
> -
> -	if (!(*rotation & valid_mask))
> -		return false;
> -
> -	return true;
> -}
> -
> -static int drm_client_modeset_commit_atomic(struct drm_client_dev *client, bool active)
> -{
> -	struct drm_device *dev = client->dev;
> -	struct drm_plane_state *plane_state;
> -	struct drm_plane *plane;
> -	struct drm_atomic_state *state;
> -	struct drm_modeset_acquire_ctx ctx;
> -	struct drm_mode_set *mode_set;
> -	int ret;
> -
> -	drm_modeset_acquire_init(&ctx, 0);
> -
> -	state = drm_atomic_state_alloc(dev);
> -	if (!state) {
> -		ret = -ENOMEM;
> -		goto out_ctx;
> -	}
> -
> -	state->acquire_ctx = &ctx;
> -retry:
> -	drm_for_each_plane(plane, dev) {
> -		plane_state = drm_atomic_get_plane_state(state, plane);
> -		if (IS_ERR(plane_state)) {
> -			ret = PTR_ERR(plane_state);
> -			goto out_state;
> -		}
> -
> -		plane_state->rotation = DRM_MODE_ROTATE_0;
> -
> -		/* disable non-primary: */
> -		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
> -			continue;
> -
> -		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
> -		if (ret != 0)
> -			goto out_state;
> -	}
> -
> -	drm_client_for_each_modeset(mode_set, client) {
> -		struct drm_plane *primary = mode_set->crtc->primary;
> -		unsigned int rotation;
> -
> -		if (drm_client_panel_rotation(mode_set, &rotation)) {
> -			/* Cannot fail as we've already gotten the plane state above */
> -			plane_state = drm_atomic_get_new_plane_state(state, primary);
> -			plane_state->rotation = rotation;
> -		}
> -
> -		ret = __drm_atomic_helper_set_config(mode_set, state);
> -		if (ret != 0)
> -			goto out_state;
> -
> -		/*
> -		 * __drm_atomic_helper_set_config() sets active when a
> -		 * mode is set, unconditionally clear it if we force DPMS off
> -		 */
> -		if (!active) {
> -			struct drm_crtc *crtc = mode_set->crtc;
> -			struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> -
> -			crtc_state->active = false;
> -		}
> -	}
> -
> -	ret = drm_atomic_commit(state);
> -
> -out_state:
> -	if (ret == -EDEADLK)
> -		goto backoff;
> -
> -	drm_atomic_state_put(state);
> -out_ctx:
> -	drm_modeset_drop_locks(&ctx);
> -	drm_modeset_acquire_fini(&ctx);
> -
> -	return ret;
> -
> -backoff:
> -	drm_atomic_state_clear(state);
> -	drm_modeset_backoff(&ctx);
> -
> -	goto retry;
> -}
> -
> -static int drm_client_modeset_commit_legacy(struct drm_client_dev *client)
> -{
> -	struct drm_device *dev = client->dev;
> -	struct drm_mode_set *mode_set;
> -	struct drm_plane *plane;
> -	int ret = 0;
> -
> -	drm_modeset_lock_all(dev);
> -	drm_for_each_plane(plane, dev) {
> -		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> -			drm_plane_force_disable(plane);
> -
> -		if (plane->rotation_property)
> -			drm_mode_plane_set_obj_prop(plane,
> -						    plane->rotation_property,
> -						    DRM_MODE_ROTATE_0);
> -	}
> -
> -	drm_client_for_each_modeset(mode_set, client) {
> -		struct drm_crtc *crtc = mode_set->crtc;
> -
> -		if (crtc->funcs->cursor_set2) {
> -			ret = crtc->funcs->cursor_set2(crtc, NULL, 0, 0, 0, 0, 0);
> -			if (ret)
> -				goto out;
> -		} else if (crtc->funcs->cursor_set) {
> -			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
> -			if (ret)
> -				goto out;
> -		}
> -
> -		ret = drm_mode_set_config_internal(mode_set);
> -		if (ret)
> -			goto out;
> -	}
> -out:
> -	drm_modeset_unlock_all(dev);
> -
> -	return ret;
> -}
> -
> -/**
> - * drm_client_modeset_commit_force() - Force commit CRTC configuration
> - * @client: DRM client
> - *
> - * Commit modeset configuration to crtcs without checking if there is a DRM master.
> - *
> - * Returns:
> - * Zero on success or negative error code on failure.
> - */
> -int drm_client_modeset_commit_force(struct drm_client_dev *client)
> -{
> -	struct drm_device *dev = client->dev;
> -	int ret;
> -
> -	mutex_lock(&client->modeset_mutex);
> -	if (drm_drv_uses_atomic_modeset(dev))
> -		ret = drm_client_modeset_commit_atomic(client, true);
> -	else
> -		ret = drm_client_modeset_commit_legacy(client);
> -	mutex_unlock(&client->modeset_mutex);
> -
> -	return ret;
> -}
> -
> -/**
> - * drm_client_modeset_commit() - Commit CRTC configuration
> - * @client: DRM client
> - *
> - * Commit modeset configuration to crtcs.
> - *
> - * Returns:
> - * Zero on success or negative error code on failure.
> - */
> -int drm_client_modeset_commit(struct drm_client_dev *client)
> -{
> -	struct drm_device *dev = client->dev;
> -	int ret;
> -
> -	if (!drm_master_internal_acquire(dev))
> -		return -EBUSY;
> -
> -	ret = drm_client_modeset_commit_force(client);
> -
> -	drm_master_internal_release(dev);
> -
> -	return ret;
> -}
> -
>  /**
>   * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
>   * @fb_helper: driver-allocated fbdev helper, can be NULL
> @@ -704,58 +474,6 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
>  static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
>  #endif
>  
> -static void drm_client_modeset_dpms_legacy(struct drm_client_dev *client, int dpms_mode)
> -{
> -	struct drm_device *dev = client->dev;
> -	struct drm_connector *connector;
> -	struct drm_mode_set *modeset;
> -	int j;
> -
> -	drm_modeset_lock_all(dev);
> -	drm_client_for_each_modeset(modeset, client) {
> -		if (!modeset->crtc->enabled)
> -			continue;
> -
> -		for (j = 0; j < modeset->num_connectors; j++) {
> -			connector = modeset->connectors[j];
> -			connector->funcs->dpms(connector, dpms_mode);
> -			drm_object_property_set_value(&connector->base,
> -				dev->mode_config.dpms_property, dpms_mode);
> -		}
> -	}
> -	drm_modeset_unlock_all(dev);
> -}
> -
> -/**
> - * drm_client_modeset_dpms() - Set DPMS mode
> - * @client: DRM client
> - * @mode: DPMS mode
> - *
> - * Note: For atomic drivers @mode is reduced to on/off.
> - *
> - * Returns:
> - * Zero on success or negative error code on failure.
> - */
> -int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
> -{
> -	struct drm_device *dev = client->dev;
> -	int ret = 0;
> -
> -	if (!drm_master_internal_acquire(dev))
> -		return -EBUSY;
> -
> -	mutex_lock(&client->modeset_mutex);
> -	if (drm_drv_uses_atomic_modeset(dev))
> -		ret = drm_client_modeset_commit_atomic(client, mode == DRM_MODE_DPMS_ON);
> -	else
> -		drm_client_modeset_dpms_legacy(client, mode);
> -	mutex_unlock(&client->modeset_mutex);
> -
> -	drm_master_internal_release(dev);
> -
> -	return ret;
> -}
> -
>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>  {
>  	struct drm_fb_helper *fb_helper = info->par;
> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
> index 858c8be70870..64b725b318f2 100644
> --- a/include/drm/drm_client.h
> +++ b/include/drm/drm_client.h
> @@ -154,6 +154,10 @@ int drm_client_modeset_create(struct drm_client_dev *client);
>  void drm_client_modeset_free(struct drm_client_dev *client);
>  void drm_client_modeset_release(struct drm_client_dev *client);
>  struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
> +bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
> +int drm_client_modeset_commit_force(struct drm_client_dev *client);

I think latest here the _force postfix stopped making sense. It's just a
commit. Also I'm wondering whether we shouldn't pull the
master_acquire_internal into these helpers here, there's not really a
use-case I can think of where we should not check for other masters.

Only two kernel modeset requests want to ignore master status:
- debug enter/leave, which is utterly broken by design (and outright
  disable for any atomic driver)
- panic handling, for which we now have a really nice plan, plus first
  sketches of an implementation.

Cheers, Daniel

> +int drm_client_modeset_commit(struct drm_client_dev *client);
> +int drm_client_modeset_dpms(struct drm_client_dev *client, int mode);
>  
>  /**
>   * drm_client_for_each_modeset() - Iterate over client modesets
> -- 
> 2.20.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client
  2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
                   ` (15 preceding siblings ...)
  2019-04-07 18:29 ` ✓ Fi.CI.IGT: " Patchwork
@ 2019-04-16  8:41 ` Daniel Vetter
  2019-04-16  8:46   ` Daniel Vetter
  2019-04-17 18:06   ` Noralf Trønnes
  16 siblings, 2 replies; 41+ messages in thread
From: Daniel Vetter @ 2019-04-16  8:41 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, Emmanuel Vadot, dri-devel

On Sun, Apr 07, 2019 at 06:52:31PM +0200, Noralf Trønnes wrote:
> This moves the modesetting code from drm_fb_helper to drm_client so it
> can be shared by all internal clients.
> 
> The main change this time is to attach the modeset array to
> drm_client_dev and honour the drm_fb_helper MIT license. I've dropped
> the display abstraction.
> 
> Noralf.
> 
> Cc: Emmanuel Vadot <manu@bidouilliste.com>
> 
> Noralf Trønnes (12):
>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>   drm/fb-helper: Avoid race with DRM userspace
>   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
>   drm/fb-helper: No need to cache rotation and sw_rotations
>   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
>   drm/fb-helper: Remove drm_fb_helper_crtc
>   drm/fb-helper: Prepare to move out commit code
>   drm/fb-helper: Move out commit code
>   drm/fb-helper: Remove drm_fb_helper_connector
>   drm/fb-helper: Prepare to move out modeset config code
>   drm/fb-helper: Move out modeset config code
>   drm/client: Hack: Add bootsplash example

I like.

Reviewed some of the prep patches, plus some more suggestions for
drm_client_modeset api polishing ideas.

Maxime is working on some other fbdev helper features and your two patch
series will conflict badly I think. Probably best if you coordinate and
cross-review for final details and best coordination for merging into
drm-misc-next.

I think for the bootsplash good option would be to add it as a todo item,
with a link to patch of your latest proof of concept.

Cheers, Daniel

> 
>  Documentation/gpu/todo.rst           |   10 +
>  drivers/gpu/drm/Kconfig              |    5 +
>  drivers/gpu/drm/Makefile             |    3 +-
>  drivers/gpu/drm/drm_atomic.c         |  168 ++++
>  drivers/gpu/drm/drm_atomic_helper.c  |  164 ----
>  drivers/gpu/drm/drm_auth.c           |   20 +
>  drivers/gpu/drm/drm_bootsplash.c     |  359 ++++++++
>  drivers/gpu/drm/drm_client.c         |   17 +-
>  drivers/gpu/drm/drm_client_modeset.c | 1086 +++++++++++++++++++++++
>  drivers/gpu/drm/drm_crtc_internal.h  |    5 +
>  drivers/gpu/drm/drm_drv.c            |    4 +
>  drivers/gpu/drm/drm_fb_helper.c      | 1195 +++-----------------------
>  drivers/gpu/drm/drm_internal.h       |    2 +
>  drivers/gpu/drm/i915/intel_fbdev.c   |  218 -----
>  include/drm/drm_atomic_helper.h      |    4 -
>  include/drm/drm_client.h             |   48 ++
>  include/drm/drm_fb_helper.h          |  125 +--
>  17 files changed, 1859 insertions(+), 1574 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
>  create mode 100644 drivers/gpu/drm/drm_client_modeset.c
> 
> -- 
> 2.20.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client
  2019-04-16  8:41 ` [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Daniel Vetter
@ 2019-04-16  8:46   ` Daniel Vetter
  2019-04-17 18:06   ` Noralf Trønnes
  1 sibling, 0 replies; 41+ messages in thread
From: Daniel Vetter @ 2019-04-16  8:46 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, Emmanuel Vadot, dri-devel

On Tue, Apr 16, 2019 at 10:41:06AM +0200, Daniel Vetter wrote:
> On Sun, Apr 07, 2019 at 06:52:31PM +0200, Noralf Trønnes wrote:
> > This moves the modesetting code from drm_fb_helper to drm_client so it
> > can be shared by all internal clients.
> > 
> > The main change this time is to attach the modeset array to
> > drm_client_dev and honour the drm_fb_helper MIT license. I've dropped
> > the display abstraction.
> > 
> > Noralf.
> > 
> > Cc: Emmanuel Vadot <manu@bidouilliste.com>
> > 
> > Noralf Trønnes (12):
> >   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
> >   drm/fb-helper: Avoid race with DRM userspace
> >   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
> >   drm/fb-helper: No need to cache rotation and sw_rotations
> >   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
> >   drm/fb-helper: Remove drm_fb_helper_crtc
> >   drm/fb-helper: Prepare to move out commit code
> >   drm/fb-helper: Move out commit code
> >   drm/fb-helper: Remove drm_fb_helper_connector
> >   drm/fb-helper: Prepare to move out modeset config code
> >   drm/fb-helper: Move out modeset config code
> >   drm/client: Hack: Add bootsplash example
> 
> I like.
> 
> Reviewed some of the prep patches, plus some more suggestions for
> drm_client_modeset api polishing ideas.
> 
> Maxime is working on some other fbdev helper features and your two patch
> series will conflict badly I think. Probably best if you coordinate and
> cross-review for final details and best coordination for merging into
> drm-misc-next.

https://marc.info/?l=linux-arm-kernel&m=155498898611173&w=2

is what I meant.
-Daniel
> 
> I think for the bootsplash good option would be to add it as a todo item,
> with a link to patch of your latest proof of concept.
> 
> Cheers, Daniel
> 
> > 
> >  Documentation/gpu/todo.rst           |   10 +
> >  drivers/gpu/drm/Kconfig              |    5 +
> >  drivers/gpu/drm/Makefile             |    3 +-
> >  drivers/gpu/drm/drm_atomic.c         |  168 ++++
> >  drivers/gpu/drm/drm_atomic_helper.c  |  164 ----
> >  drivers/gpu/drm/drm_auth.c           |   20 +
> >  drivers/gpu/drm/drm_bootsplash.c     |  359 ++++++++
> >  drivers/gpu/drm/drm_client.c         |   17 +-
> >  drivers/gpu/drm/drm_client_modeset.c | 1086 +++++++++++++++++++++++
> >  drivers/gpu/drm/drm_crtc_internal.h  |    5 +
> >  drivers/gpu/drm/drm_drv.c            |    4 +
> >  drivers/gpu/drm/drm_fb_helper.c      | 1195 +++-----------------------
> >  drivers/gpu/drm/drm_internal.h       |    2 +
> >  drivers/gpu/drm/i915/intel_fbdev.c   |  218 -----
> >  include/drm/drm_atomic_helper.h      |    4 -
> >  include/drm/drm_client.h             |   48 ++
> >  include/drm/drm_fb_helper.h          |  125 +--
> >  17 files changed, 1859 insertions(+), 1574 deletions(-)
> >  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
> >  create mode 100644 drivers/gpu/drm/drm_client_modeset.c
> > 
> > -- 
> > 2.20.1
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2019-04-07 16:52 ` [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
@ 2019-04-16  9:12   ` Maxime Ripard
  0 siblings, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:12 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 724 bytes --]

On Sun, Apr 07, 2019 at 06:52:32PM +0200, Noralf Trønnes wrote:
> Prepare for moving drm_fb_helper modesetting code to drm_client.
> drm_client will be linked to drm.ko, so move
> __drm_atomic_helper_disable_plane() and __drm_atomic_helper_set_config()
> out of drm_kms_helper.ko.
>
> While at it, fix two checkpatch complaints:
> - WARNING: Block comments use a trailing */ on a separate line
> - CHECK: Alignment should match open parenthesis
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-07 16:52 ` [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
  2019-04-16  7:59   ` Daniel Vetter
@ 2019-04-16  9:26   ` Maxime Ripard
  1 sibling, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:26 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 1068 bytes --]

On Sun, Apr 07, 2019 at 06:52:33PM +0200, Noralf Trønnes wrote:
> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
> This is done by looking at the fb on the primary plane. By the time
> fb-helper gets around to committing, it's possible that the facts have
> changed.
>
> Avoid this race by holding the drm_device->master_mutex lock while
> committing. When DRM userspace does its first open, it will now wait
> until fb-helper is done. The helper will stay away if there's a master.
>
> Locking rule: Always take the fb-helper lock first.
>
> v2:
> - Remove drm_fb_helper_is_bound() (Daniel Vetter)
> - No need to check fb_helper->dev->master in
>   drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.
>
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

With the changes asked by Daniel,
Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 04/12] drm/fb-helper: No need to cache rotation and sw_rotations
  2019-04-07 16:52 ` [PATCH v2 04/12] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
@ 2019-04-16  9:28   ` Maxime Ripard
  0 siblings, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:28 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 516 bytes --]

On Sun, Apr 07, 2019 at 06:52:35PM +0200, Noralf Trønnes wrote:
> Getting rotation info is cheap so we can do it on demand.
>
> This is done in preparation for the removal of struct drm_fb_helper_crtc.
>
> Cc: Hans de Goede <hdegoede@redhat.com>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 05/12] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode}
  2019-04-07 16:52 ` [PATCH v2 05/12] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
@ 2019-04-16  9:29   ` Maxime Ripard
  0 siblings, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:29 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 465 bytes --]

On Sun, Apr 07, 2019 at 06:52:36PM +0200, Noralf Trønnes wrote:
> The values are already present in the modeset.
>
> This is done in preparation for the removal of struct drm_fb_helper_crtc.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector
  2019-04-07 16:52 ` [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
@ 2019-04-16  9:42   ` Maxime Ripard
  2019-04-16 14:57     ` Noralf Trønnes
  0 siblings, 1 reply; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:42 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 653 bytes --]

Hi,

On Sun, Apr 07, 2019 at 06:52:40PM +0200, Noralf Trønnes wrote:
> All drivers add all their connectors so there's no need to keep around an
> array of available connectors.
>
> Rename functions which signature is changed since they will be moved to
> drm_client in a later patch.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

The patch itself looks fine in itself, but I was planning on using
connector_info to store the connector properties set on the kernel
command line as part of video=

Where should we put them now?

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 11/12] drm/fb-helper: Move out modeset config code
  2019-04-07 16:52 ` [PATCH v2 11/12] drm/fb-helper: Move " Noralf Trønnes
@ 2019-04-16  9:43   ` Maxime Ripard
  0 siblings, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:43 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 350 bytes --]

On Sun, Apr 07, 2019 at 06:52:42PM +0200, Noralf Trønnes wrote:
> No functional changes, just moving code as-is and fixing includes.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 10/12] drm/fb-helper: Prepare to move out modeset config code
  2019-04-07 16:52 ` [PATCH v2 10/12] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
@ 2019-04-16  9:43   ` Maxime Ripard
  0 siblings, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-16  9:43 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 365 bytes --]

On Sun, Apr 07, 2019 at 06:52:41PM +0200, Noralf Trønnes wrote:
> This prepares the modeset code so it can be moved out as-is in the next
> patch.
>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector
  2019-04-16  9:42   ` Maxime Ripard
@ 2019-04-16 14:57     ` Noralf Trønnes
  2019-04-17 16:48       ` Maxime Ripard
  0 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-16 14:57 UTC (permalink / raw)
  To: Maxime Ripard; +Cc: daniel.vetter, intel-gfx, dri-devel



Den 16.04.2019 11.42, skrev Maxime Ripard:
> Hi,
> 
> On Sun, Apr 07, 2019 at 06:52:40PM +0200, Noralf Trønnes wrote:
>> All drivers add all their connectors so there's no need to keep around an
>> array of available connectors.
>>
>> Rename functions which signature is changed since they will be moved to
>> drm_client in a later patch.
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> The patch itself looks fine in itself, but I was planning on using
> connector_info to store the connector properties set on the kernel
> command line as part of video=
> 
> Where should we put them now?
> 

I don't follow you here. Where do you see the conflict?

Noralf.

> Maxime
> 
> --
> Maxime Ripard, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-16  7:59   ` Daniel Vetter
@ 2019-04-16 18:46     ` Noralf Trønnes
  2019-04-17 13:24       ` Daniel Vetter
  0 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-16 18:46 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: daniel.vetter, intel-gfx, dri-devel



Den 16.04.2019 09.59, skrev Daniel Vetter:
> On Sun, Apr 07, 2019 at 06:52:33PM +0200, Noralf Trønnes wrote:
>> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
>> This is done by looking at the fb on the primary plane. By the time
>> fb-helper gets around to committing, it's possible that the facts have
>> changed.
>>
>> Avoid this race by holding the drm_device->master_mutex lock while
>> committing. When DRM userspace does its first open, it will now wait
>> until fb-helper is done. The helper will stay away if there's a master.
>>
>> Locking rule: Always take the fb-helper lock first.
>>
>> v2:
>> - Remove drm_fb_helper_is_bound() (Daniel Vetter)
>> - No need to check fb_helper->dev->master in
>>   drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.
>>
>> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> ---
>>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++
>>  drivers/gpu/drm/drm_fb_helper.c | 90 ++++++++++++++++-----------------
>>  drivers/gpu/drm/drm_internal.h  |  2 +
>>  3 files changed, 67 insertions(+), 45 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
>> index 1669c42c40ed..db199807b7dc 100644
>> --- a/drivers/gpu/drm/drm_auth.c
>> +++ b/drivers/gpu/drm/drm_auth.c
>> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
>>  	*master = NULL;
>>  }
>>  EXPORT_SYMBOL(drm_master_put);
>> +
>> +/* Used by drm_client and drm_fb_helper */
>> +bool drm_master_internal_acquire(struct drm_device *dev)
>> +{
>> +	mutex_lock(&dev->master_mutex);
>> +	if (dev->master) {
>> +		mutex_unlock(&dev->master_mutex);
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> +EXPORT_SYMBOL(drm_master_internal_acquire);
>> +
>> +/* Used by drm_client and drm_fb_helper */
>> +void drm_master_internal_release(struct drm_device *dev)
>> +{
>> +	mutex_unlock(&dev->master_mutex);
>> +}
>> +EXPORT_SYMBOL(drm_master_internal_release);
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 84791dd4a90d..a6be09ae899b 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -44,6 +44,7 @@
>>  
>>  #include "drm_crtc_internal.h"
>>  #include "drm_crtc_helper_internal.h"
>> +#include "drm_internal.h"
>>  
>>  static bool drm_fbdev_emulation = true;
>>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
>> @@ -509,7 +510,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
>>  	return ret;
>>  }
>>  
>> -static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>> +static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
> 
> Bikeshed: usually the function variant that's run with locks already taken
> is called _locked or has a __ prefix. _force feels a bit misplaced.

This isn't a _locked function in the usual sense, it is: apply modeset
even if there is a DRM master. So we are _forcing a modeset on a
possibly unexpecting DRM userspace. To me a _locked function would imply
that the caller _must_ take a lock in order to use it.

But no big deal, I can rename it _locked if that reads better. After a
few years of reading kernel code I've come to appreciate the consistency
in how things are done and named. Every time things are different it
slows down my internal logic/pattern parser.

>>  {
>>  	struct drm_device *dev = fb_helper->dev;
>>  
>> @@ -519,6 +520,21 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>>  		return restore_fbdev_mode_legacy(fb_helper);
>>  }
>>  
>> +static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
>> +{
>> +	struct drm_device *dev = fb_helper->dev;
>> +	int ret;
>> +
>> +	if (!drm_master_internal_acquire(dev))
>> +		return -EBUSY;
>> +
>> +	ret = restore_fbdev_mode_force(fb_helper);
>> +
>> +	drm_master_internal_release(dev);
>> +
>> +	return ret;
>> +}
>> +
>>  /**
>>   * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
>>   * @fb_helper: driver-allocated fbdev helper, can be NULL
>> @@ -556,34 +572,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>>  }
>>  EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
>>  
>> -static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
>> -{
>> -	struct drm_device *dev = fb_helper->dev;
>> -	struct drm_crtc *crtc;
>> -	int bound = 0, crtcs_bound = 0;
>> -
>> -	/*
>> -	 * Sometimes user space wants everything disabled, so don't steal the
>> -	 * display if there's a master.
>> -	 */
>> -	if (READ_ONCE(dev->master))
>> -		return false;
>> -
>> -	drm_for_each_crtc(crtc, dev) {
>> -		drm_modeset_lock(&crtc->mutex, NULL);
>> -		if (crtc->primary->fb)
>> -			crtcs_bound++;
>> -		if (crtc->primary->fb == fb_helper->fb)
>> -			bound++;
>> -		drm_modeset_unlock(&crtc->mutex);
>> -	}
>> -
>> -	if (bound < crtcs_bound)
>> -		return false;
>> -
>> -	return true;
>> -}
>> -
>>  #ifdef CONFIG_MAGIC_SYSRQ
>>  /*
>>   * restore fbcon display for all kms driver's using this helper, used for sysrq
>> @@ -604,7 +592,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
>>  			continue;
>>  
>>  		mutex_lock(&helper->lock);
>> -		ret = restore_fbdev_mode(helper);
>> +		ret = restore_fbdev_mode_force(helper);
> 
> I'd leave this as-is, because:
> a) I'm too lazy to review the locking of our open/close calls to convince
> myself that lastclose can't race with the next open
> b) it won't hurt
> c) leaves the door open to easily make our open/close more concurrent in
> the future
> 

I'm not actually changing anything here, it's restore_fbdev_mode() that
has changed, it now bails out if there's a DRM master. If we don't
change this to _force/_locked, then sysrq won't work if there's a DRM
master. Which kind of defeats the whole idea of this 'give me fbcon
right now' functionality doesn't it?

>>  		if (ret)
>>  			error = true;
>>  		mutex_unlock(&helper->lock);
>> @@ -663,20 +651,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
>>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
>>  {
>>  	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>>  
>>  	/*
>>  	 * For each CRTC in this fb, turn the connectors on/off.
>>  	 */
>>  	mutex_lock(&fb_helper->lock);
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> -		mutex_unlock(&fb_helper->lock);
>> -		return;
>> -	}
>> +	if (!drm_master_internal_acquire(dev))
>> +		goto unlock;
>>  
>> -	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
>> +	if (drm_drv_uses_atomic_modeset(dev))
>>  		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
>>  	else
>>  		dpms_legacy(fb_helper, dpms_mode);
>> +
>> +	drm_master_internal_release(dev);
>> +unlock:
>>  	mutex_unlock(&fb_helper->lock);
>>  }
>>  
>> @@ -1509,6 +1499,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
>>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>  {
>>  	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>>  	int ret;
>>  
>>  	if (oops_in_progress)
>> @@ -1516,9 +1507,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>  
>>  	mutex_lock(&fb_helper->lock);
>>  
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> +	if (!drm_master_internal_acquire(dev)) {
>>  		ret = -EBUSY;
>> -		goto out;
>> +		goto unlock;
>>  	}
>>  
>>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
>> @@ -1528,7 +1519,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
>>  	else
>>  		ret = setcmap_legacy(cmap, info);
>>  
>> -out:
>> +	drm_master_internal_release(dev);
>> +unlock:
>>  	mutex_unlock(&fb_helper->lock);
>>  
>>  	return ret;
>> @@ -1548,12 +1540,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>>  			unsigned long arg)
>>  {
>>  	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>>  	struct drm_mode_set *mode_set;
>>  	struct drm_crtc *crtc;
>>  	int ret = 0;
>>  
>>  	mutex_lock(&fb_helper->lock);
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> +	if (!drm_master_internal_acquire(dev)) {
>>  		ret = -EBUSY;
>>  		goto unlock;
>>  	}
>> @@ -1591,11 +1584,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
>>  		}
>>  
>>  		ret = 0;
>> -		goto unlock;
>> +		break;
>>  	default:
>>  		ret = -ENOTTY;
>>  	}
>>  
>> +	drm_master_internal_release(dev);
>>  unlock:
>>  	mutex_unlock(&fb_helper->lock);
>>  	return ret;
>> @@ -1847,15 +1841,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
>>  		return -EBUSY;
>>  
>>  	mutex_lock(&fb_helper->lock);
>> -	if (!drm_fb_helper_is_bound(fb_helper)) {
>> -		mutex_unlock(&fb_helper->lock);
>> -		return -EBUSY;
>> +	if (!drm_master_internal_acquire(dev)) {
>> +		ret = -EBUSY;
>> +		goto unlock;
>>  	}
>>  
>>  	if (drm_drv_uses_atomic_modeset(dev))
>>  		ret = pan_display_atomic(var, info);
>>  	else
>>  		ret = pan_display_legacy(var, info);
>> +
>> +	drm_master_internal_release(dev);
>> +unlock:
>>  	mutex_unlock(&fb_helper->lock);
>>  
>>  	return ret;
>> @@ -2014,7 +2011,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>  		DRM_INFO("Cannot find any crtc or sizes\n");
>>  
>>  		/* First time: disable all crtc's.. */
>> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
>> +		if (!fb_helper->deferred_setup)
>>  			restore_fbdev_mode(fb_helper);
> 
> I think we need to return the errno here, since without that the higher
> levels won't reprobe correctly. Plus we need to remap -EBUSY to -EAGAIN
> (or change the check in __drm_fb_helper_initial_config_and_unlock to also
> retry on -EBUSY).
> 

I don't think so, because -EAGAIN is returned unconditionally on the
line below. The restore_fbdev_mode() call is just to disable the outputs
_if_ there's no DRM master, which that function now checks for.

Noralf.

>>  		return -EAGAIN;
>>  	}
>> @@ -2842,6 +2839,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
>>   */
>>  int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
>>  {
>> +	struct drm_device *dev = fb_helper->dev;
>>  	int err = 0;
>>  
>>  	if (!drm_fbdev_emulation || !fb_helper)
>> @@ -2854,12 +2852,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
>>  		return err;
>>  	}
>>  
>> -	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
>> +	if (!fb_helper->fb || !drm_master_internal_acquire(dev)) {
>>  		fb_helper->delayed_hotplug = true;
>>  		mutex_unlock(&fb_helper->lock);
>>  		return err;
>>  	}
>>  
>> +	drm_master_internal_release(dev);
>> +
>>  	DRM_DEBUG_KMS("\n");
>>  
>>  	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
>> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
>> index d9a483a5fce0..3ee97c9998a2 100644
>> --- a/drivers/gpu/drm/drm_internal.h
>> +++ b/drivers/gpu/drm/drm_internal.h
>> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
>>  			 struct drm_file *file_priv);
>>  int drm_master_open(struct drm_file *file_priv);
>>  void drm_master_release(struct drm_file *file_priv);
>> +bool drm_master_internal_acquire(struct drm_device *dev);
>> +void drm_master_internal_release(struct drm_device *dev);
>>  
>>  /* drm_sysfs.c */
>>  extern struct class *drm_class;
> 
> With the nits addressed:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
>> -- 
>> 2.20.1
>>
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-16 18:46     ` Noralf Trønnes
@ 2019-04-17 13:24       ` Daniel Vetter
  2019-04-17 13:26         ` Daniel Vetter
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2019-04-17 13:24 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

On Tue, Apr 16, 2019 at 08:46:24PM +0200, Noralf Trønnes wrote:
> 
> 
> Den 16.04.2019 09.59, skrev Daniel Vetter:
> > On Sun, Apr 07, 2019 at 06:52:33PM +0200, Noralf Trønnes wrote:
> >> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
> >> This is done by looking at the fb on the primary plane. By the time
> >> fb-helper gets around to committing, it's possible that the facts have
> >> changed.
> >>
> >> Avoid this race by holding the drm_device->master_mutex lock while
> >> committing. When DRM userspace does its first open, it will now wait
> >> until fb-helper is done. The helper will stay away if there's a master.
> >>
> >> Locking rule: Always take the fb-helper lock first.
> >>
> >> v2:
> >> - Remove drm_fb_helper_is_bound() (Daniel Vetter)
> >> - No need to check fb_helper->dev->master in
> >>   drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.
> >>
> >> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >> ---
> >>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++
> >>  drivers/gpu/drm/drm_fb_helper.c | 90 ++++++++++++++++-----------------
> >>  drivers/gpu/drm/drm_internal.h  |  2 +
> >>  3 files changed, 67 insertions(+), 45 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> >> index 1669c42c40ed..db199807b7dc 100644
> >> --- a/drivers/gpu/drm/drm_auth.c
> >> +++ b/drivers/gpu/drm/drm_auth.c
> >> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
> >>  	*master = NULL;
> >>  }
> >>  EXPORT_SYMBOL(drm_master_put);
> >> +
> >> +/* Used by drm_client and drm_fb_helper */
> >> +bool drm_master_internal_acquire(struct drm_device *dev)
> >> +{
> >> +	mutex_lock(&dev->master_mutex);
> >> +	if (dev->master) {
> >> +		mutex_unlock(&dev->master_mutex);
> >> +		return false;
> >> +	}
> >> +
> >> +	return true;
> >> +}
> >> +EXPORT_SYMBOL(drm_master_internal_acquire);
> >> +
> >> +/* Used by drm_client and drm_fb_helper */
> >> +void drm_master_internal_release(struct drm_device *dev)
> >> +{
> >> +	mutex_unlock(&dev->master_mutex);
> >> +}
> >> +EXPORT_SYMBOL(drm_master_internal_release);
> >> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> >> index 84791dd4a90d..a6be09ae899b 100644
> >> --- a/drivers/gpu/drm/drm_fb_helper.c
> >> +++ b/drivers/gpu/drm/drm_fb_helper.c
> >> @@ -44,6 +44,7 @@
> >>  
> >>  #include "drm_crtc_internal.h"
> >>  #include "drm_crtc_helper_internal.h"
> >> +#include "drm_internal.h"
> >>  
> >>  static bool drm_fbdev_emulation = true;
> >>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
> >> @@ -509,7 +510,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
> >>  	return ret;
> >>  }
> >>  
> >> -static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> >> +static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
> > 
> > Bikeshed: usually the function variant that's run with locks already taken
> > is called _locked or has a __ prefix. _force feels a bit misplaced.
> 
> This isn't a _locked function in the usual sense, it is: apply modeset
> even if there is a DRM master. So we are _forcing a modeset on a
> possibly unexpecting DRM userspace. To me a _locked function would imply
> that the caller _must_ take a lock in order to use it.

Hm, good point. See my comments later on, I'm not sure the "forcing" is
really what we want. I think lastclose would be much better served if it
also checks for master status.

> But no big deal, I can rename it _locked if that reads better. After a
> few years of reading kernel code I've come to appreciate the consistency
> in how things are done and named. Every time things are different it
> slows down my internal logic/pattern parser.

If you agree with the entire "we should _force" then I think the __ prefix
would fit. It's the general "beware, this is special/internal" annotation.
My _locked suggestion was under the assumption that there's never a real
case where we want to do the unprotected modeset for an internal
drm_client.

> >>  {
> >>  	struct drm_device *dev = fb_helper->dev;
> >>  
> >> @@ -519,6 +520,21 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> >>  		return restore_fbdev_mode_legacy(fb_helper);
> >>  }
> >>  
> >> +static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> >> +{
> >> +	struct drm_device *dev = fb_helper->dev;
> >> +	int ret;
> >> +
> >> +	if (!drm_master_internal_acquire(dev))
> >> +		return -EBUSY;
> >> +
> >> +	ret = restore_fbdev_mode_force(fb_helper);
> >> +
> >> +	drm_master_internal_release(dev);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >>  /**
> >>   * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
> >>   * @fb_helper: driver-allocated fbdev helper, can be NULL
> >> @@ -556,34 +572,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
> >>  }
> >>  EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
> >>  
> >> -static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
> >> -{
> >> -	struct drm_device *dev = fb_helper->dev;
> >> -	struct drm_crtc *crtc;
> >> -	int bound = 0, crtcs_bound = 0;
> >> -
> >> -	/*
> >> -	 * Sometimes user space wants everything disabled, so don't steal the
> >> -	 * display if there's a master.
> >> -	 */
> >> -	if (READ_ONCE(dev->master))
> >> -		return false;
> >> -
> >> -	drm_for_each_crtc(crtc, dev) {
> >> -		drm_modeset_lock(&crtc->mutex, NULL);
> >> -		if (crtc->primary->fb)
> >> -			crtcs_bound++;
> >> -		if (crtc->primary->fb == fb_helper->fb)
> >> -			bound++;
> >> -		drm_modeset_unlock(&crtc->mutex);
> >> -	}
> >> -
> >> -	if (bound < crtcs_bound)
> >> -		return false;
> >> -
> >> -	return true;
> >> -}
> >> -
> >>  #ifdef CONFIG_MAGIC_SYSRQ
> >>  /*
> >>   * restore fbcon display for all kms driver's using this helper, used for sysrq
> >> @@ -604,7 +592,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
> >>  			continue;
> >>  
> >>  		mutex_lock(&helper->lock);
> >> -		ret = restore_fbdev_mode(helper);
> >> +		ret = restore_fbdev_mode_force(helper);
> > 
> > I'd leave this as-is, because:
> > a) I'm too lazy to review the locking of our open/close calls to convince
> > myself that lastclose can't race with the next open
> > b) it won't hurt
> > c) leaves the door open to easily make our open/close more concurrent in
> > the future
> > 
> 
> I'm not actually changing anything here, it's restore_fbdev_mode() that
> has changed, it now bails out if there's a DRM master. If we don't
> change this to _force/_locked, then sysrq won't work if there's a DRM
> master. Which kind of defeats the whole idea of this 'give me fbcon
> right now' functionality doesn't it?

Uh, I was blind, I thought this was for lastclose. With this one here I
think _force makes sense. I still think that the main drm_client_modeset
interface should be the normal one which checks for master for you.

> >>  		if (ret)
> >>  			error = true;
> >>  		mutex_unlock(&helper->lock);
> >> @@ -663,20 +651,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
> >>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
> >>  {
> >>  	struct drm_fb_helper *fb_helper = info->par;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  
> >>  	/*
> >>  	 * For each CRTC in this fb, turn the connectors on/off.
> >>  	 */
> >>  	mutex_lock(&fb_helper->lock);
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> -		mutex_unlock(&fb_helper->lock);
> >> -		return;
> >> -	}
> >> +	if (!drm_master_internal_acquire(dev))
> >> +		goto unlock;
> >>  
> >> -	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
> >> +	if (drm_drv_uses_atomic_modeset(dev))
> >>  		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
> >>  	else
> >>  		dpms_legacy(fb_helper, dpms_mode);
> >> +
> >> +	drm_master_internal_release(dev);
> >> +unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >>  }
> >>  
> >> @@ -1509,6 +1499,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
> >>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> >>  {
> >>  	struct drm_fb_helper *fb_helper = info->par;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  	int ret;
> >>  
> >>  	if (oops_in_progress)
> >> @@ -1516,9 +1507,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >>  
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> +	if (!drm_master_internal_acquire(dev)) {
> >>  		ret = -EBUSY;
> >> -		goto out;
> >> +		goto unlock;
> >>  	}
> >>  
> >>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
> >> @@ -1528,7 +1519,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> >>  	else
> >>  		ret = setcmap_legacy(cmap, info);
> >>  
> >> -out:
> >> +	drm_master_internal_release(dev);
> >> +unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >>  
> >>  	return ret;
> >> @@ -1548,12 +1540,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
> >>  			unsigned long arg)
> >>  {
> >>  	struct drm_fb_helper *fb_helper = info->par;
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  	struct drm_mode_set *mode_set;
> >>  	struct drm_crtc *crtc;
> >>  	int ret = 0;
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> +	if (!drm_master_internal_acquire(dev)) {
> >>  		ret = -EBUSY;
> >>  		goto unlock;
> >>  	}
> >> @@ -1591,11 +1584,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
> >>  		}
> >>  
> >>  		ret = 0;
> >> -		goto unlock;
> >> +		break;
> >>  	default:
> >>  		ret = -ENOTTY;
> >>  	}
> >>  
> >> +	drm_master_internal_release(dev);
> >>  unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >>  	return ret;
> >> @@ -1847,15 +1841,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
> >>  		return -EBUSY;
> >>  
> >>  	mutex_lock(&fb_helper->lock);
> >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> >> -		mutex_unlock(&fb_helper->lock);
> >> -		return -EBUSY;
> >> +	if (!drm_master_internal_acquire(dev)) {
> >> +		ret = -EBUSY;
> >> +		goto unlock;
> >>  	}
> >>  
> >>  	if (drm_drv_uses_atomic_modeset(dev))
> >>  		ret = pan_display_atomic(var, info);
> >>  	else
> >>  		ret = pan_display_legacy(var, info);
> >> +
> >> +	drm_master_internal_release(dev);
> >> +unlock:
> >>  	mutex_unlock(&fb_helper->lock);
> >>  
> >>  	return ret;
> >> @@ -2014,7 +2011,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> >>  		DRM_INFO("Cannot find any crtc or sizes\n");
> >>  
> >>  		/* First time: disable all crtc's.. */
> >> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
> >> +		if (!fb_helper->deferred_setup)
> >>  			restore_fbdev_mode(fb_helper);
> > 
> > I think we need to return the errno here, since without that the higher
> > levels won't reprobe correctly. Plus we need to remap -EBUSY to -EAGAIN
> > (or change the check in __drm_fb_helper_initial_config_and_unlock to also
> > retry on -EBUSY).
> > 
> 
> I don't think so, because -EAGAIN is returned unconditionally on the
> line below. The restore_fbdev_mode() call is just to disable the outputs
> _if_ there's no DRM master, which that function now checks for.

Hm right, my logic parser went *boink* I think. Looks good on 2nd reading.
-Daniel
> 
> Noralf.
> 
> >>  		return -EAGAIN;
> >>  	}
> >> @@ -2842,6 +2839,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
> >>   */
> >>  int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
> >>  {
> >> +	struct drm_device *dev = fb_helper->dev;
> >>  	int err = 0;
> >>  
> >>  	if (!drm_fbdev_emulation || !fb_helper)
> >> @@ -2854,12 +2852,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
> >>  		return err;
> >>  	}
> >>  
> >> -	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
> >> +	if (!fb_helper->fb || !drm_master_internal_acquire(dev)) {
> >>  		fb_helper->delayed_hotplug = true;
> >>  		mutex_unlock(&fb_helper->lock);
> >>  		return err;
> >>  	}
> >>  
> >> +	drm_master_internal_release(dev);
> >> +
> >>  	DRM_DEBUG_KMS("\n");
> >>  
> >>  	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
> >> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> >> index d9a483a5fce0..3ee97c9998a2 100644
> >> --- a/drivers/gpu/drm/drm_internal.h
> >> +++ b/drivers/gpu/drm/drm_internal.h
> >> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
> >>  			 struct drm_file *file_priv);
> >>  int drm_master_open(struct drm_file *file_priv);
> >>  void drm_master_release(struct drm_file *file_priv);
> >> +bool drm_master_internal_acquire(struct drm_device *dev);
> >> +void drm_master_internal_release(struct drm_device *dev);
> >>  
> >>  /* drm_sysfs.c */
> >>  extern struct class *drm_class;
> > 
> > With the nits addressed:
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > 
> >> -- 
> >> 2.20.1
> >>
> > 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-17 13:24       ` Daniel Vetter
@ 2019-04-17 13:26         ` Daniel Vetter
  2019-04-17 14:48           ` Noralf Trønnes
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Vetter @ 2019-04-17 13:26 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

On Wed, Apr 17, 2019 at 03:24:00PM +0200, Daniel Vetter wrote:
> On Tue, Apr 16, 2019 at 08:46:24PM +0200, Noralf Trønnes wrote:
> > 
> > 
> > Den 16.04.2019 09.59, skrev Daniel Vetter:
> > > On Sun, Apr 07, 2019 at 06:52:33PM +0200, Noralf Trønnes wrote:
> > >> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
> > >> This is done by looking at the fb on the primary plane. By the time
> > >> fb-helper gets around to committing, it's possible that the facts have
> > >> changed.
> > >>
> > >> Avoid this race by holding the drm_device->master_mutex lock while
> > >> committing. When DRM userspace does its first open, it will now wait
> > >> until fb-helper is done. The helper will stay away if there's a master.
> > >>
> > >> Locking rule: Always take the fb-helper lock first.
> > >>
> > >> v2:
> > >> - Remove drm_fb_helper_is_bound() (Daniel Vetter)
> > >> - No need to check fb_helper->dev->master in
> > >>   drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.
> > >>
> > >> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > >> ---
> > >>  drivers/gpu/drm/drm_auth.c      | 20 ++++++++
> > >>  drivers/gpu/drm/drm_fb_helper.c | 90 ++++++++++++++++-----------------
> > >>  drivers/gpu/drm/drm_internal.h  |  2 +
> > >>  3 files changed, 67 insertions(+), 45 deletions(-)
> > >>
> > >> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> > >> index 1669c42c40ed..db199807b7dc 100644
> > >> --- a/drivers/gpu/drm/drm_auth.c
> > >> +++ b/drivers/gpu/drm/drm_auth.c
> > >> @@ -368,3 +368,23 @@ void drm_master_put(struct drm_master **master)
> > >>  	*master = NULL;
> > >>  }
> > >>  EXPORT_SYMBOL(drm_master_put);
> > >> +
> > >> +/* Used by drm_client and drm_fb_helper */
> > >> +bool drm_master_internal_acquire(struct drm_device *dev)
> > >> +{
> > >> +	mutex_lock(&dev->master_mutex);
> > >> +	if (dev->master) {
> > >> +		mutex_unlock(&dev->master_mutex);
> > >> +		return false;
> > >> +	}
> > >> +
> > >> +	return true;
> > >> +}
> > >> +EXPORT_SYMBOL(drm_master_internal_acquire);
> > >> +
> > >> +/* Used by drm_client and drm_fb_helper */
> > >> +void drm_master_internal_release(struct drm_device *dev)
> > >> +{
> > >> +	mutex_unlock(&dev->master_mutex);
> > >> +}
> > >> +EXPORT_SYMBOL(drm_master_internal_release);
> > >> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > >> index 84791dd4a90d..a6be09ae899b 100644
> > >> --- a/drivers/gpu/drm/drm_fb_helper.c
> > >> +++ b/drivers/gpu/drm/drm_fb_helper.c
> > >> @@ -44,6 +44,7 @@
> > >>  
> > >>  #include "drm_crtc_internal.h"
> > >>  #include "drm_crtc_helper_internal.h"
> > >> +#include "drm_internal.h"
> > >>  
> > >>  static bool drm_fbdev_emulation = true;
> > >>  module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
> > >> @@ -509,7 +510,7 @@ static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper)
> > >>  	return ret;
> > >>  }
> > >>  
> > >> -static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> > >> +static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper)
> > > 
> > > Bikeshed: usually the function variant that's run with locks already taken
> > > is called _locked or has a __ prefix. _force feels a bit misplaced.
> > 
> > This isn't a _locked function in the usual sense, it is: apply modeset
> > even if there is a DRM master. So we are _forcing a modeset on a
> > possibly unexpecting DRM userspace. To me a _locked function would imply
> > that the caller _must_ take a lock in order to use it.
> 
> Hm, good point. See my comments later on, I'm not sure the "forcing" is
> really what we want. I think lastclose would be much better served if it
> also checks for master status.
> 
> > But no big deal, I can rename it _locked if that reads better. After a
> > few years of reading kernel code I've come to appreciate the consistency
> > in how things are done and named. Every time things are different it
> > slows down my internal logic/pattern parser.
> 
> If you agree with the entire "we should _force" then I think the __ prefix
> would fit. It's the general "beware, this is special/internal" annotation.
> My _locked suggestion was under the assumption that there's never a real
> case where we want to do the unprotected modeset for an internal
> drm_client.
> 
> > >>  {
> > >>  	struct drm_device *dev = fb_helper->dev;
> > >>  
> > >> @@ -519,6 +520,21 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> > >>  		return restore_fbdev_mode_legacy(fb_helper);
> > >>  }
> > >>  
> > >> +static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
> > >> +{
> > >> +	struct drm_device *dev = fb_helper->dev;
> > >> +	int ret;
> > >> +
> > >> +	if (!drm_master_internal_acquire(dev))
> > >> +		return -EBUSY;
> > >> +
> > >> +	ret = restore_fbdev_mode_force(fb_helper);
> > >> +
> > >> +	drm_master_internal_release(dev);
> > >> +
> > >> +	return ret;
> > >> +}
> > >> +
> > >>  /**
> > >>   * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
> > >>   * @fb_helper: driver-allocated fbdev helper, can be NULL
> > >> @@ -556,34 +572,6 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
> > >>  }
> > >>  EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
> > >>  
> > >> -static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
> > >> -{
> > >> -	struct drm_device *dev = fb_helper->dev;
> > >> -	struct drm_crtc *crtc;
> > >> -	int bound = 0, crtcs_bound = 0;
> > >> -
> > >> -	/*
> > >> -	 * Sometimes user space wants everything disabled, so don't steal the
> > >> -	 * display if there's a master.
> > >> -	 */
> > >> -	if (READ_ONCE(dev->master))
> > >> -		return false;
> > >> -
> > >> -	drm_for_each_crtc(crtc, dev) {
> > >> -		drm_modeset_lock(&crtc->mutex, NULL);
> > >> -		if (crtc->primary->fb)
> > >> -			crtcs_bound++;
> > >> -		if (crtc->primary->fb == fb_helper->fb)
> > >> -			bound++;
> > >> -		drm_modeset_unlock(&crtc->mutex);
> > >> -	}
> > >> -
> > >> -	if (bound < crtcs_bound)
> > >> -		return false;
> > >> -
> > >> -	return true;
> > >> -}
> > >> -
> > >>  #ifdef CONFIG_MAGIC_SYSRQ
> > >>  /*
> > >>   * restore fbcon display for all kms driver's using this helper, used for sysrq
> > >> @@ -604,7 +592,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
> > >>  			continue;
> > >>  
> > >>  		mutex_lock(&helper->lock);
> > >> -		ret = restore_fbdev_mode(helper);
> > >> +		ret = restore_fbdev_mode_force(helper);
> > > 
> > > I'd leave this as-is, because:
> > > a) I'm too lazy to review the locking of our open/close calls to convince
> > > myself that lastclose can't race with the next open
> > > b) it won't hurt
> > > c) leaves the door open to easily make our open/close more concurrent in
> > > the future
> > > 
> > 
> > I'm not actually changing anything here, it's restore_fbdev_mode() that
> > has changed, it now bails out if there's a DRM master. If we don't
> > change this to _force/_locked, then sysrq won't work if there's a DRM
> > master. Which kind of defeats the whole idea of this 'give me fbcon
> > right now' functionality doesn't it?
> 
> Uh, I was blind, I thought this was for lastclose. With this one here I
> think _force makes sense. I still think that the main drm_client_modeset
> interface should be the normal one which checks for master for you.

Ok, I read the later patches and you already have a commit() and a
commit_force(). Count me convinced on all points.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

as-is on this patch.

Cheers, Daniel

> 
> > >>  		if (ret)
> > >>  			error = true;
> > >>  		mutex_unlock(&helper->lock);
> > >> @@ -663,20 +651,22 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
> > >>  static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
> > >>  {
> > >>  	struct drm_fb_helper *fb_helper = info->par;
> > >> +	struct drm_device *dev = fb_helper->dev;
> > >>  
> > >>  	/*
> > >>  	 * For each CRTC in this fb, turn the connectors on/off.
> > >>  	 */
> > >>  	mutex_lock(&fb_helper->lock);
> > >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> > >> -		mutex_unlock(&fb_helper->lock);
> > >> -		return;
> > >> -	}
> > >> +	if (!drm_master_internal_acquire(dev))
> > >> +		goto unlock;
> > >>  
> > >> -	if (drm_drv_uses_atomic_modeset(fb_helper->dev))
> > >> +	if (drm_drv_uses_atomic_modeset(dev))
> > >>  		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
> > >>  	else
> > >>  		dpms_legacy(fb_helper, dpms_mode);
> > >> +
> > >> +	drm_master_internal_release(dev);
> > >> +unlock:
> > >>  	mutex_unlock(&fb_helper->lock);
> > >>  }
> > >>  
> > >> @@ -1509,6 +1499,7 @@ static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
> > >>  int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> > >>  {
> > >>  	struct drm_fb_helper *fb_helper = info->par;
> > >> +	struct drm_device *dev = fb_helper->dev;
> > >>  	int ret;
> > >>  
> > >>  	if (oops_in_progress)
> > >> @@ -1516,9 +1507,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> > >>  
> > >>  	mutex_lock(&fb_helper->lock);
> > >>  
> > >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> > >> +	if (!drm_master_internal_acquire(dev)) {
> > >>  		ret = -EBUSY;
> > >> -		goto out;
> > >> +		goto unlock;
> > >>  	}
> > >>  
> > >>  	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
> > >> @@ -1528,7 +1519,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
> > >>  	else
> > >>  		ret = setcmap_legacy(cmap, info);
> > >>  
> > >> -out:
> > >> +	drm_master_internal_release(dev);
> > >> +unlock:
> > >>  	mutex_unlock(&fb_helper->lock);
> > >>  
> > >>  	return ret;
> > >> @@ -1548,12 +1540,13 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
> > >>  			unsigned long arg)
> > >>  {
> > >>  	struct drm_fb_helper *fb_helper = info->par;
> > >> +	struct drm_device *dev = fb_helper->dev;
> > >>  	struct drm_mode_set *mode_set;
> > >>  	struct drm_crtc *crtc;
> > >>  	int ret = 0;
> > >>  
> > >>  	mutex_lock(&fb_helper->lock);
> > >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> > >> +	if (!drm_master_internal_acquire(dev)) {
> > >>  		ret = -EBUSY;
> > >>  		goto unlock;
> > >>  	}
> > >> @@ -1591,11 +1584,12 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
> > >>  		}
> > >>  
> > >>  		ret = 0;
> > >> -		goto unlock;
> > >> +		break;
> > >>  	default:
> > >>  		ret = -ENOTTY;
> > >>  	}
> > >>  
> > >> +	drm_master_internal_release(dev);
> > >>  unlock:
> > >>  	mutex_unlock(&fb_helper->lock);
> > >>  	return ret;
> > >> @@ -1847,15 +1841,18 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
> > >>  		return -EBUSY;
> > >>  
> > >>  	mutex_lock(&fb_helper->lock);
> > >> -	if (!drm_fb_helper_is_bound(fb_helper)) {
> > >> -		mutex_unlock(&fb_helper->lock);
> > >> -		return -EBUSY;
> > >> +	if (!drm_master_internal_acquire(dev)) {
> > >> +		ret = -EBUSY;
> > >> +		goto unlock;
> > >>  	}
> > >>  
> > >>  	if (drm_drv_uses_atomic_modeset(dev))
> > >>  		ret = pan_display_atomic(var, info);
> > >>  	else
> > >>  		ret = pan_display_legacy(var, info);
> > >> +
> > >> +	drm_master_internal_release(dev);
> > >> +unlock:
> > >>  	mutex_unlock(&fb_helper->lock);
> > >>  
> > >>  	return ret;
> > >> @@ -2014,7 +2011,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> > >>  		DRM_INFO("Cannot find any crtc or sizes\n");
> > >>  
> > >>  		/* First time: disable all crtc's.. */
> > >> -		if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master))
> > >> +		if (!fb_helper->deferred_setup)
> > >>  			restore_fbdev_mode(fb_helper);
> > > 
> > > I think we need to return the errno here, since without that the higher
> > > levels won't reprobe correctly. Plus we need to remap -EBUSY to -EAGAIN
> > > (or change the check in __drm_fb_helper_initial_config_and_unlock to also
> > > retry on -EBUSY).
> > > 
> > 
> > I don't think so, because -EAGAIN is returned unconditionally on the
> > line below. The restore_fbdev_mode() call is just to disable the outputs
> > _if_ there's no DRM master, which that function now checks for.
> 
> Hm right, my logic parser went *boink* I think. Looks good on 2nd reading.
> -Daniel
> > 
> > Noralf.
> > 
> > >>  		return -EAGAIN;
> > >>  	}
> > >> @@ -2842,6 +2839,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
> > >>   */
> > >>  int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
> > >>  {
> > >> +	struct drm_device *dev = fb_helper->dev;
> > >>  	int err = 0;
> > >>  
> > >>  	if (!drm_fbdev_emulation || !fb_helper)
> > >> @@ -2854,12 +2852,14 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
> > >>  		return err;
> > >>  	}
> > >>  
> > >> -	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
> > >> +	if (!fb_helper->fb || !drm_master_internal_acquire(dev)) {
> > >>  		fb_helper->delayed_hotplug = true;
> > >>  		mutex_unlock(&fb_helper->lock);
> > >>  		return err;
> > >>  	}
> > >>  
> > >> +	drm_master_internal_release(dev);
> > >> +
> > >>  	DRM_DEBUG_KMS("\n");
> > >>  
> > >>  	drm_setup_crtcs(fb_helper, fb_helper->fb->width, fb_helper->fb->height);
> > >> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> > >> index d9a483a5fce0..3ee97c9998a2 100644
> > >> --- a/drivers/gpu/drm/drm_internal.h
> > >> +++ b/drivers/gpu/drm/drm_internal.h
> > >> @@ -91,6 +91,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
> > >>  			 struct drm_file *file_priv);
> > >>  int drm_master_open(struct drm_file *file_priv);
> > >>  void drm_master_release(struct drm_file *file_priv);
> > >> +bool drm_master_internal_acquire(struct drm_device *dev);
> > >> +void drm_master_internal_release(struct drm_device *dev);
> > >>  
> > >>  /* drm_sysfs.c */
> > >>  extern struct class *drm_class;
> > > 
> > > With the nits addressed:
> > > 
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > 
> > >> -- 
> > >> 2.20.1
> > >>
> > > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace
  2019-04-17 13:26         ` Daniel Vetter
@ 2019-04-17 14:48           ` Noralf Trønnes
  0 siblings, 0 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-17 14:48 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: daniel.vetter, intel-gfx, dri-devel



Den 17.04.2019 15.26, skrev Daniel Vetter:
> On Wed, Apr 17, 2019 at 03:24:00PM +0200, Daniel Vetter wrote:
>> On Tue, Apr 16, 2019 at 08:46:24PM +0200, Noralf Trønnes wrote:
>>>
>>>
>>> Den 16.04.2019 09.59, skrev Daniel Vetter:
>>>> On Sun, Apr 07, 2019 at 06:52:33PM +0200, Noralf Trønnes wrote:
>>>>> drm_fb_helper_is_bound() is used to check if DRM userspace is in control.
>>>>> This is done by looking at the fb on the primary plane. By the time
>>>>> fb-helper gets around to committing, it's possible that the facts have
>>>>> changed.
>>>>>
>>>>> Avoid this race by holding the drm_device->master_mutex lock while
>>>>> committing. When DRM userspace does its first open, it will now wait
>>>>> until fb-helper is done. The helper will stay away if there's a master.
>>>>>
>>>>> Locking rule: Always take the fb-helper lock first.
>>>>>
>>>>> v2:
>>>>> - Remove drm_fb_helper_is_bound() (Daniel Vetter)
>>>>> - No need to check fb_helper->dev->master in
>>>>>   drm_fb_helper_single_fb_probe(), restore_fbdev_mode() has the check.
>>>>>
>>>>> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>>>>> ---

<snip>

> Ok, I read the later patches and you already have a commit() and a
> commit_force(). Count me convinced on all points.
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> as-is on this patch.
> 

Thanks. I want to apply this after the for-5.2 cutoff so we can get some
testing on this before it hits the world. I know from the timeline chart
that the cutoff is some time after -rc5, but I don't know _excatly_ when
that is. I looked at dim, but all I could glean from it was that it had
something to do with the state of a -fixes branch.

Noralf.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector
  2019-04-16 14:57     ` Noralf Trønnes
@ 2019-04-17 16:48       ` Maxime Ripard
  0 siblings, 0 replies; 41+ messages in thread
From: Maxime Ripard @ 2019-04-17 16:48 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

Hi,

On Tue, Apr 16, 2019 at 04:57:58PM +0200, Noralf Trønnes wrote:
> Den 16.04.2019 11.42, skrev Maxime Ripard:
> > Hi,
> >
> > On Sun, Apr 07, 2019 at 06:52:40PM +0200, Noralf Trønnes wrote:
> >> All drivers add all their connectors so there's no need to keep around an
> >> array of available connectors.
> >>
> >> Rename functions which signature is changed since they will be moved to
> >> drm_client in a later patch.
> >>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >
> > The patch itself looks fine in itself, but I was planning on using
> > connector_info to store the connector properties set on the kernel
> > command line as part of video=
> >
> > Where should we put them now?
>
> I don't follow you here. Where do you see the conflict?

I wanted to store the data parsed from the command line into
connector_info, but then, the connector itself has access to those
data directly so I guess there's none :)

Maxime

--
Maxime Ripard, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/12] drm/fb-helper: Move out commit code
  2019-04-16  8:38   ` Daniel Vetter
@ 2019-04-17 17:56     ` Noralf Trønnes
  2019-04-18  8:30       ` Daniel Vetter
  0 siblings, 1 reply; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-17 17:56 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: daniel.vetter, intel-gfx, dri-devel



Den 16.04.2019 10.38, skrev Daniel Vetter:
> On Sun, Apr 07, 2019 at 06:52:39PM +0200, Noralf Trønnes wrote:
>> Move the modeset commit code to drm_client_modeset.
>> No changes except exporting API.
>>
>> v2: Move to drm_client_modeset.c instead of drm_client.c
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> ---
>>  drivers/gpu/drm/drm_client_modeset.c | 287 +++++++++++++++++++++++++++

<snip>

>> -/**
>> - * drm_client_panel_rotation() - Check panel orientation
>> - * @modeset: DRM modeset
>> - * @rotation: Returned rotation value
>> - *
>> - * This function checks if the primary plane in @modeset can hw rotate to match
>> - * the panel orientation on its connector.
>> - *
>> - * Note: Currently only 0 and 180 degrees are supported.
>> - *
>> - * Return:
>> - * True if the plane can do the rotation, false otherwise.
>> - */
>> -bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
> 
> Why not static? Doesn't seem to be used by anything outside of
> drm_client_modeset.c.
> 

It is used in drm_fb_helper.c:drm_setup_crtcs_fb() to set up any
rotation and do fbcon sw rotation if necessary. Clients that support
rotation need to call it.

>> -{
>> -	struct drm_connector *connector = modeset->connectors[0];
>> -	struct drm_plane *plane = modeset->crtc->primary;
>> -	u64 valid_mask = 0;
>> -	unsigned int i;
>> -
>> -	if (!modeset->num_connectors)
>> -		return false;
>> -
>> -	switch (connector->display_info.panel_orientation) {
>> -	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
>> -		*rotation = DRM_MODE_ROTATE_180;
>> -		break;
>> -	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
>> -		*rotation = DRM_MODE_ROTATE_90;
>> -		break;
>> -	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
>> -		*rotation = DRM_MODE_ROTATE_270;
>> -		break;
>> -	default:
>> -		*rotation = DRM_MODE_ROTATE_0;
>> -	}
>> -
>> -	/*
>> -	 * TODO: support 90 / 270 degree hardware rotation,
>> -	 * depending on the hardware this may require the framebuffer
>> -	 * to be in a specific tiling format.
>> -	 */
>> -	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
>> -		return false;
>> -
>> -	for (i = 0; i < plane->rotation_property->num_values; i++)
>> -		valid_mask |= (1ULL << plane->rotation_property->values[i]);
>> -
>> -	if (!(*rotation & valid_mask))
>> -		return false;
>> -
>> -	return true;
>> -}
>> -

<snip>

>> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
>> index 858c8be70870..64b725b318f2 100644
>> --- a/include/drm/drm_client.h
>> +++ b/include/drm/drm_client.h
>> @@ -154,6 +154,10 @@ int drm_client_modeset_create(struct drm_client_dev *client);
>>  void drm_client_modeset_free(struct drm_client_dev *client);
>>  void drm_client_modeset_release(struct drm_client_dev *client);
>>  struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
>> +bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
>> +int drm_client_modeset_commit_force(struct drm_client_dev *client);
> 
> I think latest here the _force postfix stopped making sense. It's just a
> commit. Also I'm wondering whether we shouldn't pull the
> master_acquire_internal into these helpers here, there's not really a
> use-case I can think of where we should not check for other masters.
> 

drm_master_internal_acquire() is used in various places in drm_fb_helper
for functions that doesn't make sense to move to drm_client, like:
- drm_fb_helper_setcmap
- drm_fb_helper_ioctl
- drm_fb_helper_pan_display

Noralf.

> Only two kernel modeset requests want to ignore master status:
> - debug enter/leave, which is utterly broken by design (and outright
>   disable for any atomic driver)
> - panic handling, for which we now have a really nice plan, plus first
>   sketches of an implementation.
> 
> Cheers, Daniel
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client
  2019-04-16  8:41 ` [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Daniel Vetter
  2019-04-16  8:46   ` Daniel Vetter
@ 2019-04-17 18:06   ` Noralf Trønnes
  1 sibling, 0 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-17 18:06 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: daniel.vetter, intel-gfx, Emmanuel Vadot, dri-devel



Den 16.04.2019 10.41, skrev Daniel Vetter:
> On Sun, Apr 07, 2019 at 06:52:31PM +0200, Noralf Trønnes wrote:
>> This moves the modesetting code from drm_fb_helper to drm_client so it
>> can be shared by all internal clients.
>>
>> The main change this time is to attach the modeset array to
>> drm_client_dev and honour the drm_fb_helper MIT license. I've dropped
>> the display abstraction.
>>
>> Noralf.
>>
>> Cc: Emmanuel Vadot <manu@bidouilliste.com>
>>
>> Noralf Trønnes (12):
>>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>>   drm/fb-helper: Avoid race with DRM userspace
>>   drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
>>   drm/fb-helper: No need to cache rotation and sw_rotations
>>   drm/fb-helper: Remove drm_fb_helper_crtc->{x,y,desired_mode}
>>   drm/fb-helper: Remove drm_fb_helper_crtc
>>   drm/fb-helper: Prepare to move out commit code
>>   drm/fb-helper: Move out commit code
>>   drm/fb-helper: Remove drm_fb_helper_connector
>>   drm/fb-helper: Prepare to move out modeset config code
>>   drm/fb-helper: Move out modeset config code
>>   drm/client: Hack: Add bootsplash example
> 
> I like.
> 

Glad you like it, this turned out to be way more work than I first
imagined when I started toying with this generic fbdev emulation idea :-)

> Reviewed some of the prep patches, plus some more suggestions for
> drm_client_modeset api polishing ideas.
> 
> Maxime is working on some other fbdev helper features and your two patch
> series will conflict badly I think. Probably best if you coordinate and
> cross-review for final details and best coordination for merging into
> drm-misc-next.
> 

Yep, I'll coordinate with Maxime.

> I think for the bootsplash good option would be to add it as a todo item,
> with a link to patch of your latest proof of concept.
> 

Sure, I'll make a todo patch when stuff is applied and I know which
patchset is the last.

Noralf.

> Cheers, Daniel
> 
>>
>>  Documentation/gpu/todo.rst           |   10 +
>>  drivers/gpu/drm/Kconfig              |    5 +
>>  drivers/gpu/drm/Makefile             |    3 +-
>>  drivers/gpu/drm/drm_atomic.c         |  168 ++++
>>  drivers/gpu/drm/drm_atomic_helper.c  |  164 ----
>>  drivers/gpu/drm/drm_auth.c           |   20 +
>>  drivers/gpu/drm/drm_bootsplash.c     |  359 ++++++++
>>  drivers/gpu/drm/drm_client.c         |   17 +-
>>  drivers/gpu/drm/drm_client_modeset.c | 1086 +++++++++++++++++++++++
>>  drivers/gpu/drm/drm_crtc_internal.h  |    5 +
>>  drivers/gpu/drm/drm_drv.c            |    4 +
>>  drivers/gpu/drm/drm_fb_helper.c      | 1195 +++-----------------------
>>  drivers/gpu/drm/drm_internal.h       |    2 +
>>  drivers/gpu/drm/i915/intel_fbdev.c   |  218 -----
>>  include/drm/drm_atomic_helper.h      |    4 -
>>  include/drm/drm_client.h             |   48 ++
>>  include/drm/drm_fb_helper.h          |  125 +--
>>  17 files changed, 1859 insertions(+), 1574 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_bootsplash.c
>>  create mode 100644 drivers/gpu/drm/drm_client_modeset.c
>>
>> -- 
>> 2.20.1
>>
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 08/12] drm/fb-helper: Move out commit code
  2019-04-17 17:56     ` Noralf Trønnes
@ 2019-04-18  8:30       ` Daniel Vetter
  0 siblings, 0 replies; 41+ messages in thread
From: Daniel Vetter @ 2019-04-18  8:30 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: daniel.vetter, intel-gfx, dri-devel

On Wed, Apr 17, 2019 at 07:56:20PM +0200, Noralf Trønnes wrote:
> 
> 
> Den 16.04.2019 10.38, skrev Daniel Vetter:
> > On Sun, Apr 07, 2019 at 06:52:39PM +0200, Noralf Trønnes wrote:
> >> Move the modeset commit code to drm_client_modeset.
> >> No changes except exporting API.
> >>
> >> v2: Move to drm_client_modeset.c instead of drm_client.c
> >>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >> ---
> >>  drivers/gpu/drm/drm_client_modeset.c | 287 +++++++++++++++++++++++++++
> 
> <snip>
> 
> >> -/**
> >> - * drm_client_panel_rotation() - Check panel orientation
> >> - * @modeset: DRM modeset
> >> - * @rotation: Returned rotation value
> >> - *
> >> - * This function checks if the primary plane in @modeset can hw rotate to match
> >> - * the panel orientation on its connector.
> >> - *
> >> - * Note: Currently only 0 and 180 degrees are supported.
> >> - *
> >> - * Return:
> >> - * True if the plane can do the rotation, false otherwise.
> >> - */
> >> -bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation)
> > 
> > Why not static? Doesn't seem to be used by anything outside of
> > drm_client_modeset.c.
> > 
> 
> It is used in drm_fb_helper.c:drm_setup_crtcs_fb() to set up any
> rotation and do fbcon sw rotation if necessary. Clients that support
> rotation need to call it.
> 
> >> -{
> >> -	struct drm_connector *connector = modeset->connectors[0];
> >> -	struct drm_plane *plane = modeset->crtc->primary;
> >> -	u64 valid_mask = 0;
> >> -	unsigned int i;
> >> -
> >> -	if (!modeset->num_connectors)
> >> -		return false;
> >> -
> >> -	switch (connector->display_info.panel_orientation) {
> >> -	case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP:
> >> -		*rotation = DRM_MODE_ROTATE_180;
> >> -		break;
> >> -	case DRM_MODE_PANEL_ORIENTATION_LEFT_UP:
> >> -		*rotation = DRM_MODE_ROTATE_90;
> >> -		break;
> >> -	case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP:
> >> -		*rotation = DRM_MODE_ROTATE_270;
> >> -		break;
> >> -	default:
> >> -		*rotation = DRM_MODE_ROTATE_0;
> >> -	}
> >> -
> >> -	/*
> >> -	 * TODO: support 90 / 270 degree hardware rotation,
> >> -	 * depending on the hardware this may require the framebuffer
> >> -	 * to be in a specific tiling format.
> >> -	 */
> >> -	if (*rotation != DRM_MODE_ROTATE_180 || !plane->rotation_property)
> >> -		return false;
> >> -
> >> -	for (i = 0; i < plane->rotation_property->num_values; i++)
> >> -		valid_mask |= (1ULL << plane->rotation_property->values[i]);
> >> -
> >> -	if (!(*rotation & valid_mask))
> >> -		return false;
> >> -
> >> -	return true;
> >> -}
> >> -
> 
> <snip>
> 
> >> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
> >> index 858c8be70870..64b725b318f2 100644
> >> --- a/include/drm/drm_client.h
> >> +++ b/include/drm/drm_client.h
> >> @@ -154,6 +154,10 @@ int drm_client_modeset_create(struct drm_client_dev *client);
> >>  void drm_client_modeset_free(struct drm_client_dev *client);
> >>  void drm_client_modeset_release(struct drm_client_dev *client);
> >>  struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc);
> >> +bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotation);
> >> +int drm_client_modeset_commit_force(struct drm_client_dev *client);
> > 
> > I think latest here the _force postfix stopped making sense. It's just a
> > commit. Also I'm wondering whether we shouldn't pull the
> > master_acquire_internal into these helpers here, there's not really a
> > use-case I can think of where we should not check for other masters.
> > 
> 
> drm_master_internal_acquire() is used in various places in drm_fb_helper
> for functions that doesn't make sense to move to drm_client, like:
> - drm_fb_helper_setcmap
> - drm_fb_helper_ioctl
> - drm_fb_helper_pan_display

See discussion on the earlier patches, I completely backtracked on this
after better understanding why we need _force.

And exporting/using master_acquire_internal by drm_clients makes total
sense to me.
-Daniel

> 
> Noralf.
> 
> > Only two kernel modeset requests want to ignore master status:
> > - debug enter/leave, which is utterly broken by design (and outright
> >   disable for any atomic driver)
> > - panic handling, for which we now have a really nice plan, plus first
> >   sketches of an implementation.
> > 
> > Cheers, Daniel
> > 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-04-07 16:52 ` [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
  2019-04-11 14:25   ` Noralf Trønnes
@ 2019-04-23 14:17   ` Thomas Zimmermann
  2019-04-23 14:58     ` Noralf Trønnes
  1 sibling, 1 reply; 41+ messages in thread
From: Thomas Zimmermann @ 2019-04-23 14:17 UTC (permalink / raw)
  To: Noralf Trønnes, dri-devel
  Cc: Jani Nikula, daniel.vetter, intel-gfx, Rodrigo Vivi


[-- Attachment #1.1.1: Type: text/plain, Size: 23469 bytes --]

Hi

Am 07.04.19 um 18:52 schrieb Noralf Trønnes:
> It is generic code and having it in the helper will let other drivers
> benefit from it.
> 
> One change was necessary assuming this to be true:
> INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc
> 
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: intel-gfx@lists.freedesktop.org
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Reviewed-by: Jani Nikula <jani.nikula@intel.com>
> ---
>  drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
>  include/drm/drm_fb_helper.h        |  23 ---
>  3 files changed, 190 insertions(+), 245 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index a6be09ae899b..eda8b63f350d 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -2556,6 +2556,194 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
>  	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
>  }
>  
> +static struct drm_fb_helper_crtc *
> +drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
> +{
> +	int i;
> +
> +	for (i = 0; i < fb_helper->crtc_count; i++)
> +		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
> +			return &fb_helper->crtc_info[i];
> +
> +	return NULL;
> +}
> +
> +/* Try to read the BIOS display configuration and use it for the initial config */
> +static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
> +					  struct drm_fb_helper_crtc **crtcs,
> +					  struct drm_display_mode **modes,
> +					  struct drm_fb_offset *offsets,
> +					  bool *enabled, int width, int height)
> +{
> +	struct drm_device *dev = fb_helper->dev;
> +	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
> +	unsigned long conn_configured, conn_seq;
> +	int i, j;
> +	bool *save_enabled;
> +	bool fallback = true, ret = true;
> +	int num_connectors_enabled = 0;
> +	int num_connectors_detected = 0;
> +	struct drm_modeset_acquire_ctx ctx;
> +
> +	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
> +	if (!save_enabled)
> +		return false;
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +
> +	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
> +		drm_modeset_backoff(&ctx);
> +
> +	memcpy(save_enabled, enabled, count);
> +	conn_seq = GENMASK(count - 1, 0);
> +	conn_configured = 0;
> +retry:
> +	for (i = 0; i < count; i++) {
> +		struct drm_fb_helper_connector *fb_conn;
> +		struct drm_connector *connector;
> +		struct drm_encoder *encoder;
> +		struct drm_fb_helper_crtc *new_crtc;
> +
> +		fb_conn = fb_helper->connector_info[i];
> +		connector = fb_conn->connector;
> +
> +		if (conn_configured & BIT(i))
> +			continue;
> +
> +		/* First pass, only consider tiled connectors */
> +		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
> +			continue;
> +
> +		if (connector->status == connector_status_connected)
> +			num_connectors_detected++;
> +
> +		if (!enabled[i]) {
> +			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
> +				      connector->name);
> +			conn_configured |= BIT(i);
> +			continue;
> +		}
> +
> +		if (connector->force == DRM_FORCE_OFF) {
> +			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
> +				      connector->name);
> +			enabled[i] = false;
> +			continue;
> +		}
> +
> +		encoder = connector->state->best_encoder;

This patch breaks ast right here. Ast is a non-atomic driver and has
connector->state set to NULL. Reading best_encoder gives a NULL-pointer
dereference and the display turns black. Stack trace is below.

Best regards
Thomas


[   29.583012] [drm:drm_fb_helper_firmware_config.isra.37
[drm_kms_helper]] *ERROR* drivers/gpu/drm/drm_fb_helper.c:2649
connector=00000000db73d0b1
[   29.583048] [drm:drm_fb_helper_firmware_config.isra.37
[drm_kms_helper]] *ERROR* drivers/gpu/drm/drm_fb_helper.c:2650
connector->state=          (null)
0m] Found device[   29.609593] BUG: unable to handle kernel NULL pointer
dereference at 0000000000000010
[   29.609594] #PF error: [normal kernel read fault]
[   29.609595] PGD 0 P4D 0
[   29.609597] Oops: 0000 [#1] SMP PTI
[   29.609599] CPU: 1 PID: 354 Comm: systemd-udevd Tainted: G
 E     5.1.0-rc5-1-default+ #11
[   29.609600] Hardware name: Sun Microsystems SUN FIRE X2270 M2/SUN
FIRE X2270 M2, BIOS 2.05    07/01/2010
[   29.609608] RIP:
0010:drm_fb_helper_firmware_config.isra.37+0x2d6/0x8a0 [drm_kms_helper]
[   29.609609] Code: 48 89 de ba 5a 0a 00 00 48 c7 c7 5b 0b 48 c0 e8 60
d1 17 00 48 8b 85 e0 03 00 00 48 89 de ba 5b 0a 00 00 48 c7 c7 90 ef 47
c0 <48> 8b 48 10 e8 41 d1 17 00 ba 5d 0a 00 00 48 89 de 4c 89 ef 4b
[   29.609610] RSP: 0018:ffffb6f800c3f898 EFLAGS: 00010296
[   29.609612] RAX: 0000000000000000 RBX: ffffffffc047eec0 RCX:
0000000000000000
[   29.609612] RDX: 0000000000000a5b RSI: ffffffffc047eec0 RDI:
ffffffffc047ef90
[   29.609613] RBP: ffff9e76b6e42800 R08: 0000000000000002 R09:
0000000000000000
[   29.609614] R10: 00000000009053e2 R11: 0000000000002ae7 R12:
0000000000000000
[   29.609615] R13: ffffffffc0480b40 R14: 0000000000000000 R15:
ffff9e76b5bcac00
[   29.609616] FS:  00007f147397ef80(0000) GS:ffff9e76bb640000(0000)
knlGS:0000000000000000
[   29.609617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   29.609618] CR2: 0000000000000010 CR3: 0000000135bd2002 CR4:
00000000000206e0
[   29.609619] Call Trace:
[   29.609630]  ? drm_helper_probe_single_connector_modes+0x27f/0x680
[drm_kms_helper]
[   29.609640]  drm_setup_crtcs+0x431/0xd80 [drm_kms_helper]
[   29.753065]  __drm_fb_helper_initial_config_and_unlock+0x6f/0x6a0
[drm_kms_helper]
[   29.753160]  ? drm_modeset_unlock_all+0x31/0x50 [drm]
 ST1000[   29.765758]  ast_fbdev_init+0xa8/0xc0 [ast]
[   29.765762]  ast_driver_load.cold.7+0x2b3/0xe11 [ast]
[   29.765775]  drm_dev_register+0x111/0x150 [drm]
[   29.765790]  drm_get_pci_dev+0x95/0x190 [drm]
[   29.765794]  local_pci_probe+0x42/0x80
[   29.765796]  pci_device_probe+0xf4/0x170
[   29.765800]  really_probe+0xf8/0x3b0
[   29.765802]  driver_probe_device+0xb3/0xf0
[   29.765805]  device_driver_attach+0x50/0x60
[   29.805092]  __driver_attach+0x86/0x140
[   29.805095]  ? device_driver_attach+0x60/0x60
[   29.805138]  bus_for_each_dev+0x63/0x90
DM010-2EP102 4   29.817250]  bus_add_driver+0x131/0x1e0
[   29.817252]  ? 0xffffffffc03e6000
0m.
[   29.817254]  driver_register+0x6b/0xb0
[   29.817255]  ? 0xffffffffc03e6000
[   29.817258]  do_one_initcall+0x46/0x1c8
[   29.817262]  ? __vunmap+0x89/0xc0
[   29.817265]  do_init_module+0x5a/0x210
[   29.817266]  load_module+0x1aff/0x1f70
[   29.817270]  ? __do_sys_finit_module+0x8f/0xd0
[   29.817271]  __do_sys_finit_module+0x8f/0xd0
[   29.817274]  do_syscall_64+0x60/0x110
[   29.817279]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
[   29.817280] RIP: 0033:0x7f147428b2f9
[   29.817282] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00
48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f
05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 6f 4b 0c 00 f7 d8 64 89 08
[   29.817282] RSP: 002b:00007fffa8cd4478 EFLAGS: 00000246 ORIG_RAX:
0000000000000139
[   29.817284] RAX: ffffffffffffffda RBX: 0000561801fe62e0 RCX:
00007f147428b2f9
[   29.817285] RDX: 0000000000000000 RSI: 00007f147440089d RDI:
0000000000000016
[   29.817285] RBP: 0000000000000000 R08: 0000000000000000 R09:
0000561801ffcd50
[   29.817286] R10: 0000000000000016 R11: 0000000000000246 R12:
00007f147440089d
[   29.817287] R13: 0000000000020000 R14: 0000561802006510 R15:
0000561801fe62e0
[   29.817288] Modules linked in: hid_generic(E) btrfs(E) libcrc32c(E)
usbhid(E) xor(E) ast(E+) i2c_algo_bit(E) drm_kms_helper(E)
syscopyarea(E) sysfillrect(E) sysimgblt(E) fb_sys_fops(E) ehci_pci(E)
drm_vram_h)
[   29.817300] CR2: 0000000000000010
[   29.817311] ---[ end trace 640b47541cd2e101 ]---
[   29.827577] PM: Image not found (code -22)
[   29.830117] RIP:
0010:drm_fb_helper_firmware_config.isra.37+0x2d6/0x8a0 [drm_kms_helper]
[   29.985828] Code: 48 89 de ba 5a 0a 00 00 48 c7 c7 5b 0b 48 c0 e8 60
d1 17 00 48 8b 85 e0 03 00 00 48 89 de ba 5b 0a 00 00 48 c7 c7 90 ef 47
c0 <48> 8b 48 10 e8 41 d1 17 00 ba 5d 0a 00 00 48 89 de 4c 89 ef 4b
[   29.985829] RSP: 0018:ffffb6f800c3f898 EFLAGS: 00010296
[   29.985830] RAX: 0000000000000000 RBX: ffffffffc047eec0 RCX:
0000000000000000
[   29.985831] RDX: 0000000000000a5b RSI: ffffffffc047eec0 RDI:
ffffffffc047ef90
[   29.985832] RBP: ffff9e76b6e42800 R08: 0000000000000002 R09:
0000000000000000
[   29.985834] R10: 00000000009053e2 R11: 0000000000002ae7 R12:
0000000000000000
[   30.038589] R13: ffffffffc0480b40 R14: 0000000000000000 R15:
ffff9e76b5bcac00
[   30.038590] FS:  00007f147397ef80(0000) GS:ffff9e76bb640000(0000)
knlGS:0000000000000000
[   30.038591] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   30.038592] CR2: 0000000000000010 CR3: 0000000135bd2002 CR4:
00000000000206e0



> +		if (!encoder || WARN_ON(!connector->state->crtc)) {
> +			if (connector->force > DRM_FORCE_OFF)
> +				goto bail;
> +
> +			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
> +				      connector->name);
> +			enabled[i] = false;
> +			conn_configured |= BIT(i);
> +			continue;
> +		}
> +
> +		num_connectors_enabled++;
> +
> +		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
> +
> +		/*
> +		 * Make sure we're not trying to drive multiple connectors
> +		 * with a single CRTC, since our cloning support may not
> +		 * match the BIOS.
> +		 */
> +		for (j = 0; j < count; j++) {
> +			if (crtcs[j] == new_crtc) {
> +				DRM_DEBUG_KMS("fallback: cloned configuration\n");
> +				goto bail;
> +			}
> +		}
> +
> +		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
> +			      connector->name);
> +
> +		/* go for command line mode first */
> +		modes[i] = drm_pick_cmdline_mode(fb_conn);
> +
> +		/* try for preferred next */
> +		if (!modes[i]) {
> +			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
> +				      connector->name, connector->has_tile);
> +			modes[i] = drm_has_preferred_mode(fb_conn, width,
> +							  height);
> +		}
> +
> +		/* No preferred mode marked by the EDID? Are there any modes? */
> +		if (!modes[i] && !list_empty(&connector->modes)) {
> +			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
> +				      connector->name);
> +			modes[i] = list_first_entry(&connector->modes,
> +						    struct drm_display_mode,
> +						    head);
> +		}
> +
> +		/* last resort: use current mode */
> +		if (!modes[i]) {
> +			/*
> +			 * IMPORTANT: We want to use the adjusted mode (i.e.
> +			 * after the panel fitter upscaling) as the initial
> +			 * config, not the input mode, which is what crtc->mode
> +			 * usually contains. But since our current
> +			 * code puts a mode derived from the post-pfit timings
> +			 * into crtc->mode this works out correctly.
> +			 *
> +			 * This is crtc->mode and not crtc->state->mode for the
> +			 * fastboot check to work correctly.
> +			 */
> +			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
> +				      connector->name);
> +			modes[i] = &connector->state->crtc->mode;
> +		}
> +		crtcs[i] = new_crtc;
> +
> +		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
> +			      connector->name,
> +			      connector->state->crtc->base.id,
> +			      connector->state->crtc->name,
> +			      modes[i]->hdisplay, modes[i]->vdisplay,
> +			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
> +
> +		fallback = false;
> +		conn_configured |= BIT(i);
> +	}
> +
> +	if (conn_configured != conn_seq) { /* repeat until no more are found */
> +		conn_seq = conn_configured;
> +		goto retry;
> +	}
> +
> +	/*
> +	 * If the BIOS didn't enable everything it could, fall back to have the
> +	 * same user experiencing of lighting up as much as possible like the
> +	 * fbdev helper library.
> +	 */
> +	if (num_connectors_enabled != num_connectors_detected &&
> +	    num_connectors_enabled < dev->mode_config.num_crtc) {
> +		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
> +		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
> +			      num_connectors_detected);
> +		fallback = true;
> +	}
> +
> +	if (fallback) {
> +bail:
> +		DRM_DEBUG_KMS("Not using firmware configuration\n");
> +		memcpy(enabled, save_enabled, count);
> +		ret = false;
> +	}
> +
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +
> +	kfree(save_enabled);
> +	return ret;
> +}
> +
>  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  			    u32 width, u32 height)
>  {
> @@ -2588,10 +2776,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
>  	drm_enable_connectors(fb_helper, enabled);
>  
> -	if (!(fb_helper->funcs->initial_config &&
> -	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
> -					       offsets,
> -					       enabled, width, height))) {
> +	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
> +					   enabled, width, height)) {
>  		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
>  		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
>  		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index ef93c27e60b4..c4d17dda3355 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -284,225 +284,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
>  	return ret;
>  }
>  
> -static struct drm_fb_helper_crtc *
> -intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
> -{
> -	int i;
> -
> -	for (i = 0; i < fb_helper->crtc_count; i++)
> -		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
> -			return &fb_helper->crtc_info[i];
> -
> -	return NULL;
> -}
> -
> -/*
> - * Try to read the BIOS display configuration and use it for the initial
> - * fb configuration.
> - *
> - * The BIOS or boot loader will generally create an initial display
> - * configuration for us that includes some set of active pipes and displays.
> - * This routine tries to figure out which pipes and connectors are active
> - * and stuffs them into the crtcs and modes array given to us by the
> - * drm_fb_helper code.
> - *
> - * The overall sequence is:
> - *   intel_fbdev_init - from driver load
> - *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
> - *     drm_fb_helper_init - build fb helper structs
> - *     drm_fb_helper_single_add_all_connectors - more fb helper structs
> - *   intel_fbdev_initial_config - apply the config
> - *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
> - *         drm_setup_crtcs - build crtc config for fbdev
> - *           intel_fb_initial_config - find active connectors etc
> - *         drm_fb_helper_single_fb_probe - set up fbdev
> - *           intelfb_create - re-use or alloc fb, build out fbdev structs
> - *
> - * Note that we don't make special consideration whether we could actually
> - * switch to the selected modes without a full modeset. E.g. when the display
> - * is in VGA mode we need to recalculate watermarks and set a new high-res
> - * framebuffer anyway.
> - */
> -static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
> -				    struct drm_fb_helper_crtc **crtcs,
> -				    struct drm_display_mode **modes,
> -				    struct drm_fb_offset *offsets,
> -				    bool *enabled, int width, int height)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
> -	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
> -	unsigned long conn_configured, conn_seq;
> -	int i, j;
> -	bool *save_enabled;
> -	bool fallback = true, ret = true;
> -	int num_connectors_enabled = 0;
> -	int num_connectors_detected = 0;
> -	struct drm_modeset_acquire_ctx ctx;
> -
> -	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
> -	if (!save_enabled)
> -		return false;
> -
> -	drm_modeset_acquire_init(&ctx, 0);
> -
> -	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
> -		drm_modeset_backoff(&ctx);
> -
> -	memcpy(save_enabled, enabled, count);
> -	conn_seq = GENMASK(count - 1, 0);
> -	conn_configured = 0;
> -retry:
> -	for (i = 0; i < count; i++) {
> -		struct drm_fb_helper_connector *fb_conn;
> -		struct drm_connector *connector;
> -		struct drm_encoder *encoder;
> -		struct drm_fb_helper_crtc *new_crtc;
> -
> -		fb_conn = fb_helper->connector_info[i];
> -		connector = fb_conn->connector;
> -
> -		if (conn_configured & BIT(i))
> -			continue;
> -
> -		/* First pass, only consider tiled connectors */
> -		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
> -			continue;
> -
> -		if (connector->status == connector_status_connected)
> -			num_connectors_detected++;
> -
> -		if (!enabled[i]) {
> -			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
> -				      connector->name);
> -			conn_configured |= BIT(i);
> -			continue;
> -		}
> -
> -		if (connector->force == DRM_FORCE_OFF) {
> -			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
> -				      connector->name);
> -			enabled[i] = false;
> -			continue;
> -		}
> -
> -		encoder = connector->state->best_encoder;
> -		if (!encoder || WARN_ON(!connector->state->crtc)) {
> -			if (connector->force > DRM_FORCE_OFF)
> -				goto bail;
> -
> -			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
> -				      connector->name);
> -			enabled[i] = false;
> -			conn_configured |= BIT(i);
> -			continue;
> -		}
> -
> -		num_connectors_enabled++;
> -
> -		new_crtc = intel_fb_helper_crtc(fb_helper,
> -						connector->state->crtc);
> -
> -		/*
> -		 * Make sure we're not trying to drive multiple connectors
> -		 * with a single CRTC, since our cloning support may not
> -		 * match the BIOS.
> -		 */
> -		for (j = 0; j < count; j++) {
> -			if (crtcs[j] == new_crtc) {
> -				DRM_DEBUG_KMS("fallback: cloned configuration\n");
> -				goto bail;
> -			}
> -		}
> -
> -		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
> -			      connector->name);
> -
> -		/* go for command line mode first */
> -		modes[i] = drm_pick_cmdline_mode(fb_conn);
> -
> -		/* try for preferred next */
> -		if (!modes[i]) {
> -			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
> -				      connector->name, connector->has_tile);
> -			modes[i] = drm_has_preferred_mode(fb_conn, width,
> -							  height);
> -		}
> -
> -		/* No preferred mode marked by the EDID? Are there any modes? */
> -		if (!modes[i] && !list_empty(&connector->modes)) {
> -			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
> -				      connector->name);
> -			modes[i] = list_first_entry(&connector->modes,
> -						    struct drm_display_mode,
> -						    head);
> -		}
> -
> -		/* last resort: use current mode */
> -		if (!modes[i]) {
> -			/*
> -			 * IMPORTANT: We want to use the adjusted mode (i.e.
> -			 * after the panel fitter upscaling) as the initial
> -			 * config, not the input mode, which is what crtc->mode
> -			 * usually contains. But since our current
> -			 * code puts a mode derived from the post-pfit timings
> -			 * into crtc->mode this works out correctly.
> -			 *
> -			 * This is crtc->mode and not crtc->state->mode for the
> -			 * fastboot check to work correctly. crtc_state->mode has
> -			 * I915_MODE_FLAG_INHERITED, which we clear to force check
> -			 * state.
> -			 */
> -			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
> -				      connector->name);
> -			modes[i] = &connector->state->crtc->mode;
> -		}
> -		crtcs[i] = new_crtc;
> -
> -		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
> -			      connector->name,
> -			      connector->state->crtc->base.id,
> -			      connector->state->crtc->name,
> -			      modes[i]->hdisplay, modes[i]->vdisplay,
> -			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
> -
> -		fallback = false;
> -		conn_configured |= BIT(i);
> -	}
> -
> -	if (conn_configured != conn_seq) { /* repeat until no more are found */
> -		conn_seq = conn_configured;
> -		goto retry;
> -	}
> -
> -	/*
> -	 * If the BIOS didn't enable everything it could, fall back to have the
> -	 * same user experiencing of lighting up as much as possible like the
> -	 * fbdev helper library.
> -	 */
> -	if (num_connectors_enabled != num_connectors_detected &&
> -	    num_connectors_enabled < INTEL_INFO(dev_priv)->num_pipes) {
> -		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
> -		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
> -			      num_connectors_detected);
> -		fallback = true;
> -	}
> -
> -	if (fallback) {
> -bail:
> -		DRM_DEBUG_KMS("Not using firmware configuration\n");
> -		memcpy(enabled, save_enabled, count);
> -		ret = false;
> -	}
> -
> -	drm_modeset_drop_locks(&ctx);
> -	drm_modeset_acquire_fini(&ctx);
> -
> -	kfree(save_enabled);
> -	return ret;
> -}
> -
>  static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
> -	.initial_config = intel_fb_initial_config,
>  	.fb_probe = intelfb_create,
>  };
>  
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 81ae48a0df48..4db7de19a491 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -101,29 +101,6 @@ struct drm_fb_helper_funcs {
>  	 */
>  	int (*fb_probe)(struct drm_fb_helper *helper,
>  			struct drm_fb_helper_surface_size *sizes);
> -
> -	/**
> -	 * @initial_config:
> -	 *
> -	 * Driver callback to setup an initial fbdev display configuration.
> -	 * Drivers can use this callback to tell the fbdev emulation what the
> -	 * preferred initial configuration is. This is useful to implement
> -	 * smooth booting where the fbdev (and subsequently all userspace) never
> -	 * changes the mode, but always inherits the existing configuration.
> -	 *
> -	 * This callback is optional.
> -	 *
> -	 * RETURNS:
> -	 *
> -	 * The driver should return true if a suitable initial configuration has
> -	 * been filled out and false when the fbdev helper should fall back to
> -	 * the default probing logic.
> -	 */
> -	bool (*initial_config)(struct drm_fb_helper *fb_helper,
> -			       struct drm_fb_helper_crtc **crtcs,
> -			       struct drm_display_mode **modes,
> -			       struct drm_fb_offset *offsets,
> -			       bool *enabled, int width, int height);
>  };
>  
>  struct drm_fb_helper_connector {
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper
  2019-04-23 14:17   ` Thomas Zimmermann
@ 2019-04-23 14:58     ` Noralf Trønnes
  0 siblings, 0 replies; 41+ messages in thread
From: Noralf Trønnes @ 2019-04-23 14:58 UTC (permalink / raw)
  To: Thomas Zimmermann, dri-devel
  Cc: Jani Nikula, daniel.vetter, intel-gfx, Rodrigo Vivi



Den 23.04.2019 16.17, skrev Thomas Zimmermann:
> Hi
> 
> Am 07.04.19 um 18:52 schrieb Noralf Trønnes:
>> It is generic code and having it in the helper will let other drivers
>> benefit from it.
>>
>> One change was necessary assuming this to be true:
>> INTEL_INFO(dev_priv)->num_pipes == dev->mode_config.num_crtc
>>
>> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>> Cc: Jani Nikula <jani.nikula@linux.intel.com>
>> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>> Cc: intel-gfx@lists.freedesktop.org
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> Reviewed-by: Jani Nikula <jani.nikula@intel.com>
>> ---
>>  drivers/gpu/drm/drm_fb_helper.c    | 194 ++++++++++++++++++++++++-
>>  drivers/gpu/drm/i915/intel_fbdev.c | 218 -----------------------------
>>  include/drm/drm_fb_helper.h        |  23 ---
>>  3 files changed, 190 insertions(+), 245 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index a6be09ae899b..eda8b63f350d 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -2556,6 +2556,194 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper,
>>  	fb_helper->sw_rotations |= DRM_MODE_ROTATE_0;
>>  }
>>  
>> +static struct drm_fb_helper_crtc *
>> +drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < fb_helper->crtc_count; i++)
>> +		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
>> +			return &fb_helper->crtc_info[i];
>> +
>> +	return NULL;
>> +}
>> +
>> +/* Try to read the BIOS display configuration and use it for the initial config */
>> +static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
>> +					  struct drm_fb_helper_crtc **crtcs,
>> +					  struct drm_display_mode **modes,
>> +					  struct drm_fb_offset *offsets,
>> +					  bool *enabled, int width, int height)
>> +{
>> +	struct drm_device *dev = fb_helper->dev;
>> +	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
>> +	unsigned long conn_configured, conn_seq;
>> +	int i, j;
>> +	bool *save_enabled;
>> +	bool fallback = true, ret = true;
>> +	int num_connectors_enabled = 0;
>> +	int num_connectors_detected = 0;
>> +	struct drm_modeset_acquire_ctx ctx;
>> +
>> +	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
>> +	if (!save_enabled)
>> +		return false;
>> +
>> +	drm_modeset_acquire_init(&ctx, 0);
>> +
>> +	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
>> +		drm_modeset_backoff(&ctx);
>> +
>> +	memcpy(save_enabled, enabled, count);
>> +	conn_seq = GENMASK(count - 1, 0);
>> +	conn_configured = 0;
>> +retry:
>> +	for (i = 0; i < count; i++) {
>> +		struct drm_fb_helper_connector *fb_conn;
>> +		struct drm_connector *connector;
>> +		struct drm_encoder *encoder;
>> +		struct drm_fb_helper_crtc *new_crtc;
>> +
>> +		fb_conn = fb_helper->connector_info[i];
>> +		connector = fb_conn->connector;
>> +
>> +		if (conn_configured & BIT(i))
>> +			continue;
>> +
>> +		/* First pass, only consider tiled connectors */
>> +		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
>> +			continue;
>> +
>> +		if (connector->status == connector_status_connected)
>> +			num_connectors_detected++;
>> +
>> +		if (!enabled[i]) {
>> +			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
>> +				      connector->name);
>> +			conn_configured |= BIT(i);
>> +			continue;
>> +		}
>> +
>> +		if (connector->force == DRM_FORCE_OFF) {
>> +			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
>> +				      connector->name);
>> +			enabled[i] = false;
>> +			continue;
>> +		}
>> +
>> +		encoder = connector->state->best_encoder;
> 
> This patch breaks ast right here. Ast is a non-atomic driver and has
> connector->state set to NULL. Reading best_encoder gives a NULL-pointer
> dereference and the display turns black. Stack trace is below.
> 

Thanks for the report, I've sent a fix.

Noralf.

> Best regards
> Thomas
> 
> 
> [   29.583012] [drm:drm_fb_helper_firmware_config.isra.37
> [drm_kms_helper]] *ERROR* drivers/gpu/drm/drm_fb_helper.c:2649
> connector=00000000db73d0b1
> [   29.583048] [drm:drm_fb_helper_firmware_config.isra.37
> [drm_kms_helper]] *ERROR* drivers/gpu/drm/drm_fb_helper.c:2650
> connector->state=          (null)
> 0m] Found device[   29.609593] BUG: unable to handle kernel NULL pointer
> dereference at 0000000000000010
> [   29.609594] #PF error: [normal kernel read fault]
> [   29.609595] PGD 0 P4D 0
> [   29.609597] Oops: 0000 [#1] SMP PTI
> [   29.609599] CPU: 1 PID: 354 Comm: systemd-udevd Tainted: G
>  E     5.1.0-rc5-1-default+ #11
> [   29.609600] Hardware name: Sun Microsystems SUN FIRE X2270 M2/SUN
> FIRE X2270 M2, BIOS 2.05    07/01/2010
> [   29.609608] RIP:
> 0010:drm_fb_helper_firmware_config.isra.37+0x2d6/0x8a0 [drm_kms_helper]
> [   29.609609] Code: 48 89 de ba 5a 0a 00 00 48 c7 c7 5b 0b 48 c0 e8 60
> d1 17 00 48 8b 85 e0 03 00 00 48 89 de ba 5b 0a 00 00 48 c7 c7 90 ef 47
> c0 <48> 8b 48 10 e8 41 d1 17 00 ba 5d 0a 00 00 48 89 de 4c 89 ef 4b
> [   29.609610] RSP: 0018:ffffb6f800c3f898 EFLAGS: 00010296
> [   29.609612] RAX: 0000000000000000 RBX: ffffffffc047eec0 RCX:
> 0000000000000000
> [   29.609612] RDX: 0000000000000a5b RSI: ffffffffc047eec0 RDI:
> ffffffffc047ef90
> [   29.609613] RBP: ffff9e76b6e42800 R08: 0000000000000002 R09:
> 0000000000000000
> [   29.609614] R10: 00000000009053e2 R11: 0000000000002ae7 R12:
> 0000000000000000
> [   29.609615] R13: ffffffffc0480b40 R14: 0000000000000000 R15:
> ffff9e76b5bcac00
> [   29.609616] FS:  00007f147397ef80(0000) GS:ffff9e76bb640000(0000)
> knlGS:0000000000000000
> [   29.609617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   29.609618] CR2: 0000000000000010 CR3: 0000000135bd2002 CR4:
> 00000000000206e0
> [   29.609619] Call Trace:
> [   29.609630]  ? drm_helper_probe_single_connector_modes+0x27f/0x680
> [drm_kms_helper]
> [   29.609640]  drm_setup_crtcs+0x431/0xd80 [drm_kms_helper]
> [   29.753065]  __drm_fb_helper_initial_config_and_unlock+0x6f/0x6a0
> [drm_kms_helper]
> [   29.753160]  ? drm_modeset_unlock_all+0x31/0x50 [drm]
>  ST1000[   29.765758]  ast_fbdev_init+0xa8/0xc0 [ast]
> [   29.765762]  ast_driver_load.cold.7+0x2b3/0xe11 [ast]
> [   29.765775]  drm_dev_register+0x111/0x150 [drm]
> [   29.765790]  drm_get_pci_dev+0x95/0x190 [drm]
> [   29.765794]  local_pci_probe+0x42/0x80
> [   29.765796]  pci_device_probe+0xf4/0x170
> [   29.765800]  really_probe+0xf8/0x3b0
> [   29.765802]  driver_probe_device+0xb3/0xf0
> [   29.765805]  device_driver_attach+0x50/0x60
> [   29.805092]  __driver_attach+0x86/0x140
> [   29.805095]  ? device_driver_attach+0x60/0x60
> [   29.805138]  bus_for_each_dev+0x63/0x90
> DM010-2EP102 4   29.817250]  bus_add_driver+0x131/0x1e0
> [   29.817252]  ? 0xffffffffc03e6000
> 0m.
> [   29.817254]  driver_register+0x6b/0xb0
> [   29.817255]  ? 0xffffffffc03e6000
> [   29.817258]  do_one_initcall+0x46/0x1c8
> [   29.817262]  ? __vunmap+0x89/0xc0
> [   29.817265]  do_init_module+0x5a/0x210
> [   29.817266]  load_module+0x1aff/0x1f70
> [   29.817270]  ? __do_sys_finit_module+0x8f/0xd0
> [   29.817271]  __do_sys_finit_module+0x8f/0xd0
> [   29.817274]  do_syscall_64+0x60/0x110
> [   29.817279]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
> [   29.817280] RIP: 0033:0x7f147428b2f9
> [   29.817282] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00
> 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f
> 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 6f 4b 0c 00 f7 d8 64 89 08
> [   29.817282] RSP: 002b:00007fffa8cd4478 EFLAGS: 00000246 ORIG_RAX:
> 0000000000000139
> [   29.817284] RAX: ffffffffffffffda RBX: 0000561801fe62e0 RCX:
> 00007f147428b2f9
> [   29.817285] RDX: 0000000000000000 RSI: 00007f147440089d RDI:
> 0000000000000016
> [   29.817285] RBP: 0000000000000000 R08: 0000000000000000 R09:
> 0000561801ffcd50
> [   29.817286] R10: 0000000000000016 R11: 0000000000000246 R12:
> 00007f147440089d
> [   29.817287] R13: 0000000000020000 R14: 0000561802006510 R15:
> 0000561801fe62e0
> [   29.817288] Modules linked in: hid_generic(E) btrfs(E) libcrc32c(E)
> usbhid(E) xor(E) ast(E+) i2c_algo_bit(E) drm_kms_helper(E)
> syscopyarea(E) sysfillrect(E) sysimgblt(E) fb_sys_fops(E) ehci_pci(E)
> drm_vram_h)
> [   29.817300] CR2: 0000000000000010
> [   29.817311] ---[ end trace 640b47541cd2e101 ]---
> [   29.827577] PM: Image not found (code -22)
> [   29.830117] RIP:
> 0010:drm_fb_helper_firmware_config.isra.37+0x2d6/0x8a0 [drm_kms_helper]
> [   29.985828] Code: 48 89 de ba 5a 0a 00 00 48 c7 c7 5b 0b 48 c0 e8 60
> d1 17 00 48 8b 85 e0 03 00 00 48 89 de ba 5b 0a 00 00 48 c7 c7 90 ef 47
> c0 <48> 8b 48 10 e8 41 d1 17 00 ba 5d 0a 00 00 48 89 de 4c 89 ef 4b
> [   29.985829] RSP: 0018:ffffb6f800c3f898 EFLAGS: 00010296
> [   29.985830] RAX: 0000000000000000 RBX: ffffffffc047eec0 RCX:
> 0000000000000000
> [   29.985831] RDX: 0000000000000a5b RSI: ffffffffc047eec0 RDI:
> ffffffffc047ef90
> [   29.985832] RBP: ffff9e76b6e42800 R08: 0000000000000002 R09:
> 0000000000000000
> [   29.985834] R10: 00000000009053e2 R11: 0000000000002ae7 R12:
> 0000000000000000
> [   30.038589] R13: ffffffffc0480b40 R14: 0000000000000000 R15:
> ffff9e76b5bcac00
> [   30.038590] FS:  00007f147397ef80(0000) GS:ffff9e76bb640000(0000)
> knlGS:0000000000000000
> [   30.038591] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [   30.038592] CR2: 0000000000000010 CR3: 0000000135bd2002 CR4:
> 00000000000206e0
> 
> 
> 
>> +		if (!encoder || WARN_ON(!connector->state->crtc)) {
>> +			if (connector->force > DRM_FORCE_OFF)
>> +				goto bail;
>> +
>> +			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
>> +				      connector->name);
>> +			enabled[i] = false;
>> +			conn_configured |= BIT(i);
>> +			continue;
>> +		}
>> +
>> +		num_connectors_enabled++;
>> +
>> +		new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc);
>> +
>> +		/*
>> +		 * Make sure we're not trying to drive multiple connectors
>> +		 * with a single CRTC, since our cloning support may not
>> +		 * match the BIOS.
>> +		 */
>> +		for (j = 0; j < count; j++) {
>> +			if (crtcs[j] == new_crtc) {
>> +				DRM_DEBUG_KMS("fallback: cloned configuration\n");
>> +				goto bail;
>> +			}
>> +		}
>> +
>> +		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
>> +			      connector->name);
>> +
>> +		/* go for command line mode first */
>> +		modes[i] = drm_pick_cmdline_mode(fb_conn);
>> +
>> +		/* try for preferred next */
>> +		if (!modes[i]) {
>> +			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
>> +				      connector->name, connector->has_tile);
>> +			modes[i] = drm_has_preferred_mode(fb_conn, width,
>> +							  height);
>> +		}
>> +
>> +		/* No preferred mode marked by the EDID? Are there any modes? */
>> +		if (!modes[i] && !list_empty(&connector->modes)) {
>> +			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
>> +				      connector->name);
>> +			modes[i] = list_first_entry(&connector->modes,
>> +						    struct drm_display_mode,
>> +						    head);
>> +		}
>> +
>> +		/* last resort: use current mode */
>> +		if (!modes[i]) {
>> +			/*
>> +			 * IMPORTANT: We want to use the adjusted mode (i.e.
>> +			 * after the panel fitter upscaling) as the initial
>> +			 * config, not the input mode, which is what crtc->mode
>> +			 * usually contains. But since our current
>> +			 * code puts a mode derived from the post-pfit timings
>> +			 * into crtc->mode this works out correctly.
>> +			 *
>> +			 * This is crtc->mode and not crtc->state->mode for the
>> +			 * fastboot check to work correctly.
>> +			 */
>> +			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
>> +				      connector->name);
>> +			modes[i] = &connector->state->crtc->mode;
>> +		}
>> +		crtcs[i] = new_crtc;
>> +
>> +		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
>> +			      connector->name,
>> +			      connector->state->crtc->base.id,
>> +			      connector->state->crtc->name,
>> +			      modes[i]->hdisplay, modes[i]->vdisplay,
>> +			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
>> +
>> +		fallback = false;
>> +		conn_configured |= BIT(i);
>> +	}
>> +
>> +	if (conn_configured != conn_seq) { /* repeat until no more are found */
>> +		conn_seq = conn_configured;
>> +		goto retry;
>> +	}
>> +
>> +	/*
>> +	 * If the BIOS didn't enable everything it could, fall back to have the
>> +	 * same user experiencing of lighting up as much as possible like the
>> +	 * fbdev helper library.
>> +	 */
>> +	if (num_connectors_enabled != num_connectors_detected &&
>> +	    num_connectors_enabled < dev->mode_config.num_crtc) {
>> +		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
>> +		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
>> +			      num_connectors_detected);
>> +		fallback = true;
>> +	}
>> +
>> +	if (fallback) {
>> +bail:
>> +		DRM_DEBUG_KMS("Not using firmware configuration\n");
>> +		memcpy(enabled, save_enabled, count);
>> +		ret = false;
>> +	}
>> +
>> +	drm_modeset_drop_locks(&ctx);
>> +	drm_modeset_acquire_fini(&ctx);
>> +
>> +	kfree(save_enabled);
>> +	return ret;
>> +}
>> +
>>  static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  			    u32 width, u32 height)
>>  {
>> @@ -2588,10 +2776,8 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
>>  	drm_enable_connectors(fb_helper, enabled);
>>  
>> -	if (!(fb_helper->funcs->initial_config &&
>> -	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
>> -					       offsets,
>> -					       enabled, width, height))) {
>> +	if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
>> +					   enabled, width, height)) {
>>  		memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
>>  		memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
>>  		memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
>> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
>> index ef93c27e60b4..c4d17dda3355 100644
>> --- a/drivers/gpu/drm/i915/intel_fbdev.c
>> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
>> @@ -284,225 +284,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
>>  	return ret;
>>  }
>>  
>> -static struct drm_fb_helper_crtc *
>> -intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
>> -{
>> -	int i;
>> -
>> -	for (i = 0; i < fb_helper->crtc_count; i++)
>> -		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
>> -			return &fb_helper->crtc_info[i];
>> -
>> -	return NULL;
>> -}
>> -
>> -/*
>> - * Try to read the BIOS display configuration and use it for the initial
>> - * fb configuration.
>> - *
>> - * The BIOS or boot loader will generally create an initial display
>> - * configuration for us that includes some set of active pipes and displays.
>> - * This routine tries to figure out which pipes and connectors are active
>> - * and stuffs them into the crtcs and modes array given to us by the
>> - * drm_fb_helper code.
>> - *
>> - * The overall sequence is:
>> - *   intel_fbdev_init - from driver load
>> - *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
>> - *     drm_fb_helper_init - build fb helper structs
>> - *     drm_fb_helper_single_add_all_connectors - more fb helper structs
>> - *   intel_fbdev_initial_config - apply the config
>> - *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
>> - *         drm_setup_crtcs - build crtc config for fbdev
>> - *           intel_fb_initial_config - find active connectors etc
>> - *         drm_fb_helper_single_fb_probe - set up fbdev
>> - *           intelfb_create - re-use or alloc fb, build out fbdev structs
>> - *
>> - * Note that we don't make special consideration whether we could actually
>> - * switch to the selected modes without a full modeset. E.g. when the display
>> - * is in VGA mode we need to recalculate watermarks and set a new high-res
>> - * framebuffer anyway.
>> - */
>> -static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>> -				    struct drm_fb_helper_crtc **crtcs,
>> -				    struct drm_display_mode **modes,
>> -				    struct drm_fb_offset *offsets,
>> -				    bool *enabled, int width, int height)
>> -{
>> -	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
>> -	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
>> -	unsigned long conn_configured, conn_seq;
>> -	int i, j;
>> -	bool *save_enabled;
>> -	bool fallback = true, ret = true;
>> -	int num_connectors_enabled = 0;
>> -	int num_connectors_detected = 0;
>> -	struct drm_modeset_acquire_ctx ctx;
>> -
>> -	save_enabled = kcalloc(count, sizeof(bool), GFP_KERNEL);
>> -	if (!save_enabled)
>> -		return false;
>> -
>> -	drm_modeset_acquire_init(&ctx, 0);
>> -
>> -	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
>> -		drm_modeset_backoff(&ctx);
>> -
>> -	memcpy(save_enabled, enabled, count);
>> -	conn_seq = GENMASK(count - 1, 0);
>> -	conn_configured = 0;
>> -retry:
>> -	for (i = 0; i < count; i++) {
>> -		struct drm_fb_helper_connector *fb_conn;
>> -		struct drm_connector *connector;
>> -		struct drm_encoder *encoder;
>> -		struct drm_fb_helper_crtc *new_crtc;
>> -
>> -		fb_conn = fb_helper->connector_info[i];
>> -		connector = fb_conn->connector;
>> -
>> -		if (conn_configured & BIT(i))
>> -			continue;
>> -
>> -		/* First pass, only consider tiled connectors */
>> -		if (conn_seq == GENMASK(count - 1, 0) && !connector->has_tile)
>> -			continue;
>> -
>> -		if (connector->status == connector_status_connected)
>> -			num_connectors_detected++;
>> -
>> -		if (!enabled[i]) {
>> -			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
>> -				      connector->name);
>> -			conn_configured |= BIT(i);
>> -			continue;
>> -		}
>> -
>> -		if (connector->force == DRM_FORCE_OFF) {
>> -			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
>> -				      connector->name);
>> -			enabled[i] = false;
>> -			continue;
>> -		}
>> -
>> -		encoder = connector->state->best_encoder;
>> -		if (!encoder || WARN_ON(!connector->state->crtc)) {
>> -			if (connector->force > DRM_FORCE_OFF)
>> -				goto bail;
>> -
>> -			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
>> -				      connector->name);
>> -			enabled[i] = false;
>> -			conn_configured |= BIT(i);
>> -			continue;
>> -		}
>> -
>> -		num_connectors_enabled++;
>> -
>> -		new_crtc = intel_fb_helper_crtc(fb_helper,
>> -						connector->state->crtc);
>> -
>> -		/*
>> -		 * Make sure we're not trying to drive multiple connectors
>> -		 * with a single CRTC, since our cloning support may not
>> -		 * match the BIOS.
>> -		 */
>> -		for (j = 0; j < count; j++) {
>> -			if (crtcs[j] == new_crtc) {
>> -				DRM_DEBUG_KMS("fallback: cloned configuration\n");
>> -				goto bail;
>> -			}
>> -		}
>> -
>> -		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
>> -			      connector->name);
>> -
>> -		/* go for command line mode first */
>> -		modes[i] = drm_pick_cmdline_mode(fb_conn);
>> -
>> -		/* try for preferred next */
>> -		if (!modes[i]) {
>> -			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
>> -				      connector->name, connector->has_tile);
>> -			modes[i] = drm_has_preferred_mode(fb_conn, width,
>> -							  height);
>> -		}
>> -
>> -		/* No preferred mode marked by the EDID? Are there any modes? */
>> -		if (!modes[i] && !list_empty(&connector->modes)) {
>> -			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
>> -				      connector->name);
>> -			modes[i] = list_first_entry(&connector->modes,
>> -						    struct drm_display_mode,
>> -						    head);
>> -		}
>> -
>> -		/* last resort: use current mode */
>> -		if (!modes[i]) {
>> -			/*
>> -			 * IMPORTANT: We want to use the adjusted mode (i.e.
>> -			 * after the panel fitter upscaling) as the initial
>> -			 * config, not the input mode, which is what crtc->mode
>> -			 * usually contains. But since our current
>> -			 * code puts a mode derived from the post-pfit timings
>> -			 * into crtc->mode this works out correctly.
>> -			 *
>> -			 * This is crtc->mode and not crtc->state->mode for the
>> -			 * fastboot check to work correctly. crtc_state->mode has
>> -			 * I915_MODE_FLAG_INHERITED, which we clear to force check
>> -			 * state.
>> -			 */
>> -			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
>> -				      connector->name);
>> -			modes[i] = &connector->state->crtc->mode;
>> -		}
>> -		crtcs[i] = new_crtc;
>> -
>> -		DRM_DEBUG_KMS("connector %s on [CRTC:%d:%s]: %dx%d%s\n",
>> -			      connector->name,
>> -			      connector->state->crtc->base.id,
>> -			      connector->state->crtc->name,
>> -			      modes[i]->hdisplay, modes[i]->vdisplay,
>> -			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
>> -
>> -		fallback = false;
>> -		conn_configured |= BIT(i);
>> -	}
>> -
>> -	if (conn_configured != conn_seq) { /* repeat until no more are found */
>> -		conn_seq = conn_configured;
>> -		goto retry;
>> -	}
>> -
>> -	/*
>> -	 * If the BIOS didn't enable everything it could, fall back to have the
>> -	 * same user experiencing of lighting up as much as possible like the
>> -	 * fbdev helper library.
>> -	 */
>> -	if (num_connectors_enabled != num_connectors_detected &&
>> -	    num_connectors_enabled < INTEL_INFO(dev_priv)->num_pipes) {
>> -		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
>> -		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
>> -			      num_connectors_detected);
>> -		fallback = true;
>> -	}
>> -
>> -	if (fallback) {
>> -bail:
>> -		DRM_DEBUG_KMS("Not using firmware configuration\n");
>> -		memcpy(enabled, save_enabled, count);
>> -		ret = false;
>> -	}
>> -
>> -	drm_modeset_drop_locks(&ctx);
>> -	drm_modeset_acquire_fini(&ctx);
>> -
>> -	kfree(save_enabled);
>> -	return ret;
>> -}
>> -
>>  static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
>> -	.initial_config = intel_fb_initial_config,
>>  	.fb_probe = intelfb_create,
>>  };
>>  
>> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
>> index 81ae48a0df48..4db7de19a491 100644
>> --- a/include/drm/drm_fb_helper.h
>> +++ b/include/drm/drm_fb_helper.h
>> @@ -101,29 +101,6 @@ struct drm_fb_helper_funcs {
>>  	 */
>>  	int (*fb_probe)(struct drm_fb_helper *helper,
>>  			struct drm_fb_helper_surface_size *sizes);
>> -
>> -	/**
>> -	 * @initial_config:
>> -	 *
>> -	 * Driver callback to setup an initial fbdev display configuration.
>> -	 * Drivers can use this callback to tell the fbdev emulation what the
>> -	 * preferred initial configuration is. This is useful to implement
>> -	 * smooth booting where the fbdev (and subsequently all userspace) never
>> -	 * changes the mode, but always inherits the existing configuration.
>> -	 *
>> -	 * This callback is optional.
>> -	 *
>> -	 * RETURNS:
>> -	 *
>> -	 * The driver should return true if a suitable initial configuration has
>> -	 * been filled out and false when the fbdev helper should fall back to
>> -	 * the default probing logic.
>> -	 */
>> -	bool (*initial_config)(struct drm_fb_helper *fb_helper,
>> -			       struct drm_fb_helper_crtc **crtcs,
>> -			       struct drm_display_mode **modes,
>> -			       struct drm_fb_offset *offsets,
>> -			       bool *enabled, int width, int height);
>>  };
>>  
>>  struct drm_fb_helper_connector {
>>
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2019-04-23 14:58 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-07 16:52 [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Noralf Trønnes
2019-04-07 16:52 ` [PATCH v2 01/12] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
2019-04-16  9:12   ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 02/12] drm/fb-helper: Avoid race with DRM userspace Noralf Trønnes
2019-04-16  7:59   ` Daniel Vetter
2019-04-16 18:46     ` Noralf Trønnes
2019-04-17 13:24       ` Daniel Vetter
2019-04-17 13:26         ` Daniel Vetter
2019-04-17 14:48           ` Noralf Trønnes
2019-04-16  9:26   ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 03/12] drm/i915/fbdev: Move intel_fb_initial_config() to fbdev helper Noralf Trønnes
2019-04-11 14:25   ` Noralf Trønnes
2019-04-23 14:17   ` Thomas Zimmermann
2019-04-23 14:58     ` Noralf Trønnes
2019-04-07 16:52 ` [PATCH v2 04/12] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
2019-04-16  9:28   ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 05/12] drm/fb-helper: Remove drm_fb_helper_crtc->{x, y, desired_mode} Noralf Trønnes
2019-04-16  9:29   ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 06/12] drm/fb-helper: Remove drm_fb_helper_crtc Noralf Trønnes
2019-04-16  8:34   ` Daniel Vetter
2019-04-07 16:52 ` [PATCH v2 07/12] drm/fb-helper: Prepare to move out commit code Noralf Trønnes
2019-04-07 16:52 ` [PATCH v2 08/12] drm/fb-helper: Move " Noralf Trønnes
2019-04-16  8:38   ` Daniel Vetter
2019-04-17 17:56     ` Noralf Trønnes
2019-04-18  8:30       ` Daniel Vetter
2019-04-07 16:52 ` [PATCH v2 09/12] drm/fb-helper: Remove drm_fb_helper_connector Noralf Trønnes
2019-04-16  9:42   ` Maxime Ripard
2019-04-16 14:57     ` Noralf Trønnes
2019-04-17 16:48       ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 10/12] drm/fb-helper: Prepare to move out modeset config code Noralf Trønnes
2019-04-16  9:43   ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 11/12] drm/fb-helper: Move " Noralf Trønnes
2019-04-16  9:43   ` Maxime Ripard
2019-04-07 16:52 ` [PATCH v2 12/12] drm/client: Hack: Add bootsplash example Noralf Trønnes
2019-04-07 17:02 ` ✗ Fi.CI.CHECKPATCH: warning for drm/fb-helper: Move modesetting code to drm_client (rev2) Patchwork
2019-04-07 17:10 ` ✗ Fi.CI.SPARSE: " Patchwork
2019-04-07 17:21 ` ✓ Fi.CI.BAT: success " Patchwork
2019-04-07 18:29 ` ✓ Fi.CI.IGT: " Patchwork
2019-04-16  8:41 ` [PATCH v2 00/12] drm/fb-helper: Move modesetting code to drm_client Daniel Vetter
2019-04-16  8:46   ` Daniel Vetter
2019-04-17 18:06   ` Noralf Trønnes

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.