dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [RFC v4 00/25] drm: Add generic fbdev emulation
@ 2018-04-14 11:52 Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 01/25] drm: provide management functions for drm_file Noralf Trønnes
                   ` (25 more replies)
  0 siblings, 26 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

This patchset explores the possibility of having generic fbdev emulation
in DRM for drivers that supports dumb buffers which they can export. An
API is added to support in-kernel clients in general.

In this version I was able to reuse the modesetting code from
drm_fb_helper in the client API. This avoids code duplication, carries
over lessons learned and the modesetting code is bisectable. The
downside is that it takes +10 patches to rip drm_fb_helper in two, so
maybe it's not worth it wrt possible breakage and a challenging review.

Does the Intel CI test the fbdev emulation?

Daniel had this concern with the previous version:

    The register/unregister model needs more thought. Allowing both clients
    to register whenever they want to, and drm_device instances to come and
    go is what fbcon has done, and the resulting locking is a horror show.

    I think if we require that all in-kernel drm_clients are registers when
    loading drm.ko (and enabled/disabled only per module options and
    Kconfig), then we can throw out all the locking. That avoids a lot of
    the headaches.

I have solved this by adding a notifier that fires when a new DRM device
is registered (I've removed the new() callback). Currently only
bootsplash uses this. The fbdev client needs to be setup from the driver
since it can't know on device registration if the driver will setup it's
own fbdev emulation later and the vtcon client hooks up to a user
provided device id.

Since fbcon can't handle fb_open failing, the buffer has to be
pre-allocated. Exporting a GEM buffer pins the driver module making it
impossible to unload it.
I have included 2 solutions to the problem:
- sysfs file to remove/close clients: remove_internal_clients
- Change drm_gem_prime_export() so it doesn't pin on client buffers

If a dumb buffer is exported from a kernel thread (worker) context, the
file descriptor isn't closed and I leak a reference so the buffer isn't
freed. Please look at drm_client_buffer_create() in patch
'drm/client: Finish the in-kernel client API'.
This is a blocker that needs a solution.


Noralf.

Changes since version 3:
Client API changes:
- Drop drm_client_register_funcs() which attached clients indirectly.
  Let clients attach directly using drm_client_new{_from_id}(). Clients
  that wants to attach to all devices must be linked into drm.ko and use
  the DRM device notifier. This is done to avoid the lock/race
  register/unregister hell we have with fbcon. (Daniel Vetter)
- drm_client_display_restore() checks if there is a master and if so
  returns -EBUSY. (Daniel Vetter)
- Allocate drm_file up front instead of on-demand. Since fbdev can't do
  on demand buffer allocation because of fbcon, there's no need for this.
- Add sysfs file to remove clients
- Don't pin driver module when exporting gem client buffers
- Dropped page flip support since drm_fb_helper is now used for fbdev
  emulation.

- The bootsplash client now switches over to fbdev on keypress.

Changes since version 2:
- Don't set drm master for in-kernel clients. (Daniel Vetter)
- Add in-kernel client API

Changes since version 1:
- Don't add drm_fb_helper_fb_open() and drm_fb_helper_fb_release() to
  DRM_FB_HELPER_DEFAULT_OPS(). (Fi.CI.STATIC)
  The following uses that macro and sets fb_open/close: udlfb_ops,
  amdgpufb_ops, drm_fb_helper_generic_fbdev_ops, nouveau_fbcon_ops,
  nouveau_fbcon_sw_ops, radeonfb_ops.
  This results in: warning: Initializer entry defined twice
- Support CONFIG_DRM_KMS_HELPER=m (kbuild test robot)
  ERROR: <function> [drivers/gpu/drm/drm_kms_helper.ko] undefined!
- Drop buggy patch: (Chris Wilson)
  drm/prime: Clear drm_gem_object->dma_buf on release
- Defer buffer creation until fb_open.


David Herrmann (1):
  drm: provide management functions for drm_file

Noralf Trønnes (24):
  drm/file: Don't set master on in-kernel clients
  drm/fb-helper: No need to cache rotation and sw_rotations
  drm/fb-helper: Remove drm_fb_helper_debug_enter/leave()
  drm/fb-helper: dpms_legacy(): Only set on connectors in use
  drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  drm: Begin an API for in-kernel clients
  drm/fb-helper: Use struct drm_client_display
  drm/fb-helper: Move modeset commit code to drm_client
  drm/connector: Add
    drm_connector_has_preferred_mode/pick_cmdline_mode()
  drm/connector: Add connector array functions
  drm/i915: Add drm_driver->initial_client_display callback
  drm/fb-helper: Remove struct drm_fb_helper_crtc
  drm/fb-helper: Remove struct drm_fb_helper_connector
  drm/fb-helper: Move modeset config code to drm_client
  drm: Make ioctls available for in-kernel clients
  drm/client: Bail out if there's a DRM master
  drm/client: Make the display modes available to clients
  drm/client: Finish the in-kernel client API
  drm/prime: Don't pin module on export for in-kernel clients
  drm/fb-helper: Add drm_fb_helper_fb_open/release()
  drm/fb-helper: Add generic fbdev emulation
  drm: Add DRM device registered notifier
  drm/client: Hack: Add bootsplash
  drm/client: Hack: Add DRM VT console client

 drivers/gpu/drm/Kconfig                 |    2 +
 drivers/gpu/drm/Makefile                |    4 +-
 drivers/gpu/drm/client/Kconfig          |   14 +
 drivers/gpu/drm/client/Makefile         |    3 +
 drivers/gpu/drm/client/drm_bootsplash.c |  248 ++++++
 drivers/gpu/drm/client/drm_vtcon.c      |  785 +++++++++++++++++
 drivers/gpu/drm/client/internal.h       |   19 +
 drivers/gpu/drm/drm_atomic.c            |  168 ++++
 drivers/gpu/drm/drm_atomic_helper.c     |  168 +---
 drivers/gpu/drm/drm_auth.c              |   33 +
 drivers/gpu/drm/drm_client.c            | 1448 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_connector.c         |  199 +++++
 drivers/gpu/drm/drm_crtc_internal.h     |   18 +-
 drivers/gpu/drm/drm_debugfs.c           |    7 +
 drivers/gpu/drm/drm_drv.c               |   43 +
 drivers/gpu/drm/drm_dumb_buffers.c      |   33 +-
 drivers/gpu/drm/drm_fb_helper.c         | 1420 ++++++++----------------------
 drivers/gpu/drm/drm_file.c              |  304 ++++---
 drivers/gpu/drm/drm_framebuffer.c       |   50 +-
 drivers/gpu/drm/drm_internal.h          |    7 +
 drivers/gpu/drm/drm_ioc32.c             |    2 +-
 drivers/gpu/drm/drm_ioctl.c             |    4 +-
 drivers/gpu/drm/drm_prime.c             |   37 +-
 drivers/gpu/drm/drm_probe_helper.c      |    3 +
 drivers/gpu/drm/drm_sysfs.c             |   20 +
 drivers/gpu/drm/i915/i915_drv.c         |    1 +
 drivers/gpu/drm/i915/intel_drv.h        |   11 +
 drivers/gpu/drm/i915/intel_fbdev.c      |  112 +--
 include/drm/drm_atomic.h                |    5 +
 include/drm/drm_atomic_helper.h         |    4 -
 include/drm/drm_client.h                |  182 ++++
 include/drm/drm_connector.h             |   11 +
 include/drm/drm_device.h                |    4 +
 include/drm/drm_drv.h                   |   25 +
 include/drm/drm_fb_helper.h             |  126 ++-
 35 files changed, 4007 insertions(+), 1513 deletions(-)
 create mode 100644 drivers/gpu/drm/client/Kconfig
 create mode 100644 drivers/gpu/drm/client/Makefile
 create mode 100644 drivers/gpu/drm/client/drm_bootsplash.c
 create mode 100644 drivers/gpu/drm/client/drm_vtcon.c
 create mode 100644 drivers/gpu/drm/client/internal.h
 create mode 100644 drivers/gpu/drm/drm_client.c
 create mode 100644 include/drm/drm_client.h

--
2.15.1

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

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

* [RFC v4 01/25] drm: provide management functions for drm_file
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
@ 2018-04-14 11:52 ` Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 02/25] drm/file: Don't set master on in-kernel clients Noralf Trønnes
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes, David Herrmann

From: David Herrmann <dh.herrmann@gmail.com>

Rather than doing drm_file allocation/destruction right in the fops, lets
provide separate helpers. This decouples drm_file management from the
still-mandatory drm-fops. It prepares for use of drm_file without the
fops, both by possible separate fops implementations and APIs (not that I
am aware of any such plans), and more importantly from in-kernel use where
no real file is available.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_file.c     | 305 +++++++++++++++++++++++------------------
 drivers/gpu/drm/drm_internal.h |   2 +
 2 files changed, 175 insertions(+), 132 deletions(-)

diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index e394799979a6..d4588d33f91c 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -101,6 +101,175 @@ DEFINE_MUTEX(drm_global_mutex);
 
 static int drm_open_helper(struct file *filp, struct drm_minor *minor);
 
+/**
+ * drm_file_alloc - allocate file context
+ * @minor: minor to allocate on
+ *
+ * This allocates a new DRM file context. It is not linked into any context and
+ * can be used by the caller freely. Note that the context keeps a pointer to
+ * @minor, so it must be freed before @minor is.
+ *
+ * RETURNS:
+ * Pointer to newly allocated context, ERR_PTR on failure.
+ */
+struct drm_file *drm_file_alloc(struct drm_minor *minor)
+{
+	struct drm_device *dev = minor->dev;
+	struct drm_file *file;
+	int ret;
+
+	file = kzalloc(sizeof(*file), GFP_KERNEL);
+	if (!file)
+		return ERR_PTR(-ENOMEM);
+
+	file->pid = get_pid(task_pid(current));
+	file->minor = minor;
+
+	/* for compatibility root is always authenticated */
+	file->authenticated = capable(CAP_SYS_ADMIN);
+	file->lock_count = 0;
+
+	INIT_LIST_HEAD(&file->lhead);
+	INIT_LIST_HEAD(&file->fbs);
+	mutex_init(&file->fbs_lock);
+	INIT_LIST_HEAD(&file->blobs);
+	INIT_LIST_HEAD(&file->pending_event_list);
+	INIT_LIST_HEAD(&file->event_list);
+	init_waitqueue_head(&file->event_wait);
+	file->event_space = 4096; /* set aside 4k for event buffer */
+
+	mutex_init(&file->event_read_lock);
+
+	if (drm_core_check_feature(dev, DRIVER_GEM))
+		drm_gem_open(dev, file);
+
+	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		drm_syncobj_open(file);
+
+	if (drm_core_check_feature(dev, DRIVER_PRIME))
+		drm_prime_init_file_private(&file->prime);
+
+	if (dev->driver->open) {
+		ret = dev->driver->open(dev, file);
+		if (ret < 0)
+			goto out_prime_destroy;
+	}
+
+	if (drm_is_primary_client(file)) {
+		ret = drm_master_open(file);
+		if (ret)
+			goto out_close;
+	}
+
+	return file;
+
+out_close:
+	if (dev->driver->postclose)
+		dev->driver->postclose(dev, file);
+out_prime_destroy:
+	if (drm_core_check_feature(dev, DRIVER_PRIME))
+		drm_prime_destroy_file_private(&file->prime);
+	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		drm_syncobj_release(file);
+	if (drm_core_check_feature(dev, DRIVER_GEM))
+		drm_gem_release(dev, file);
+	put_pid(file->pid);
+	kfree(file);
+
+	return ERR_PTR(ret);
+}
+
+static void drm_events_release(struct drm_file *file_priv)
+{
+	struct drm_device *dev = file_priv->minor->dev;
+	struct drm_pending_event *e, *et;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	/* Unlink pending events */
+	list_for_each_entry_safe(e, et, &file_priv->pending_event_list,
+				 pending_link) {
+		list_del(&e->pending_link);
+		e->file_priv = NULL;
+	}
+
+	/* Remove unconsumed events */
+	list_for_each_entry_safe(e, et, &file_priv->event_list, link) {
+		list_del(&e->link);
+		kfree(e);
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+/**
+ * drm_file_free - free file context
+ * @file: context to free, or NULL
+ *
+ * This destroys and deallocates a DRM file context previously allocated via
+ * drm_file_alloc(). The caller must make sure to unlink it from any contexts
+ * before calling this.
+ *
+ * If NULL is passed, this is a no-op.
+ *
+ * RETURNS:
+ * 0 on success, or error code on failure.
+ */
+void drm_file_free(struct drm_file *file)
+{
+	struct drm_device *dev;
+
+	if (!file)
+		return;
+
+	dev = file->minor->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
+		  task_pid_nr(current),
+		  (long)old_encode_dev(file->minor->kdev->devt),
+		  dev->open_count);
+
+	if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
+	    dev->driver->preclose)
+		dev->driver->preclose(dev, file);
+
+	if (drm_core_check_feature(dev, DRIVER_LEGACY))
+		drm_legacy_lock_release(dev, file->filp);
+
+	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
+		drm_legacy_reclaim_buffers(dev, file);
+
+	drm_events_release(file);
+
+	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		drm_fb_release(file);
+		drm_property_destroy_user_blobs(dev, file);
+	}
+
+	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		drm_syncobj_release(file);
+
+	if (drm_core_check_feature(dev, DRIVER_GEM))
+		drm_gem_release(dev, file);
+
+	drm_legacy_ctxbitmap_flush(dev, file);
+
+	if (drm_is_primary_client(file))
+		drm_master_release(file);
+
+	if (dev->driver->postclose)
+		dev->driver->postclose(dev, file);
+
+	if (drm_core_check_feature(dev, DRIVER_PRIME))
+		drm_prime_destroy_file_private(&file->prime);
+
+	WARN_ON(!list_empty(&file->event_list));
+
+	put_pid(file->pid);
+	kfree(file);
+}
+
 static int drm_setup(struct drm_device * dev)
 {
 	int ret;
@@ -196,7 +365,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
 {
 	struct drm_device *dev = minor->dev;
 	struct drm_file *priv;
-	int ret;
 
 	if (filp->f_flags & O_EXCL)
 		return -EBUSY;	/* No exclusive opens */
@@ -207,50 +375,12 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
 
 	DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index);
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	priv = drm_file_alloc(minor);
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
 
 	filp->private_data = priv;
 	priv->filp = filp;
-	priv->pid = get_pid(task_pid(current));
-	priv->minor = minor;
-
-	/* for compatibility root is always authenticated */
-	priv->authenticated = capable(CAP_SYS_ADMIN);
-	priv->lock_count = 0;
-
-	INIT_LIST_HEAD(&priv->lhead);
-	INIT_LIST_HEAD(&priv->fbs);
-	mutex_init(&priv->fbs_lock);
-	INIT_LIST_HEAD(&priv->blobs);
-	INIT_LIST_HEAD(&priv->pending_event_list);
-	INIT_LIST_HEAD(&priv->event_list);
-	init_waitqueue_head(&priv->event_wait);
-	priv->event_space = 4096; /* set aside 4k for event buffer */
-
-	mutex_init(&priv->event_read_lock);
-
-	if (drm_core_check_feature(dev, DRIVER_GEM))
-		drm_gem_open(dev, priv);
-
-	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
-		drm_syncobj_open(priv);
-
-	if (drm_core_check_feature(dev, DRIVER_PRIME))
-		drm_prime_init_file_private(&priv->prime);
-
-	if (dev->driver->open) {
-		ret = dev->driver->open(dev, priv);
-		if (ret < 0)
-			goto out_prime_destroy;
-	}
-
-	if (drm_is_primary_client(priv)) {
-		ret = drm_master_open(priv);
-		if (ret)
-			goto out_close;
-	}
 
 	mutex_lock(&dev->filelist_mutex);
 	list_add(&priv->lhead, &dev->filelist);
@@ -277,45 +407,6 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
 #endif
 
 	return 0;
-
-out_close:
-	if (dev->driver->postclose)
-		dev->driver->postclose(dev, priv);
-out_prime_destroy:
-	if (drm_core_check_feature(dev, DRIVER_PRIME))
-		drm_prime_destroy_file_private(&priv->prime);
-	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
-		drm_syncobj_release(priv);
-	if (drm_core_check_feature(dev, DRIVER_GEM))
-		drm_gem_release(dev, priv);
-	put_pid(priv->pid);
-	kfree(priv);
-	filp->private_data = NULL;
-	return ret;
-}
-
-static void drm_events_release(struct drm_file *file_priv)
-{
-	struct drm_device *dev = file_priv->minor->dev;
-	struct drm_pending_event *e, *et;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->event_lock, flags);
-
-	/* Unlink pending events */
-	list_for_each_entry_safe(e, et, &file_priv->pending_event_list,
-				 pending_link) {
-		list_del(&e->pending_link);
-		e->file_priv = NULL;
-	}
-
-	/* Remove unconsumed events */
-	list_for_each_entry_safe(e, et, &file_priv->event_list, link) {
-		list_del(&e->link);
-		kfree(e);
-	}
-
-	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
 static void drm_legacy_dev_reinit(struct drm_device *dev)
@@ -382,57 +473,7 @@ int drm_release(struct inode *inode, struct file *filp)
 	list_del(&file_priv->lhead);
 	mutex_unlock(&dev->filelist_mutex);
 
-	if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
-	    dev->driver->preclose)
-		dev->driver->preclose(dev, file_priv);
-
-	/* ========================================================
-	 * Begin inline drm_release
-	 */
-
-	DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
-		  task_pid_nr(current),
-		  (long)old_encode_dev(file_priv->minor->kdev->devt),
-		  dev->open_count);
-
-	if (drm_core_check_feature(dev, DRIVER_LEGACY))
-		drm_legacy_lock_release(dev, filp);
-
-	if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
-		drm_legacy_reclaim_buffers(dev, file_priv);
-
-	drm_events_release(file_priv);
-
-	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-		drm_fb_release(file_priv);
-		drm_property_destroy_user_blobs(dev, file_priv);
-	}
-
-	if (drm_core_check_feature(dev, DRIVER_SYNCOBJ))
-		drm_syncobj_release(file_priv);
-
-	if (drm_core_check_feature(dev, DRIVER_GEM))
-		drm_gem_release(dev, file_priv);
-
-	drm_legacy_ctxbitmap_flush(dev, file_priv);
-
-	if (drm_is_primary_client(file_priv))
-		drm_master_release(file_priv);
-
-	if (dev->driver->postclose)
-		dev->driver->postclose(dev, file_priv);
-
-	if (drm_core_check_feature(dev, DRIVER_PRIME))
-		drm_prime_destroy_file_private(&file_priv->prime);
-
-	WARN_ON(!list_empty(&file_priv->event_list));
-
-	put_pid(file_priv->pid);
-	kfree(file_priv);
-
-	/* ========================================================
-	 * End inline drm_release
-	 */
+	drm_file_free(file_priv);
 
 	if (!--dev->open_count) {
 		drm_lastclose(dev);
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index b72242e93ea4..40179c5fc6b8 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -26,6 +26,8 @@
 
 /* drm_file.c */
 extern struct mutex drm_global_mutex;
+struct drm_file *drm_file_alloc(struct drm_minor *minor);
+void drm_file_free(struct drm_file *file);
 void drm_lastclose(struct drm_device *dev);
 
 /* drm_pci.c */
-- 
2.15.1

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

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

* [RFC v4 02/25] drm/file: Don't set master on in-kernel clients
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 01/25] drm: provide management functions for drm_file Noralf Trønnes
@ 2018-04-14 11:52 ` Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 03/25] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

It only makes sense for userspace clients.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_file.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index d4588d33f91c..55505378df47 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -155,17 +155,8 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor)
 			goto out_prime_destroy;
 	}
 
-	if (drm_is_primary_client(file)) {
-		ret = drm_master_open(file);
-		if (ret)
-			goto out_close;
-	}
-
 	return file;
 
-out_close:
-	if (dev->driver->postclose)
-		dev->driver->postclose(dev, file);
 out_prime_destroy:
 	if (drm_core_check_feature(dev, DRIVER_PRIME))
 		drm_prime_destroy_file_private(&file->prime);
@@ -365,6 +356,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
 {
 	struct drm_device *dev = minor->dev;
 	struct drm_file *priv;
+	int ret;
 
 	if (filp->f_flags & O_EXCL)
 		return -EBUSY;	/* No exclusive opens */
@@ -379,6 +371,14 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
 	if (IS_ERR(priv))
 		return PTR_ERR(priv);
 
+	if (drm_is_primary_client(priv)) {
+		ret = drm_master_open(priv);
+		if (ret) {
+			drm_file_free(priv);
+			return ret;
+		}
+	}
+
 	filp->private_data = priv;
 	priv->filp = filp;
 
-- 
2.15.1

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

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

* [RFC v4 03/25] drm/fb-helper: No need to cache rotation and sw_rotations
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 01/25] drm: provide management functions for drm_file Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 02/25] drm/file: Don't set master on in-kernel clients Noralf Trønnes
@ 2018-04-14 11:52 ` Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 04/25] drm/fb-helper: Remove drm_fb_helper_debug_enter/leave() Noralf Trønnes
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: Hans de Goede, intel-gfx

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>
---
 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 0646b108030b..e48ace2d55f5 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -361,6 +361,48 @@ 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_connector *connector,
+					 struct drm_plane *plane,
+					 unsigned int *rotation)
+{
+	uint64_t valid_mask = 0;
+	unsigned int i;
+
+	if (!connector)
+		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;
@@ -406,10 +448,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->connectors[0], primary, &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)
@@ -841,7 +886,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;
@@ -2414,62 +2458,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, its 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 void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
@@ -2529,7 +2517,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];
@@ -2549,7 +2536,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;
@@ -2572,11 +2558,24 @@ 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->connectors[0],
+						 modeset->crtc->primary, &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) {
@@ -2592,7 +2591,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 b069433e7fc1..d1e45c832cd5 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -49,7 +49,6 @@ struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
 	struct drm_display_mode *desired_mode;
 	int x, y;
-	int rotation;
 };
 
 /**
@@ -160,13 +159,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.15.1

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

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

* [RFC v4 04/25] drm/fb-helper: Remove drm_fb_helper_debug_enter/leave()
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (2 preceding siblings ...)
  2018-04-14 11:52 ` [RFC v4 03/25] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
@ 2018-04-14 11:52 ` Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 05/25] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

Atomic drivers can't use them so finish what was started in
commit 9c79e0b1d096 ("drm/fb-helper: Give up on kgdb for atomic drivers").

This prepares the ground for creating modesets on demand.

TODO:
- Actually remove the functions, not just the contents.
- Nuke drm_crtc_helper_funcs->mode_set_base_atomic
- Documentation/dev-tools/kgdb.rst

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

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index e48ace2d55f5..06e94de6452a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -267,96 +267,14 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
 }
 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;
-
-	if (crtc->funcs->gamma_set == NULL)
-		return;
-
-	r_base = crtc->gamma_store;
-	g_base = r_base + crtc->gamma_size;
-	b_base = g_base + crtc->gamma_size;
-
-	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
-			       crtc->gamma_size, NULL);
-}
-
-/**
- * drm_fb_helper_debug_enter - implementation for &fb_ops.fb_debug_enter
- * @info: fbdev registered by the helper
- */
 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;
-
-	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;
-
-			if (!mode_set->crtc->enabled)
-				continue;
-
-			funcs =	mode_set->crtc->helper_private;
-			if (funcs->mode_set_base_atomic == NULL)
-				continue;
-
-			if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
-				continue;
-
-			funcs->mode_set_base_atomic(mode_set->crtc,
-						    mode_set->fb,
-						    mode_set->x,
-						    mode_set->y,
-						    ENTER_ATOMIC_MODE_SET);
-		}
-	}
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_enter);
 
-/**
- * drm_fb_helper_debug_leave - implementation for &fb_ops.fb_debug_leave
- * @info: fbdev registered by the helper
- */
 int drm_fb_helper_debug_leave(struct fb_info *info)
 {
-	struct drm_fb_helper *helper = info->par;
-	struct drm_crtc *crtc;
-	const struct drm_crtc_helper_funcs *funcs;
-	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;
-
-		crtc = mode_set->crtc;
-		if (drm_drv_uses_atomic_modeset(crtc->dev))
-			continue;
-
-		funcs = crtc->helper_private;
-		fb = crtc->primary->fb;
-
-		if (!crtc->enabled)
-			continue;
-
-		if (!fb) {
-			DRM_ERROR("no fb to restore??\n");
-			continue;
-		}
-
-		if (funcs->mode_set_base_atomic == NULL)
-			continue;
-
-		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
-		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
-					    crtc->y, LEAVE_ATOMIC_MODE_SET);
-	}
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
-- 
2.15.1

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

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

* [RFC v4 05/25] drm/fb-helper: dpms_legacy(): Only set on connectors in use
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (3 preceding siblings ...)
  2018-04-14 11:52 ` [RFC v4 04/25] drm/fb-helper: Remove drm_fb_helper_debug_enter/leave() Noralf Trønnes
@ 2018-04-14 11:52 ` Noralf Trønnes
  2018-04-14 11:52 ` [RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

For each enabled crtc the functions sets dpms on all registered connectors.
Limit this to only doing it once and on the connectors actually in use.

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

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 06e94de6452a..d0936671a9a6 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -583,20 +583,19 @@ 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_device *dev = fb_helper->dev;
-	struct drm_crtc *crtc;
 	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
 	int i, j;
 
 	drm_modeset_lock_all(dev);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
-		crtc = fb_helper->crtc_info[i].mode_set.crtc;
+		modeset = &fb_helper->crtc_info[i].mode_set;
 
-		if (!crtc->enabled)
+		if (!modeset->crtc->enabled)
 			continue;
 
-		/* Walk the connectors & encoders on this fb turning them on/off */
-		drm_fb_helper_for_each_connector(fb_helper, j) {
-			connector = fb_helper->connector_info[j]->connector;
+		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);
-- 
2.15.1

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

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

* [RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (4 preceding siblings ...)
  2018-04-14 11:52 ` [RFC v4 05/25] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
@ 2018-04-14 11:52 ` Noralf Trønnes
  2018-04-16  8:30   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 07/25] drm: Begin an API for in-kernel clients Noralf Trønnes
                   ` (19 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:52 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

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.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_atomic_helper.c | 168 +-----------------------------------
 drivers/gpu/drm/drm_fb_helper.c     |   8 +-
 include/drm/drm_atomic.h            |   5 ++
 include/drm/drm_atomic_helper.h     |   4 -
 5 files changed, 179 insertions(+), 174 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 7d25c42f22db..1fb602b6c8b1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -2060,6 +2060,174 @@ void drm_atomic_clean_old_fb(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_atomic_clean_old_fb);
 
+/* just used from drm_client and atomic-helper: */
+int drm_atomic_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_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_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_set_config);
+
 /**
  * DOC: explicit fencing properties
  *
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index ee03c1ed2521..4f20eb58dd4f 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2673,7 +2673,7 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
 	if (plane_state->crtc && plane_state->crtc->cursor == plane)
 		plane_state->state->legacy_cursor_update = true;
 
-	ret = __drm_atomic_helper_disable_plane(plane, plane_state);
+	ret = drm_atomic_disable_plane(plane, plane_state);
 	if (ret != 0)
 		goto fail;
 
@@ -2684,95 +2684,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
@@ -2801,7 +2712,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
 		return -ENOMEM;
 
 	state->acquire_ctx = ctx;
-	ret = __drm_atomic_helper_set_config(set, state);
+	ret = drm_atomic_set_config(set, state);
 	if (ret != 0)
 		goto fail;
 
@@ -2817,81 +2728,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;
-}
-
 static int __drm_atomic_helper_disable_all(struct drm_device *dev,
 					   struct drm_modeset_acquire_ctx *ctx,
 					   bool clean_old_fbs)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index d0936671a9a6..2eef24db21f8 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -358,7 +358,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
 			continue;
 
-		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
+		ret = drm_atomic_disable_plane(plane, plane_state);
 		if (ret != 0)
 			goto out_state;
 	}
@@ -374,13 +374,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
 			plane_state->rotation = rotation;
 		}
 
-		ret = __drm_atomic_helper_set_config(mode_set, state);
+		ret = drm_atomic_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
+		 * drm_atomic_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;
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index a57a8aa90ffb..0b0827ff2169 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -604,6 +604,11 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
 void
 drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret);
 
+int drm_atomic_disable_plane(struct drm_plane *plane,
+			     struct drm_plane_state *plane_state);
+int drm_atomic_set_config(struct drm_mode_set *set,
+			  struct drm_atomic_state *state);
+
 int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
 int __must_check drm_atomic_commit(struct drm_atomic_state *state);
 int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 26aaba58d6ce..8d88a8b2ad52 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -114,12 +114,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.15.1

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

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

* [RFC v4 07/25] drm: Begin an API for in-kernel clients
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (5 preceding siblings ...)
  2018-04-14 11:52 ` [RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 08/25] drm/fb-helper: Use struct drm_client_display Noralf Trønnes
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

This the beginning of an API for in-kernel clients.
First out is a display representation that will be used by drm_fb_helper
in order to move out its mode setting code.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Makefile     |   2 +-
 drivers/gpu/drm/drm_client.c | 119 +++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_client.h     |  44 ++++++++++++++++
 3 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/drm_client.c
 create mode 100644 include/drm/drm_client.h

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9d66657ea117..d25afa136d8f 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -18,7 +18,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_encoder.o drm_mode_object.o drm_property.o \
 		drm_plane.o drm_color_mgmt.o drm_print.o \
 		drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \
-		drm_syncobj.o drm_lease.o
+		drm_syncobj.o drm_lease.o drm_client.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
new file mode 100644
index 000000000000..7c31a6efb2f4
--- /dev/null
+++ b/drivers/gpu/drm/drm_client.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 Noralf Trønnes
+ *
+ * For parts copied from drm_fb_helper:
+ * Copyright (c) 2006-2009 Red Hat Inc.
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ */
+
+#include <linux/slab.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_modes.h>
+
+/**
+ * drm_client_display_create() - Create display structure
+ * @dev: DRM device
+ *
+ * This function creates a display structure for clients backed by an array of
+ * &drm_mode_set, one per CRTC.
+ *
+ * Returns:
+ * A &drm_client_display or an error pointer on allocation failure.
+ */
+struct drm_client_display *drm_client_display_create(struct drm_device *dev)
+{
+	unsigned int num_crtc = dev->mode_config.num_crtc;
+	struct drm_client_display *display;
+	struct drm_mode_set *modeset;
+	struct drm_crtc *crtc;
+	unsigned int i = 0;
+
+	display = kzalloc(sizeof(*display), GFP_KERNEL);
+	if (!display)
+		return ERR_PTR(-ENOMEM);
+
+	/* Add NULL terminating entry to enable index less iteration */
+	display->modesets = kcalloc(num_crtc + 1, sizeof(*display->modesets), GFP_KERNEL);
+	if (!display->modesets) {
+		kfree(display);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	display->dev = dev;
+	display->modeset_count = num_crtc;
+
+	drm_for_each_crtc(crtc, dev)
+		display->modesets[i++].crtc = crtc;
+
+	drm_client_display_for_each_modeset(modeset, display) {
+		/* One connector per crtc except for the cloned case */
+		modeset->connectors = kcalloc(2, sizeof(*modeset->connectors), GFP_KERNEL);
+		if (!modeset->connectors)
+			goto err_free;
+	}
+
+	return display;
+
+err_free:
+	drm_client_display_free(display);
+
+	return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL(drm_client_display_create);
+
+/**
+ * drm_client_display_free() - Free display structure
+ * @display: Client display
+ *
+ * This function frees the structure allocated by drm_client_display_create().
+ * It also destroys display modes and puts connectors.
+ */
+void drm_client_display_free(struct drm_client_display *display)
+{
+	struct drm_mode_set *modeset;
+	unsigned int i;
+
+	if (!display)
+		return;
+
+	drm_client_display_for_each_modeset(modeset, display) {
+		if (modeset->mode)
+			drm_mode_destroy(display->dev, modeset->mode);
+
+		for (i = 0; i < modeset->num_connectors; i++)
+			drm_connector_put(modeset->connectors[i]);
+		kfree(modeset->connectors);
+	}
+	kfree(display->modesets);
+	kfree(display);
+}
+EXPORT_SYMBOL(drm_client_display_free);
+
+/**
+ * drm_client_display_find_modeset() - Find modeset matching a CRTC
+ * @display: Client display
+ * @crtc: CRTC
+ *
+ * This function looks up the @display modeset connected to @crtc.
+ *
+ * Returns:
+ * A &drm_mode_set or NULL.
+ */
+struct drm_mode_set *
+drm_client_display_find_modeset(struct drm_client_display *display, struct drm_crtc *crtc)
+{
+	struct drm_mode_set *modeset;
+
+	drm_client_display_for_each_modeset(modeset, display)
+		if (modeset->crtc == crtc)
+			return modeset;
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_client_display_find_modeset);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
new file mode 100644
index 000000000000..b6a057802769
--- /dev/null
+++ b/include/drm/drm_client.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DRM_CLIENT_H_
+#define _DRM_CLIENT_H_
+
+struct drm_crtc;
+struct drm_device;
+struct drm_mode_set;
+
+/**
+ * struct drm_client_display - DRM client display
+ */
+struct drm_client_display {
+	/**
+	 * @dev:
+	 *
+	 * DRM device.
+	 */
+	struct drm_device *dev;
+
+	/**
+	 * @modesets:
+	 *
+	 * Per CRTC array of modeset configurations.
+	 */
+	struct drm_mode_set *modesets;
+
+	/**
+	 * @modeset_count:
+	 *
+	 * Number of modesets
+	 */
+	unsigned int modeset_count;
+};
+
+struct drm_client_display *drm_client_display_create(struct drm_device *dev);
+void drm_client_display_free(struct drm_client_display *display);
+struct drm_mode_set *
+drm_client_display_find_modeset(struct drm_client_display *display, struct drm_crtc *crtc);
+
+#define drm_client_display_for_each_modeset(modeset, display) \
+	for (modeset = display->modesets; modeset->crtc; modeset++)
+
+#endif
-- 
2.15.1

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

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

* [RFC v4 08/25] drm/fb-helper: Use struct drm_client_display
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (6 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 07/25] drm: Begin an API for in-kernel clients Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 09/25] drm/fb-helper: Move modeset commit code to drm_client Noralf Trønnes
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

Prepare to move the modeset committing code to drm_client.

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

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2eef24db21f8..bdb4b57d2c12 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
+#include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -321,13 +322,14 @@ static bool drm_fb_helper_panel_rotation(struct drm_connector *connector,
 	return true;
 }
 
-static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
+static int drm_client_display_restore_atomic(struct drm_client_display *display, bool active)
 {
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = display->dev;
 	struct drm_plane_state *plane_state;
+	struct drm_mode_set *mode_set;
 	struct drm_plane *plane;
 	struct drm_atomic_state *state;
-	int i, ret;
+	int ret;
 	unsigned int plane_mask;
 	struct drm_modeset_acquire_ctx ctx;
 
@@ -363,8 +365,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_display_for_each_modeset(mode_set, display) {
 		struct drm_plane *primary = mode_set->crtc->primary;
 		unsigned int rotation;
 
@@ -412,13 +413,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_display_restore_legacy(struct drm_client_display *display)
 {
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = display->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_modeset_lock_all(dev);
 	drm_for_each_plane(plane, dev) {
 		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
 			drm_plane_force_disable(plane);
@@ -429,8 +431,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_display_for_each_modeset(mode_set, display) {
 		struct drm_crtc *crtc = mode_set->crtc;
 
 		if (crtc->funcs->cursor_set2) {
@@ -448,19 +449,17 @@ 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(struct drm_fb_helper *fb_helper)
+static int drm_client_display_restore(struct drm_client_display *display)
 {
-	struct drm_device *dev = fb_helper->dev;
-
-	if (drm_drv_uses_atomic_modeset(dev))
-		return restore_fbdev_mode_atomic(fb_helper, true);
+	if (drm_drv_uses_atomic_modeset(display->dev))
+		return drm_client_display_restore_atomic(display, true);
 	else
-		return restore_fbdev_mode_legacy(fb_helper);
+		return drm_client_display_restore_legacy(display);
 }
 
 /**
@@ -486,7 +485,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_display_restore(fb_helper->display);
 
 	do_delayed = fb_helper->delayed_hotplug;
 	if (do_delayed)
@@ -548,7 +547,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
 			continue;
 
 		mutex_lock(&helper->lock);
-		ret = restore_fbdev_mode(helper);
+		ret = drm_client_display_restore(helper->display);
 		if (ret)
 			error = true;
 		mutex_unlock(&helper->lock);
@@ -580,22 +579,20 @@ 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_display_dpms_legacy(struct drm_client_display *display, int dpms_mode)
 {
-	struct drm_device *dev = fb_helper->dev;
+	struct drm_device *dev = display->dev;
 	struct drm_connector *connector;
 	struct drm_mode_set *modeset;
-	int i, j;
+	int i;
 
 	drm_modeset_lock_all(dev);
-	for (i = 0; i < fb_helper->crtc_count; i++) {
-		modeset = &fb_helper->crtc_info[i].mode_set;
-
+	drm_client_display_for_each_modeset(modeset, display) {
 		if (!modeset->crtc->enabled)
 			continue;
 
-		for (j = 0; j < modeset->num_connectors; j++) {
-			connector = modeset->connectors[j];
+		for (i = 0; i < modeset->num_connectors; i++) {
+			connector = modeset->connectors[i];
 			connector->funcs->dpms(connector, dpms_mode);
 			drm_object_property_set_value(&connector->base,
 				dev->mode_config.dpms_property, dpms_mode);
@@ -604,23 +601,21 @@ static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 	drm_modeset_unlock_all(dev);
 }
 
+static void drm_client_display_dpms(struct drm_client_display *display, int mode)
+{
+	if (drm_drv_uses_atomic_modeset(display->dev))
+		drm_client_display_restore_atomic(display, mode == DRM_MODE_DPMS_ON);
+	else
+		drm_client_display_dpms_legacy(display, mode);
+}
+
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
 
-	/*
-	 * 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_drv_uses_atomic_modeset(fb_helper->dev))
-		restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
-	else
-		dpms_legacy(fb_helper, dpms_mode);
+	if (drm_fb_helper_is_bound(fb_helper))
+		drm_client_display_dpms(fb_helper->display, dpms_mode);
 	mutex_unlock(&fb_helper->lock);
 }
 
@@ -811,6 +806,10 @@ int drm_fb_helper_init(struct drm_device *dev,
 		i++;
 	}
 
+	fb_helper->display = drm_client_display_create(dev);
+	if (IS_ERR(fb_helper->display))
+		goto out_free;
+
 	dev->fb_helper = fb_helper;
 
 	return 0;
@@ -919,6 +918,7 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 	mutex_unlock(&kernel_fb_helper_lock);
 
 	mutex_destroy(&fb_helper->lock);
+	drm_client_display_free(fb_helper->display);
 	drm_fb_helper_crtc_free(fb_helper);
 
 }
@@ -1265,13 +1265,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_display_for_each_modeset(modeset, fb_helper->display) {
+		crtc = modeset->crtc;
 		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
 			return -EINVAL;
 
@@ -1347,9 +1348,10 @@ 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;
+	int ret = 0;
 	bool replaced;
 
 	drm_modeset_acquire_init(&ctx, 0);
@@ -1362,8 +1364,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_display_for_each_modeset(modeset, fb_helper->display) {
+		crtc = modeset->crtc;
 
 		if (!gamma_lut)
 			gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
@@ -1391,8 +1393,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_display_for_each_modeset(modeset, fb_helper->display) {
+		crtc = modeset->crtc;
 
 		r = crtc->gamma_store;
 		g = r + crtc->gamma_size;
@@ -1468,7 +1470,6 @@ 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_mode_set *mode_set;
 	struct drm_crtc *crtc;
 	int ret = 0;
 
@@ -1496,8 +1497,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->display->modesets[0].crtc;
 
 		/*
 		 * Only wait for a vblank event if the CRTC is
@@ -1651,13 +1651,9 @@ 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;
 
+	drm_client_display_for_each_modeset(mode_set, fb_helper->display) {
 		mode_set->x = x;
 		mode_set->y = y;
 	}
@@ -1671,7 +1667,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 = drm_client_display_restore(fb_helper->display);
 	if (!ret) {
 		info->var.xoffset = var->xoffset;
 		info->var.yoffset = var->yoffset;
@@ -1687,12 +1683,9 @@ static int pan_display_legacy(struct fb_var_screeninfo *var,
 	struct drm_fb_helper *fb_helper = info->par;
 	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;
-
+	drm_client_display_for_each_modeset(modeset, fb_helper->display) {
 		modeset->x = var->xoffset;
 		modeset->y = var->yoffset;
 
@@ -1751,6 +1744,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	int crtc_count = 0;
 	int i;
 	struct drm_fb_helper_surface_size sizes;
+	struct drm_mode_set *mode_set;
 	int gamma_size = 0;
 
 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
@@ -1795,9 +1789,8 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	}
 
 	crtc_count = 0;
-	for (i = 0; i < fb_helper->crtc_count; i++) {
+	drm_client_display_for_each_modeset(mode_set, fb_helper->display) {
 		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
@@ -1805,19 +1798,18 @@ 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;
 
 		if (gamma_size == 0)
-			gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
+			gamma_size = mode_set->crtc->gamma_size;
 
 		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);
@@ -1844,7 +1836,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 && !READ_ONCE(fb_helper->dev->master))
-			restore_fbdev_mode(fb_helper);
+			drm_client_display_restore(fb_helper->display);
 		return -EAGAIN;
 	}
 
@@ -2379,6 +2371,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
 	struct drm_device *dev = fb_helper->dev;
+	struct drm_client_display *display;
 	struct drm_fb_helper_crtc **crtcs;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
@@ -2402,6 +2395,10 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		goto out;
 	}
 
+	display = drm_client_display_create(dev);
+	if (IS_ERR(display))
+		goto out;
+
 	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");
@@ -2440,24 +2437,29 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		struct drm_fb_offset *offset = &offsets[i];
 
 		if (mode && fb_crtc) {
-			struct drm_mode_set *modeset = &fb_crtc->mode_set;
 			struct drm_connector *connector =
 				fb_helper->connector_info[i]->connector;
+			struct drm_mode_set *modeset;
+
+			modeset = drm_client_display_find_modeset(display, fb_crtc->mode_set.crtc);
+			if (WARN_ON(!modeset)) {
+				drm_client_display_free(display);
+				goto out;
+			}
 
 			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, modeset->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;
 			modeset->y = offset->y;
 		}
 	}
+
+	drm_client_display_free(fb_helper->display);
+	fb_helper->display = display;
 out:
 	kfree(crtcs);
 	kfree(modes);
@@ -2476,11 +2478,10 @@ 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;
+	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;
-
+	drm_client_display_for_each_modeset(modeset, fb_helper->display) {
 		if (!modeset->num_connectors)
 			continue;
 
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index d1e45c832cd5..e2df40ad5063 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -155,6 +155,14 @@ struct drm_fb_helper_connector {
 struct drm_fb_helper {
 	struct drm_framebuffer *fb;
 	struct drm_device *dev;
+
+	/**
+	 * @display:
+	 *
+	 * Display representation.
+	 */
+	struct drm_client_display *display;
+
 	int crtc_count;
 	struct drm_fb_helper_crtc *crtc_info;
 	int connector_count;
-- 
2.15.1

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

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

* [RFC v4 09/25] drm/fb-helper: Move modeset commit code to drm_client
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (7 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 08/25] drm/fb-helper: Use struct drm_client_display Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 10/25] drm/connector: Add drm_connector_has_preferred_mode/pick_cmdline_mode() Noralf Trønnes
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

This moves the committing part of the modesetting code to drm_client.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c    | 242 ++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c | 216 +----------------------------------
 include/drm/drm_client.h        |   8 ++
 3 files changed, 252 insertions(+), 214 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 7c31a6efb2f4..c85c13568cf9 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -10,6 +10,8 @@
 
 #include <linux/slab.h>
 
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_client.h>
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
@@ -117,3 +119,243 @@ drm_client_display_find_modeset(struct drm_client_display *display, struct drm_c
 	return NULL;
 }
 EXPORT_SYMBOL(drm_client_display_find_modeset);
+
+/**
+ * drm_client_display_panel_rotation() - Check panel orientation
+ * @connector: DRM connector
+ * @plane: DRM plane
+ * @rotation: Returned rotation value
+ *
+ * This function checks if @plane can hw rotate to match the panel orientation
+ * on @connector.
+ *
+ * Return:
+ * True if the plane can do the rotation, false otherwise.
+ */
+bool drm_client_display_panel_rotation(struct drm_connector *connector,
+				       struct drm_plane *plane,
+				       unsigned int *rotation)
+{
+	uint64_t valid_mask = 0;
+	unsigned int i;
+
+	if (!connector)
+		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;
+}
+EXPORT_SYMBOL(drm_client_display_panel_rotation);
+
+static int drm_client_display_restore_atomic(struct drm_client_display *display, bool active)
+{
+	struct drm_device *dev = display->dev;
+	struct drm_plane_state *plane_state;
+	struct drm_mode_set *mode_set;
+	struct drm_plane *plane;
+	struct drm_atomic_state *state;
+	int ret;
+	unsigned int plane_mask;
+	struct drm_modeset_acquire_ctx ctx;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state) {
+		ret = -ENOMEM;
+		goto out_ctx;
+	}
+
+	state->acquire_ctx = &ctx;
+retry:
+	plane_mask = 0;
+	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;
+
+		plane->old_fb = plane->fb;
+		plane_mask |= 1 << drm_plane_index(plane);
+
+		/* disable non-primary: */
+		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+			continue;
+
+		ret = drm_atomic_disable_plane(plane, plane_state);
+		if (ret != 0)
+			goto out_state;
+	}
+
+	drm_client_display_for_each_modeset(mode_set, display) {
+		struct drm_plane *primary = mode_set->crtc->primary;
+		unsigned int rotation;
+
+		if (drm_client_display_panel_rotation(mode_set->connectors[0], primary, &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_set_config(mode_set, state);
+		if (ret != 0)
+			goto out_state;
+
+		/*
+		 * drm_atomic_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:
+	drm_atomic_clean_old_fb(dev, plane_mask, ret);
+
+	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_display_restore_legacy(struct drm_client_display *display)
+{
+	struct drm_device *dev = display->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_display_for_each_modeset(mode_set, display) {
+		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_display_restore() - Restore client display
+ * @display: Client display
+ *
+ * Restore client display using the current modeset configuration.
+ *
+ * Return:
+ * Zero on succes or negative error code on failure.
+ */
+int drm_client_display_restore(struct drm_client_display *display)
+{
+	if (drm_drv_uses_atomic_modeset(display->dev))
+		return drm_client_display_restore_atomic(display, true);
+	else
+		return drm_client_display_restore_legacy(display);
+}
+EXPORT_SYMBOL(drm_client_display_restore);
+
+static void drm_client_display_dpms_legacy(struct drm_client_display *display, int dpms_mode)
+{
+	struct drm_device *dev = display->dev;
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	int i;
+
+	drm_modeset_lock_all(dev);
+	drm_client_display_for_each_modeset(modeset, display) {
+		if (!modeset->crtc->enabled)
+			continue;
+
+		for (i = 0; i < modeset->num_connectors; i++) {
+			connector = modeset->connectors[i];
+			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_display_dpms() - Set display DPMS mode
+ * @display: Client display
+ * @mode: DPMS mode
+ */
+void drm_client_display_dpms(struct drm_client_display *display, int mode)
+{
+	if (drm_drv_uses_atomic_modeset(display->dev))
+		drm_client_display_restore_atomic(display, mode == DRM_MODE_DPMS_ON);
+	else
+		drm_client_display_dpms_legacy(display, mode);
+}
+EXPORT_SYMBOL(drm_client_display_dpms);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index bdb4b57d2c12..785a2f5d2647 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -280,188 +280,6 @@ 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_connector *connector,
-					 struct drm_plane *plane,
-					 unsigned int *rotation)
-{
-	uint64_t valid_mask = 0;
-	unsigned int i;
-
-	if (!connector)
-		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_display_restore_atomic(struct drm_client_display *display, bool active)
-{
-	struct drm_device *dev = display->dev;
-	struct drm_plane_state *plane_state;
-	struct drm_mode_set *mode_set;
-	struct drm_plane *plane;
-	struct drm_atomic_state *state;
-	int ret;
-	unsigned int plane_mask;
-	struct drm_modeset_acquire_ctx ctx;
-
-	drm_modeset_acquire_init(&ctx, 0);
-
-	state = drm_atomic_state_alloc(dev);
-	if (!state) {
-		ret = -ENOMEM;
-		goto out_ctx;
-	}
-
-	state->acquire_ctx = &ctx;
-retry:
-	plane_mask = 0;
-	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;
-
-		plane->old_fb = plane->fb;
-		plane_mask |= 1 << drm_plane_index(plane);
-
-		/* disable non-primary: */
-		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
-			continue;
-
-		ret = drm_atomic_disable_plane(plane, plane_state);
-		if (ret != 0)
-			goto out_state;
-	}
-
-	drm_client_display_for_each_modeset(mode_set, display) {
-		struct drm_plane *primary = mode_set->crtc->primary;
-		unsigned int rotation;
-
-		if (drm_fb_helper_panel_rotation(mode_set->connectors[0], primary, &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_set_config(mode_set, state);
-		if (ret != 0)
-			goto out_state;
-
-		/*
-		 * drm_atomic_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:
-	drm_atomic_clean_old_fb(dev, plane_mask, ret);
-
-	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_display_restore_legacy(struct drm_client_display *display)
-{
-	struct drm_device *dev = display->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_display_for_each_modeset(mode_set, display) {
-		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;
-}
-
-static int drm_client_display_restore(struct drm_client_display *display)
-{
-	if (drm_drv_uses_atomic_modeset(display->dev))
-		return drm_client_display_restore_atomic(display, true);
-	else
-		return drm_client_display_restore_legacy(display);
-}
-
 /**
  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
  * @fb_helper: driver-allocated fbdev helper, can be NULL
@@ -579,36 +397,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_display_dpms_legacy(struct drm_client_display *display, int dpms_mode)
-{
-	struct drm_device *dev = display->dev;
-	struct drm_connector *connector;
-	struct drm_mode_set *modeset;
-	int i;
-
-	drm_modeset_lock_all(dev);
-	drm_client_display_for_each_modeset(modeset, display) {
-		if (!modeset->crtc->enabled)
-			continue;
-
-		for (i = 0; i < modeset->num_connectors; i++) {
-			connector = modeset->connectors[i];
-			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);
-}
-
-static void drm_client_display_dpms(struct drm_client_display *display, int mode)
-{
-	if (drm_drv_uses_atomic_modeset(display->dev))
-		drm_client_display_restore_atomic(display, mode == DRM_MODE_DPMS_ON);
-	else
-		drm_client_display_dpms_legacy(display, mode);
-}
-
 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 {
 	struct drm_fb_helper *fb_helper = info->par;
@@ -2487,8 +2275,8 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 
 		modeset->fb = fb_helper->fb;
 
-		if (drm_fb_helper_panel_rotation(modeset->connectors[0],
-						 modeset->crtc->primary, &rotation))
+		if (drm_client_display_panel_rotation(modeset->connectors[0],
+						      modeset->crtc->primary, &rotation))
 			/* Rotating in hardware, fbcon should not rotate */
 			sw_rotations |= DRM_MODE_ROTATE_0;
 		else
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index b6a057802769..ed028f5877d0 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,9 +3,11 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+struct drm_connector;
 struct drm_crtc;
 struct drm_device;
 struct drm_mode_set;
+struct drm_plane;
 
 /**
  * struct drm_client_display - DRM client display
@@ -41,4 +43,10 @@ drm_client_display_find_modeset(struct drm_client_display *display, struct drm_c
 #define drm_client_display_for_each_modeset(modeset, display) \
 	for (modeset = display->modesets; modeset->crtc; modeset++)
 
+bool drm_client_display_panel_rotation(struct drm_connector *connector,
+				       struct drm_plane *plane,
+				       unsigned int *rotation);
+int drm_client_display_restore(struct drm_client_display *display);
+void drm_client_display_dpms(struct drm_client_display *display, int mode);
+
 #endif
-- 
2.15.1

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

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

* [RFC v4 10/25] drm/connector: Add drm_connector_has_preferred_mode/pick_cmdline_mode()
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (8 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 09/25] drm/fb-helper: Move modeset commit code to drm_client Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 11/25] drm/connector: Add connector array functions Noralf Trønnes
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

Move them over from drm_fb_helper since they are connector functions.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_connector.c    | 94 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_fb_helper.c    | 75 ++----------------------------
 drivers/gpu/drm/i915/intel_fbdev.c |  7 +--
 include/drm/drm_connector.h        |  6 +++
 include/drm/drm_fb_helper.h        | 19 --------
 5 files changed, 108 insertions(+), 93 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b3cde897cd80..b9eb143d70fc 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1760,3 +1760,97 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
 	return tg;
 }
 EXPORT_SYMBOL(drm_mode_create_tile_group);
+
+/**
+ * drm_connector_has_preferred_mode() - Lookup preferred display mode
+ * @connector: DRM connector
+ * @width: Max width
+ * @height: Max height
+ *
+ * Look for a preferred display mode within the bounds of @width and @height
+ * (inclusive).
+ *
+ * Returns:
+ * A &drm_display_mode or NULL.
+ */
+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;
+}
+EXPORT_SYMBOL(drm_connector_has_preferred_mode);
+
+/**
+ * drm_connector_pick_cmdline_mode() - Get commandline display mode
+ * @connector: DRM connector
+ *
+ * Return the display mode specified on the kernel commandline or NULL if not
+ * specified.
+ *
+ * Returns:
+ * A &drm_display_mode or NULL.
+ */
+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)
+		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;
+}
+EXPORT_SYMBOL(drm_connector_pick_cmdline_mode);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 785a2f5d2647..b992f59dad30 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1774,78 +1774,11 @@ static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
 	return count;
 }
 
-struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
-{
-	struct drm_display_mode *mode;
-
-	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
-		if (mode->hdisplay > width ||
-		    mode->vdisplay > height)
-			continue;
-		if (mode->type & DRM_MODE_TYPE_PREFERRED)
-			return mode;
-	}
-	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)
-{
-	struct drm_cmdline_mode *cmdline_mode;
-	struct drm_display_mode *mode;
-	bool prefer_non_interlace;
-
-	cmdline_mode = &fb_helper_conn->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, &fb_helper_conn->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(fb_helper_conn->connector->dev,
-						 cmdline_mode);
-	list_add(&mode->head, &fb_helper_conn->connector->modes);
-	return mode;
-}
-EXPORT_SYMBOL(drm_pick_cmdline_mode);
-
 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 {
 	bool enable;
@@ -1916,7 +1849,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 		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(fb_helper_conn->connector);
 		if (!modes[i]) {
 			can_clone = false;
 			break;
@@ -2040,11 +1973,11 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 			      fb_helper_conn->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(fb_helper_conn->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);
+			modes[i] = drm_connector_has_preferred_mode(fb_helper_conn->connector, width, height);
 		}
 		/* No preferred modes, pick one off the list */
 		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
@@ -2097,7 +2030,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 		my_score++;
 	if (drm_has_cmdline_mode(fb_helper_conn))
 		my_score++;
-	if (drm_has_preferred_mode(fb_helper_conn, width, height))
+	if (drm_connector_has_preferred_mode(connector, width, height))
 		my_score++;
 
 	connector_funcs = connector->helper_private;
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 89592ecc44ca..a4ab8575a72e 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -421,14 +421,15 @@ static bool intel_fb_initial_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? */
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 675cc3f8cf85..9cb4ca42373c 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1163,4 +1163,10 @@ void drm_connector_list_iter_end(struct drm_connector_list_iter *iter);
 #define drm_for_each_connector_iter(connector, iter) \
 	while ((connector = drm_connector_list_iter_next(iter)))
 
+struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector,
+				 int width, int height);
+struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector);
+
 #endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index e2df40ad5063..f379ef6d6085 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -311,11 +311,6 @@ 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,
@@ -510,20 +505,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)
-- 
2.15.1

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

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

* [RFC v4 11/25] drm/connector: Add connector array functions
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (9 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 10/25] drm/connector: Add drm_connector_has_preferred_mode/pick_cmdline_mode() Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:33   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

Add functions to deal with the registred connectors as an array:
- drm_connector_get_all()
- drm_connector_put_all()

And to get the enabled status of those connectors:
drm_connector_get_enabled_status()

This is prep work to remove struct drm_fb_helper_connector.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_connector.c | 105 ++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h     |   5 ++
 2 files changed, 110 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b9eb143d70fc..25c333c05a4e 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1854,3 +1854,108 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector)
 	return mode;
 }
 EXPORT_SYMBOL(drm_connector_pick_cmdline_mode);
+
+/**
+ * drm_connector_get_all - Get all connectors into an array
+ * @dev: DRM device
+ * @connectors: Returned connector array
+ *
+ * This function iterates through all registered connectors and adds them to an
+ * array allocated by this function. A ref is taken on the connectors.
+ *
+ * Use drm_connector_put_all() to drop refs and free the array.
+ *
+ * Returns:
+ * Number of connectors or -ENOMEM on failure.
+ */
+int drm_connector_get_all(struct drm_device *dev, struct drm_connector ***connectors)
+{
+	struct drm_connector *connector, **temp, **conns = NULL;
+	struct drm_connector_list_iter conn_iter;
+	int connector_count = 0;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		temp = krealloc(conns, (connector_count + 1) * sizeof(*conns), GFP_KERNEL);
+		if (!temp)
+			goto err_put_free;
+
+		conns = temp;
+		conns[connector_count++] = connector;
+		drm_connector_get(connector);
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	*connectors = conns;
+
+	return connector_count;
+
+err_put_free:
+	drm_connector_list_iter_end(&conn_iter);
+	drm_connector_put_all(conns, connector_count);
+
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_connector_get_all);
+
+/**
+ * drm_connector_put_all - Put and free connector array
+ * @connectors: Array of connectors
+ * @connector_count: Number of connectors in the array (can be negative or zero)
+ *
+ * This function drops the ref on the connectors an frees the array.
+ */
+void drm_connector_put_all(struct drm_connector **connectors, int connector_count)
+{
+	int i;
+
+	if (connector_count < 1)
+		return;
+
+	for (i = 0; i < connector_count; i++)
+		drm_connector_put(connectors[i]);
+	kfree(connectors);
+}
+EXPORT_SYMBOL(drm_connector_put_all);
+
+/**
+ * drm_connector_get_enabled_status - Get enabled status on connectors
+ * @connectors: Array of connectors
+ * @connector_count: Number of connectors in the array
+ *
+ * This loops over the connector array and sets enabled if connector status is
+ * _connected_. If no connectors are connected, a new pass is done and
+ * connectors that are not _disconnected_ are set enabled.
+ *
+ * The caller is responsible for freeing the array using kfree().
+ *
+ * Returns:
+ * A boolean array of connector enabled statuses or NULL on allocation failure.
+ */
+bool *drm_connector_get_enabled_status(struct drm_connector **connectors,
+				       unsigned int connector_count)
+{
+	bool *enabled, any_enabled = false;
+	unsigned int i;
+
+	enabled = kcalloc(connector_count, sizeof(*enabled), GFP_KERNEL);
+	if (!enabled)
+		return NULL;
+
+	for (i = 0; i < connector_count; i++) {
+		if (connectors[i]->status == connector_status_connected) {
+			enabled[i] = true;
+			any_enabled = true;
+		}
+	}
+
+	if (any_enabled)
+		return enabled;
+
+	for (i = 0; i < connector_count; i++)
+		if (connectors[i]->status != connector_status_disconnected)
+			enabled[i] = true;
+
+	return enabled;
+}
+EXPORT_SYMBOL(drm_connector_get_enabled_status);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 9cb4ca42373c..c3556a5f40c9 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1169,4 +1169,9 @@ drm_connector_has_preferred_mode(struct drm_connector *connector,
 struct drm_display_mode *
 drm_connector_pick_cmdline_mode(struct drm_connector *connector);
 
+int drm_connector_get_all(struct drm_device *dev, struct drm_connector ***connectors);
+void drm_connector_put_all(struct drm_connector **connectors, int connector_count);
+bool *drm_connector_get_enabled_status(struct drm_connector **connectors,
+				       unsigned int connector_count);
+
 #endif
-- 
2.15.1

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

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

* [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (10 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 11/25] drm/connector: Add connector array functions Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:38   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 13/25] drm/fb-helper: Remove struct drm_fb_helper_crtc Noralf Trønnes
                   ` (13 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

As part of moving the modesetting code out of drm_fb_helper and into
drm_client, the drm_fb_helper_funcs->initial_config callback needs to go.
Replace it with a drm_driver->initial_client_display callback that can
work for all in-kernel clients.

TODO:
- Add a patch that moves the function out of intel_fbdev.c since it's not
  fbdev specific anymore.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c    |  19 +++++--
 drivers/gpu/drm/i915/i915_drv.c    |   1 +
 drivers/gpu/drm/i915/intel_drv.h   |  11 ++++
 drivers/gpu/drm/i915/intel_fbdev.c | 113 ++++++++++++++++++-------------------
 include/drm/drm_drv.h              |  21 +++++++
 5 files changed, 104 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b992f59dad30..5407bf6dc8c0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -2103,6 +2103,20 @@ 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);
 
+	mutex_lock(&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");
+
+	if (dev->driver->initial_client_display) {
+		display = dev->driver->initial_client_display(dev, width, height);
+		if (display) {
+			drm_client_display_free(fb_helper->display);
+			fb_helper->display = display;
+			mutex_unlock(&dev->mode_config.mutex);
+			return;
+		}
+	}
+
 	crtcs = kcalloc(fb_helper->connector_count,
 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
 	modes = kcalloc(fb_helper->connector_count,
@@ -2120,9 +2134,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	if (IS_ERR(display))
 		goto out;
 
-	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");
 	drm_enable_connectors(fb_helper, enabled);
 
 	if (!(fb_helper->funcs->initial_config &&
@@ -2144,7 +2155,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 
 		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
 	}
-	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 */
@@ -2182,6 +2192,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	drm_client_display_free(fb_helper->display);
 	fb_helper->display = display;
 out:
+	mutex_unlock(&dev->mode_config.mutex);
 	kfree(crtcs);
 	kfree(modes);
 	kfree(offsets);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 07c07d55398b..b746c0cbaa4b 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -2857,6 +2857,7 @@ static struct drm_driver driver = {
 
 	.dumb_create = i915_gem_dumb_create,
 	.dumb_map_offset = i915_gem_mmap_gtt,
+	.initial_client_display = i915_initial_client_display,
 	.ioctls = i915_ioctls,
 	.num_ioctls = ARRAY_SIZE(i915_ioctls),
 	.fops = &i915_driver_fops,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d4368589b355..f77f510617c5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1720,6 +1720,9 @@ extern void intel_fbdev_fini(struct drm_i915_private *dev_priv);
 extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
 extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
 extern void intel_fbdev_restore_mode(struct drm_device *dev);
+struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+			    unsigned int height);
 #else
 static inline int intel_fbdev_init(struct drm_device *dev)
 {
@@ -1749,6 +1752,14 @@ static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
 static inline void intel_fbdev_restore_mode(struct drm_device *dev)
 {
 }
+
+static inline struct drm_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+			    unsigned int height)
+{
+	return NULL;
+}
+
 #endif
 
 /* intel_fbc.c */
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index a4ab8575a72e..b7f44c9475a8 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -38,6 +38,7 @@
 #include <linux/vga_switcheroo.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fb_helper.h>
 #include "intel_drv.h"
@@ -287,18 +288,6 @@ 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.
@@ -326,44 +315,48 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
  * 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_client_display *
+i915_initial_client_display(struct drm_device *dev, unsigned int width,
+			    unsigned int height)
 {
-	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
+	struct drm_i915_private *dev_priv = to_i915(dev);
 	unsigned long conn_configured, conn_seq, mask;
-	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
-	int i, j;
-	bool *save_enabled;
-	bool fallback = true, ret = true;
+	bool fallback = true, *enabled = NULL;
+	struct drm_client_display *display;
+	struct drm_connector **connectors;
+	int i, connector_count;
+	unsigned int count;
 	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;
+	display = drm_client_display_create(dev);
+	if (IS_ERR(display))
+		return NULL;
 
 	drm_modeset_acquire_init(&ctx, 0);
 
-	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
+	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
 		drm_modeset_backoff(&ctx);
 
-	memcpy(save_enabled, enabled, count);
+	connector_count = drm_connector_get_all(dev, &connectors);
+	if (connector_count < 1)
+		goto bail;
+
+	enabled = drm_connector_get_enabled_status(connectors, connector_count);
+	if (!enabled)
+		goto bail;
+
+	count = min(connector_count, BITS_PER_LONG);
 	mask = GENMASK(count - 1, 0);
 	conn_configured = 0;
 retry:
 	conn_seq = conn_configured;
 	for (i = 0; i < count; i++) {
-		struct drm_fb_helper_connector *fb_conn;
-		struct drm_connector *connector;
+		struct drm_connector *connector = connectors[i];
+		struct drm_display_mode *mode;
+		struct drm_mode_set *modeset;
 		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;
@@ -402,16 +395,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 
 		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_client_display_for_each_modeset(modeset, display) {
+			if (modeset->connectors[0] == connector) {
 				DRM_DEBUG_KMS("fallback: cloned configuration\n");
 				goto bail;
 			}
@@ -421,28 +411,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 			      connector->name);
 
 		/* go for command line mode first */
-		modes[i] = drm_connector_pick_cmdline_mode(connector);
+		mode = drm_connector_pick_cmdline_mode(connector);
 
 		/* try for preferred next */
-		if (!modes[i]) {
+		if (!mode) {
 			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);
+			mode = 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)) {
+		if (!mode && !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);
+			mode = list_first_entry(&connector->modes,
+						struct drm_display_mode, head);
 		}
 
 		/* last resort: use current mode */
-		if (!modes[i]) {
+		if (!mode) {
 			/*
 			 * IMPORTANT: We want to use the adjusted mode (i.e.
 			 * after the panel fitter upscaling) as the initial
@@ -458,16 +446,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 			 */
 			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
 				      connector->name);
-			modes[i] = &connector->state->crtc->mode;
+			mode = &connector->state->crtc->mode;
 		}
-		crtcs[i] = new_crtc;
+
+		modeset = drm_client_display_find_modeset(display, connector->state->crtc);
+		if (WARN_ON(!modeset))
+			goto bail;
+
+		modeset->mode = drm_mode_duplicate(dev, mode);
+		drm_connector_get(connector);
+		modeset->connectors[0] = connector;
+		modeset->num_connectors = 1;
+		modeset->x = 0;
+		modeset->y = 0;
 
 		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" :"");
+			      mode->hdisplay, mode->vdisplay,
+			      mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
 
 		fallback = false;
 		conn_configured |= BIT(i);
@@ -492,19 +490,20 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 	if (fallback) {
 bail:
 		DRM_DEBUG_KMS("Not using firmware configuration\n");
-		memcpy(enabled, save_enabled, count);
-		ret = false;
+		drm_client_display_free(display);
+		display = NULL;
 	}
 
 	drm_modeset_drop_locks(&ctx);
 	drm_modeset_acquire_fini(&ctx);
 
-	kfree(save_enabled);
-	return ret;
+	drm_connector_put_all(connectors, connector_count);
+	kfree(enabled);
+
+	return display;
 }
 
 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_drv.h b/include/drm/drm_drv.h
index 7e545f5f94d3..13356e6fd40c 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -32,6 +32,7 @@
 
 #include <drm/drm_device.h>
 
+struct drm_client_display;
 struct drm_file;
 struct drm_gem_object;
 struct drm_master;
@@ -553,6 +554,26 @@ struct drm_driver {
 			    struct drm_device *dev,
 			    uint32_t handle);
 
+	/**
+	 * @initial_client_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.
+	 */
+	struct drm_client_display *(*initial_client_display)(struct drm_device *dev,
+					unsigned int width, unsigned int height);
+
 	/**
 	 * @gem_vm_ops: Driver private ops for this object
 	 */
-- 
2.15.1

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

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

* [RFC v4 13/25] drm/fb-helper: Remove struct drm_fb_helper_crtc
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (11 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 14/25] drm/fb-helper: Remove struct drm_fb_helper_connector Noralf Trønnes
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

The stage is now set for a clean removal of drm_fb_helper_crtc.
struct drm_client_display is doing its job now.

Also remove the drm_fb_helper_funcs->initial_config which has been
superseded by drm_driver->initial_client_display.

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

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 5407bf6dc8c0..ce38eadcb346 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -443,24 +443,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;
@@ -470,14 +452,6 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
 		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)
@@ -552,48 +526,18 @@ 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;
-
 	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);
+	if (!fb_helper->connector_info)
 		return -ENOMEM;
-	}
+
 	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++;
-	}
-
 	fb_helper->display = drm_client_display_create(dev);
 	if (IS_ERR(fb_helper->display))
 		goto out_free;
@@ -1830,7 +1774,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;
@@ -1997,16 +1941,18 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 }
 
 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_display *display = fb_helper->display;
+	struct drm_device *dev = display->dev;
+	int o, my_score, best_score, score;
 	struct drm_connector *connector;
 	const struct drm_connector_helper_funcs *connector_funcs;
+	struct drm_mode_set *modeset;
 	struct drm_encoder *encoder;
-	int my_score, best_score, score;
-	struct drm_fb_helper_crtc **crtcs, *crtc;
+	struct drm_crtc **crtcs;
 	struct drm_fb_helper_connector *fb_helper_conn;
 
 	if (n == fb_helper->connector_count)
@@ -2020,8 +1966,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;
 
@@ -2053,10 +1998,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_display_for_each_modeset(modeset, display) {
+		struct drm_crtc *crtc = modeset->crtc;
 
-		if ((encoder->possible_crtcs & (1 << c)) == 0)
+		if ((encoder->possible_crtcs & drm_crtc_mask(crtc)) == 0)
 			continue;
 
 		for (o = 0; o < n; o++)
@@ -2065,7 +2010,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 (dev->mode_config.num_crtc > 1)
 				continue;
 
 			if (!drm_mode_equal(modes[o], modes[n]))
@@ -2073,14 +2018,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));
 		}
 	}
 out:
@@ -2093,9 +2037,9 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 {
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_client_display *display;
-	struct drm_fb_helper_crtc **crtcs;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
+	struct drm_crtc **crtcs;
 	bool *enabled;
 	int i;
 
@@ -2117,8 +2061,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		}
 	}
 
-	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,
@@ -2136,43 +2079,28 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 
 	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))) {
-		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_target_cloned(fb_helper, modes, offsets, enabled, width, height) &&
+	    !drm_target_preferred(fb_helper, modes, offsets, enabled, width, height))
+		DRM_ERROR("Unable to find initial modes\n");
 
-		if (!drm_target_cloned(fb_helper, modes, offsets,
-				       enabled, width, height) &&
-		    !drm_target_preferred(fb_helper, 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_DEBUG_KMS("picking CRTCs for %dx%d config\n",
-			      width, height);
-
-		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
-	}
+	drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
 
 	/* 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_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) {
+		if (mode && crtc) {
 			struct drm_connector *connector =
 				fb_helper->connector_info[i]->connector;
 			struct drm_mode_set *modeset;
 
-			modeset = drm_client_display_find_modeset(display, fb_crtc->mode_set.crtc);
+			modeset = drm_client_display_find_modeset(display, crtc);
 			if (WARN_ON(!modeset)) {
 				drm_client_display_free(display);
 				goto out;
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index f379ef6d6085..408931f7613f 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -45,12 +45,6 @@ struct drm_fb_offset {
 	int x, y;
 };
 
-struct drm_fb_helper_crtc {
-	struct drm_mode_set mode_set;
-	struct drm_display_mode *desired_mode;
-	int x, y;
-};
-
 /**
  * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size
  * @fb_width: fbdev width
@@ -101,29 +95,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 {
@@ -163,8 +134,6 @@ struct drm_fb_helper {
 	 */
 	struct drm_client_display *display;
 
-	int crtc_count;
-	struct drm_fb_helper_crtc *crtc_info;
 	int connector_count;
 	int connector_info_alloc_count;
 	/**
-- 
2.15.1

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

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

* [RFC v4 14/25] drm/fb-helper: Remove struct drm_fb_helper_connector
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (12 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 13/25] drm/fb-helper: Remove struct drm_fb_helper_crtc Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client Noralf Trønnes
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

No need to maintain a list of registered connectors. Just use the
connector iterator.

TODO: Remove:
- drm_fb_helper_add_one_connector()
- drm_fb_helper_single_add_all_connectors()
- drm_fb_helper_remove_one_connector()

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

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index ce38eadcb346..6ee61f195321 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -112,59 +112,10 @@ 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;
+	return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
 
@@ -184,87 +135,14 @@ EXPORT_SYMBOL(drm_fb_helper_add_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) {
-		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;
 }
+EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
 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;
+	return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
 
@@ -443,17 +321,6 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_blank);
 
-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);
-}
-
 static void drm_fb_helper_resume_worker(struct work_struct *work)
 {
 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
@@ -531,23 +398,13 @@ int drm_fb_helper_init(struct drm_device *dev,
 		return 0;
 	}
 
-	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-	if (!fb_helper->connector_info)
-		return -ENOMEM;
-
-	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
-	fb_helper->connector_count = 0;
-
 	fb_helper->display = drm_client_display_create(dev);
 	if (IS_ERR(fb_helper->display))
-		goto out_free;
+		return PTR_ERR(fb_helper->display);
 
 	dev->fb_helper = fb_helper;
 
 	return 0;
-out_free:
-	drm_fb_helper_crtc_free(fb_helper);
-	return -ENOMEM;
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
 
@@ -651,8 +508,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 
 	mutex_destroy(&fb_helper->lock);
 	drm_client_display_free(fb_helper->display);
-	drm_fb_helper_crtc_free(fb_helper);
-
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
@@ -1474,8 +1329,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 {
 	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 gamma_size = 0;
 
@@ -1490,11 +1346,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
 
 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
-		struct drm_cmdline_mode *cmdline_mode;
-
-		cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
 
 		if (cmdline_mode->bpp_specified) {
 			switch (cmdline_mode->bpp) {
@@ -1519,6 +1373,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 			break;
 		}
 	}
+	drm_connector_list_iter_end(&conn_iter);
 
 	crtc_count = 0;
 	drm_client_display_for_each_modeset(mode_set, fb_helper->display) {
@@ -1707,70 +1562,28 @@ static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
 						uint32_t maxX,
 						uint32_t maxY)
 {
+	struct drm_connector_list_iter conn_iter;
 	struct drm_connector *connector;
-	int i, count = 0;
+	int count = 0;
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
+	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
 		count += connector->funcs->fill_modes(connector, maxX, maxY);
 	}
+	drm_connector_list_iter_end(&conn_iter);
 
 	return count;
 }
 
-static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
-{
-	return fb_connector->connector->cmdline_mode.specified;
-}
-
-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_enable_connectors(struct drm_fb_helper *fb_helper,
-				  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;
-		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;
-
-	drm_fb_helper_for_each_connector(fb_helper, i) {
-		connector = fb_helper->connector_info[i]->connector;
-		enabled[i] = drm_connector_enabled(connector, false);
-	}
-}
-
 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
+			      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 */
@@ -1778,7 +1591,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 		return false;
 
 	count = 0;
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
 		if (enabled[i])
 			count++;
 	}
@@ -1789,11 +1602,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_connector_pick_cmdline_mode(fb_helper_conn->connector);
+		modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
 		if (!modes[i]) {
 			can_clone = false;
 			break;
@@ -1815,12 +1627,11 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 	can_clone = true;
 	dmt_mode = drm_mode_find_dmt(fb_helper->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_equal(mode, dmt_mode))
 				modes[i] = mode;
 		}
@@ -1836,30 +1647,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,
+static int drm_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;
 	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++) {
+		struct drm_connector *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;
@@ -1868,20 +1680,20 @@ 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,
+static bool drm_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;
 	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++) {
+		struct drm_connector *connector = connectors[i];
 
 		if (conn_configured & BIT_ULL(i))
 			continue;
@@ -1892,17 +1704,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;
 
@@ -1910,24 +1722,23 @@ 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_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_connector_pick_cmdline_mode(fb_helper_conn->connector);
+		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_connector_has_preferred_mode(fb_helper_conn->connector, 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)
-				break;
-		}
+		if (!modes[i])
+			modes[i] = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head);
+
 		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
 			  "none");
 		conn_configured |= BIT_ULL(i);
@@ -1940,12 +1751,13 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 	return true;
 }
 
-static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
+static int drm_pick_crtcs(struct drm_client_display *display,
+			  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_display *display = fb_helper->display;
 	struct drm_device *dev = display->dev;
 	int o, my_score, best_score, score;
 	struct drm_connector *connector;
@@ -1953,27 +1765,26 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	struct drm_mode_set *modeset;
 	struct drm_encoder *encoder;
 	struct drm_crtc **crtcs;
-	struct drm_fb_helper_connector *fb_helper_conn;
 
-	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_pick_crtcs(display, 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_connector_has_preferred_mode(connector, width, height))
 		my_score++;
@@ -1985,7 +1796,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
 	 * NULL we fallback to the default drm_atomic_helper_best_encoder()
 	 * helper.
 	 */
-	if (drm_drv_uses_atomic_modeset(fb_helper->dev) &&
+	if (drm_drv_uses_atomic_modeset(dev) &&
 	    !connector_funcs->best_encoder)
 		encoder = drm_atomic_helper_best_encoder(connector);
 	else
@@ -2019,12 +1830,12 @@ 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_pick_crtcs(display, 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));
+			       connector_count * sizeof(*crtcs));
 		}
 	}
 out:
@@ -2037,11 +1848,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 {
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_client_display *display;
+	struct drm_connector **connectors;
 	struct drm_display_mode **modes;
 	struct drm_fb_offset *offsets;
 	struct drm_crtc **crtcs;
+	int i, connector_count;
 	bool *enabled;
-	int i;
 
 	DRM_DEBUG_KMS("\n");
 	/* prevent concurrent modification of connector_count by hotplug */
@@ -2061,13 +1873,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 		}
 	}
 
-	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);
+	connector_count = drm_connector_get_all(dev, &connectors);
+	if (connector_count < 1)
+		return;
+
+	enabled = drm_connector_get_enabled_status(connectors, connector_count);
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
 	if (!crtcs || !modes || !enabled || !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
 		goto out;
@@ -2077,27 +1890,26 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	if (IS_ERR(display))
 		goto out;
 
-	drm_enable_connectors(fb_helper, enabled);
-
-	if (!drm_target_cloned(fb_helper, modes, offsets, enabled, width, height) &&
-	    !drm_target_preferred(fb_helper, modes, offsets, enabled, width, height))
+	if (!drm_target_cloned(fb_helper, connectors, connector_count,
+			       modes, offsets, enabled, width, height) &&
+	    !drm_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_pick_crtcs(display, connectors, connector_count, crtcs, modes, 0, width, height);
 
 	/* need to set the modesets up here for use later */
 	/* fill out the connector<->crtc mappings into the modesets */
 
-	drm_fb_helper_for_each_connector(fb_helper, i) {
+	for (i = 0; i < connector_count; i++) {
+		struct drm_connector *connector = connectors[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_connector *connector =
-				fb_helper->connector_info[i]->connector;
 			struct drm_mode_set *modeset;
 
 			modeset = drm_client_display_find_modeset(display, crtc);
@@ -2121,6 +1933,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 	fb_helper->display = display;
 out:
 	mutex_unlock(&dev->mode_config.mutex);
+	drm_connector_put_all(connectors, connector_count);
 	kfree(crtcs);
 	kfree(modes);
 	kfree(offsets);
@@ -2136,10 +1949,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_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;
 
 	drm_client_display_for_each_modeset(modeset, fb_helper->display) {
 		if (!modeset->num_connectors)
@@ -2156,10 +1970,8 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 	}
 
 	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_for_each_connector_iter(connector, &conn_iter) {
 		/* use first connected connector for the physical dimensions */
 		if (connector->status == connector_status_connected) {
 			info->var.width = connector->display_info.width_mm;
@@ -2167,6 +1979,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 			break;
 		}
 	}
+	drm_connector_list_iter_end(&conn_iter);
 	mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
 	switch (sw_rotations) {
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 408931f7613f..a1e1ab1247c5 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -97,10 +97,6 @@ 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
@@ -134,15 +130,6 @@ struct drm_fb_helper {
 	 */
 	struct drm_client_display *display;
 
-	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];
-- 
2.15.1

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

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

* [RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (13 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 14/25] drm/fb-helper: Remove struct drm_fb_helper_connector Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 16/25] drm: Make ioctls available for in-kernel clients Noralf Trønnes
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

Call the function drm_client_find_display().
No functional change apart from making width/height arguments optional.
Some function name/signature changes and whitespace adjustments.

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

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index c85c13568cf9..27818a467b09 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -18,6 +18,10 @@
 #include <drm/drm_device.h>
 #include <drm/drm_modes.h>
 
+struct drm_client_display_offset {
+	int x, y;
+};
+
 /**
  * drm_client_display_create() - Create display structure
  * @dev: DRM device
@@ -359,3 +363,398 @@ void drm_client_display_dpms(struct drm_client_display *display, int mode)
 		drm_client_display_dpms_legacy(display, mode);
 }
 EXPORT_SYMBOL(drm_client_display_dpms);
+
+static int drm_client_probe_connector_modes(struct drm_device *dev,
+					    u32 max_width, u32 max_height)
+{
+	struct drm_connector_list_iter conn_iter;
+	struct drm_connector *connector;
+	int count = 0;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		count += connector->funcs->fill_modes(connector, max_width, max_height);
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	return count;
+}
+
+static bool drm_target_cloned(struct drm_device *dev,
+			      struct drm_connector **connectors,
+			      unsigned int connector_count,
+			      struct drm_display_mode **modes,
+			      struct drm_client_display_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_equal(modes[j], modes[i]))
+				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_equal(mode, dmt_mode))
+				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 void drm_get_tile_offsets(struct drm_connector **connectors,
+				 unsigned int connector_count,
+				 struct drm_display_mode **modes,
+				 struct drm_client_display_offset *offsets,
+				 int idx,
+				 int h_idx, int v_idx)
+{
+	int i;
+	int hoffset = 0, voffset = 0;
+
+	for (i = 0; i < connector_count; i++) {
+		struct drm_connector *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);
+}
+
+static bool drm_target_preferred(struct drm_connector **connectors,
+				 unsigned int connector_count,
+				 struct drm_display_mode **modes,
+				 struct drm_client_display_offset *offsets,
+				 bool *enabled, int width, int height)
+{
+	const u64 mask = BIT_ULL(connector_count) - 1;
+	u64 conn_configured = 0;
+	int tile_pass = 0;
+	int i;
+
+retry:
+	for (i = 0; i < connector_count; i++) {
+		struct drm_connector *connector = connectors[i];
+
+		if (conn_configured & BIT_ULL(i))
+			continue;
+
+		if (!enabled[i]) {
+			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_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])
+			modes[i] = list_first_entry_or_null(&connector->modes,
+							    struct drm_display_mode, head);
+
+		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 int drm_pick_crtcs(struct drm_client_display *display,
+			  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 = display->dev;
+	int o, my_score, best_score, score;
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	struct drm_encoder *encoder;
+	struct drm_crtc **crtcs;
+
+	if (n == connector_count)
+		return 0;
+
+	connector = connectors[n];
+
+	best_crtcs[n] = NULL;
+	best_score = drm_pick_crtcs(display, connectors, connector_count,
+				    best_crtcs, modes, n + 1, width, height);
+	if (!modes[n])
+		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++;
+
+	/*
+	 * If the DRM device implements atomic hooks and ->best_encoder() is
+	 * NULL we fallback to the default drm_atomic_helper_best_encoder()
+	 * helper.
+	 */
+	if (drm_drv_uses_atomic_modeset(dev) &&
+	    !connector->helper_private->best_encoder)
+		encoder = drm_atomic_helper_best_encoder(connector);
+	else
+		encoder = connector->helper_private->best_encoder(connector);
+
+	if (!encoder)
+		goto out;
+
+	/*
+	 * select a crtc for this connector and then attempt to configure
+	 * remaining connectors
+	 */
+	drm_client_display_for_each_modeset(modeset, display) {
+		struct drm_crtc *crtc = modeset->crtc;
+
+		if ((encoder->possible_crtcs & drm_crtc_mask(crtc)) == 0)
+			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_pick_crtcs(display, connectors, connector_count,
+						  crtcs, modes, n + 1, width, height);
+		if (score > best_score) {
+			best_score = score;
+			memcpy(best_crtcs, crtcs,
+			       connector_count * sizeof(*crtcs));
+		}
+	}
+out:
+	kfree(crtcs);
+
+	return best_score;
+}
+
+/**
+ * drm_client_find_display() - Find display
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function returns a display the client can use if available.
+ *
+ * Free resources by calling drm_client_display_free().
+ *
+ * Returns:
+ * A &drm_client_display on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_client_display *
+drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+{
+	struct drm_client_display_offset *offsets;
+	struct drm_client_display *display;
+	struct drm_connector **connectors;
+	struct drm_display_mode **modes;
+	struct drm_crtc **crtcs;
+	int i, connector_count;
+	bool *enabled;
+
+	DRM_DEBUG_KMS("\n");
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
+	mutex_lock(&dev->mode_config.mutex);
+	if (!drm_client_probe_connector_modes(dev, width, height))
+		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+
+	if (dev->driver->initial_client_display) {
+		display = dev->driver->initial_client_display(dev, width, height);
+		if (display) {
+			mutex_unlock(&dev->mode_config.mutex);
+			return display;
+		}
+	}
+
+	connector_count = drm_connector_get_all(dev, &connectors);
+	if (connector_count < 1)
+		return NULL;
+
+	enabled = drm_connector_get_enabled_status(connectors, connector_count);
+	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
+	if (!crtcs || !modes || !enabled || !offsets) {
+		DRM_ERROR("Memory allocation failed\n");
+		display = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	display = drm_client_display_create(dev);
+	if (IS_ERR(display))
+		goto out;
+
+	if (!drm_target_cloned(dev, connectors, connector_count,
+			       modes, offsets, enabled, width, height) &&
+	    !drm_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(display, connectors, connector_count, crtcs, modes, 0, width, height);
+
+	/* need to set the modesets up here for use later */
+	/* fill out the connector<->crtc mappings into the modesets */
+
+	for (i = 0; i < connector_count; i++) {
+		struct drm_client_display_offset *offset = &offsets[i];
+		struct drm_connector *connector = connectors[i];
+		struct drm_display_mode *mode = modes[i];
+		struct drm_crtc *crtc = crtcs[i];
+
+		if (mode && crtc) {
+			struct drm_mode_set *modeset;
+
+			modeset = drm_client_display_find_modeset(display, crtc);
+			if (WARN_ON(!modeset)) {
+				drm_client_display_free(display);
+				display = ERR_PTR(-EINVAL);
+				goto out;
+			}
+
+			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
+				      mode->name, modeset->crtc->base.id, offset->x, offset->y);
+
+			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;
+		}
+	}
+out:
+	mutex_unlock(&dev->mode_config.mutex);
+	drm_connector_put_all(connectors, connector_count);
+	kfree(crtcs);
+	kfree(modes);
+	kfree(offsets);
+	kfree(enabled);
+
+	return display;
+}
+EXPORT_SYMBOL(drm_client_find_display);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 6ee61f195321..01d8840930a3 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1558,386 +1558,19 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
 }
 EXPORT_SYMBOL(drm_fb_helper_fill_var);
 
-static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
-						uint32_t maxX,
-						uint32_t maxY)
-{
-	struct drm_connector_list_iter conn_iter;
-	struct drm_connector *connector;
-	int count = 0;
-
-	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
-	drm_for_each_connector_iter(connector, &conn_iter) {
-		count += connector->funcs->fill_modes(connector, maxX, maxY);
-	}
-	drm_connector_list_iter_end(&conn_iter);
-
-	return count;
-}
-
-static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
-			      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_display_mode *dmt_mode, *mode;
-
-	/* only contemplate cloning in the single crtc case */
-	if (fb_helper->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_equal(modes[j], modes[i]))
-				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(fb_helper->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_equal(mode, dmt_mode))
-				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_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)
-{
-	int i;
-	int hoffset = 0, voffset = 0;
-
-	for (i = 0; i < connector_count; i++) {
-		struct drm_connector *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_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)
-{
-	const u64 mask = BIT_ULL(connector_count) - 1;
-	u64 conn_configured = 0;
-	int tile_pass = 0;
-	int i;
-
-retry:
-	for (i = 0; i < connector_count; i++) {
-		struct drm_connector *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_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])
-			modes[i] = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head);
-
-		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 int drm_pick_crtcs(struct drm_client_display *display,
-			  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 = display->dev;
-	int o, my_score, best_score, score;
-	struct drm_connector *connector;
-	const struct drm_connector_helper_funcs *connector_funcs;
-	struct drm_mode_set *modeset;
-	struct drm_encoder *encoder;
-	struct drm_crtc **crtcs;
-
-	if (n == connector_count)
-		return 0;
-
-	connector = connectors[n];
-
-	best_crtcs[n] = NULL;
-	best_score = drm_pick_crtcs(display, 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++;
-
-	connector_funcs = connector->helper_private;
-
-	/*
-	 * If the DRM device implements atomic hooks and ->best_encoder() is
-	 * NULL we fallback to the default drm_atomic_helper_best_encoder()
-	 * helper.
-	 */
-	if (drm_drv_uses_atomic_modeset(dev) &&
-	    !connector_funcs->best_encoder)
-		encoder = drm_atomic_helper_best_encoder(connector);
-	else
-		encoder = connector_funcs->best_encoder(connector);
-
-	if (!encoder)
-		goto out;
-
-	/*
-	 * select a crtc for this connector and then attempt to configure
-	 * remaining connectors
-	 */
-	drm_client_display_for_each_modeset(modeset, display) {
-		struct drm_crtc *crtc = modeset->crtc;
-
-		if ((encoder->possible_crtcs & drm_crtc_mask(crtc)) == 0)
-			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_pick_crtcs(display, connectors, connector_count,
-						  crtcs, modes, n + 1, width, height);
-		if (score > best_score) {
-			best_score = score;
-			memcpy(best_crtcs, crtcs,
-			       connector_count * sizeof(*crtcs));
-		}
-	}
-out:
-	kfree(crtcs);
-	return best_score;
-}
-
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
 			    u32 width, u32 height)
 {
-	struct drm_device *dev = fb_helper->dev;
 	struct drm_client_display *display;
-	struct drm_connector **connectors;
-	struct drm_display_mode **modes;
-	struct drm_fb_offset *offsets;
-	struct drm_crtc **crtcs;
-	int i, connector_count;
-	bool *enabled;
 
-	DRM_DEBUG_KMS("\n");
-	/* prevent concurrent modification of connector_count by hotplug */
 	lockdep_assert_held(&fb_helper->lock);
 
-	mutex_lock(&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");
-
-	if (dev->driver->initial_client_display) {
-		display = dev->driver->initial_client_display(dev, width, height);
-		if (display) {
-			drm_client_display_free(fb_helper->display);
-			fb_helper->display = display;
-			mutex_unlock(&dev->mode_config.mutex);
-			return;
-		}
-	}
-
-	connector_count = drm_connector_get_all(dev, &connectors);
-	if (connector_count < 1)
+	display = drm_client_find_display(fb_helper->dev, width, height);
+	if (IS_ERR_OR_NULL(display))
 		return;
 
-	enabled = drm_connector_get_enabled_status(connectors, connector_count);
-	crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
-	modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
-	offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
-	if (!crtcs || !modes || !enabled || !offsets) {
-		DRM_ERROR("Memory allocation failed\n");
-		goto out;
-	}
-
-	display = drm_client_display_create(dev);
-	if (IS_ERR(display))
-		goto out;
-
-	if (!drm_target_cloned(fb_helper, connectors, connector_count,
-			       modes, offsets, enabled, width, height) &&
-	    !drm_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(display, connectors, connector_count, crtcs, modes, 0, width, height);
-
-	/* need to set the modesets up here for use later */
-	/* fill out the connector<->crtc mappings into the modesets */
-
-	for (i = 0; i < connector_count; i++) {
-		struct drm_connector *connector = connectors[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;
-
-			modeset = drm_client_display_find_modeset(display, crtc);
-			if (WARN_ON(!modeset)) {
-				drm_client_display_free(display);
-				goto out;
-			}
-
-			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
-				      mode->name, modeset->crtc->base.id, offset->x, offset->y);
-
-			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;
-		}
-	}
-
 	drm_client_display_free(fb_helper->display);
 	fb_helper->display = display;
-out:
-	mutex_unlock(&dev->mode_config.mutex);
-	drm_connector_put_all(connectors, connector_count);
-	kfree(crtcs);
-	kfree(modes);
-	kfree(offsets);
-	kfree(enabled);
 }
 
 /*
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index ed028f5877d0..27d2a46cd94a 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -48,5 +48,7 @@ bool drm_client_display_panel_rotation(struct drm_connector *connector,
 				       unsigned int *rotation);
 int drm_client_display_restore(struct drm_client_display *display);
 void drm_client_display_dpms(struct drm_client_display *display, int mode);
+struct drm_client_display *
+drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height);
 
 #endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index a1e1ab1247c5..5f66f253a97b 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -41,10 +41,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.15.1

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

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

* [RFC v4 16/25] drm: Make ioctls available for in-kernel clients
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (14 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  9:04   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 17/25] drm/client: Bail out if there's a DRM master Noralf Trønnes
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

Make ioctl wrappers for functions that will be used by the in-kernel API.
The following functions are touched:
- drm_mode_create_dumb_ioctl()
- drm_mode_destroy_dumb_ioctl()
- drm_mode_addfb2()
- drm_mode_rmfb()
- drm_prime_handle_to_fd_ioctl()

drm_mode_addfb2() also gets the ability to override the debug name.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_crtc_internal.h | 18 ++++++++++---
 drivers/gpu/drm/drm_dumb_buffers.c  | 33 ++++++++++++++++--------
 drivers/gpu/drm/drm_framebuffer.c   | 50 ++++++++++++++++++++++++-------------
 drivers/gpu/drm/drm_internal.h      |  3 +++
 drivers/gpu/drm/drm_ioc32.c         |  2 +-
 drivers/gpu/drm/drm_ioctl.c         |  4 +--
 drivers/gpu/drm/drm_prime.c         | 13 +++++++---
 7 files changed, 84 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 3c2b82865ad2..8f8886ac0e4d 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -62,6 +62,12 @@ int drm_mode_getresources(struct drm_device *dev,
 
 
 /* drm_dumb_buffers.c */
+int drm_mode_create_dumb(struct drm_device *dev,
+			 struct drm_mode_create_dumb *args,
+			 struct drm_file *file_priv);
+int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle,
+			  struct drm_file *file_priv);
+
 /* IOCTLs */
 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
 			       void *data, struct drm_file *file_priv);
@@ -163,14 +169,18 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
 				     const struct drm_framebuffer *fb);
 void drm_fb_release(struct drm_file *file_priv);
 
+int drm_mode_addfb2(struct drm_device *dev, struct drm_mode_fb_cmd2 *r,
+		    struct drm_file *file_priv, const char *comm);
+int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
+		  struct drm_file *file_priv);
 
 /* IOCTL */
 int drm_mode_addfb(struct drm_device *dev,
 		   void *data, struct drm_file *file_priv);
-int drm_mode_addfb2(struct drm_device *dev,
-		    void *data, struct drm_file *file_priv);
-int drm_mode_rmfb(struct drm_device *dev,
-		  void *data, struct drm_file *file_priv);
+int drm_mode_addfb2_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv);
+int drm_mode_rmfb_ioctl(struct drm_device *dev,
+			void *data, struct drm_file *file_priv);
 int drm_mode_getfb(struct drm_device *dev,
 		   void *data, struct drm_file *file_priv);
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c
index 39ac15ce4702..eed9687b8698 100644
--- a/drivers/gpu/drm/drm_dumb_buffers.c
+++ b/drivers/gpu/drm/drm_dumb_buffers.c
@@ -53,10 +53,10 @@
  * a hardware-specific ioctl to allocate suitable buffer objects.
  */
 
-int drm_mode_create_dumb_ioctl(struct drm_device *dev,
-			       void *data, struct drm_file *file_priv)
+int drm_mode_create_dumb(struct drm_device *dev,
+			 struct drm_mode_create_dumb *args,
+			 struct drm_file *file_priv)
 {
-	struct drm_mode_create_dumb *args = data;
 	u32 cpp, stride, size;
 
 	if (!dev->driver->dumb_create)
@@ -91,6 +91,12 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
 	return dev->driver->dumb_create(file_priv, dev, args);
 }
 
+int drm_mode_create_dumb_ioctl(struct drm_device *dev,
+			       void *data, struct drm_file *file_priv)
+{
+	return drm_mode_create_dumb(dev, data, file_priv);
+}
+
 /**
  * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
  * @dev: DRM device
@@ -122,17 +128,22 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
 					       &args->offset);
 }
 
+int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle,
+			  struct drm_file *file_priv)
+{
+	if (!dev->driver->dumb_create)
+		return -ENOSYS;
+
+	if (dev->driver->dumb_destroy)
+		return dev->driver->dumb_destroy(file_priv, dev, handle);
+	else
+		return drm_gem_dumb_destroy(file_priv, dev, handle);
+}
+
 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
 				void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_destroy_dumb *args = data;
 
-	if (!dev->driver->dumb_create)
-		return -ENOSYS;
-
-	if (dev->driver->dumb_destroy)
-		return dev->driver->dumb_destroy(file_priv, dev, args->handle);
-	else
-		return drm_gem_dumb_destroy(file_priv, dev, args->handle);
+	return drm_mode_destroy_dumb(dev, args->handle, file_priv);
 }
-
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 8c4d32adcc17..16769e4db5c0 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -125,7 +125,7 @@ int drm_mode_addfb(struct drm_device *dev,
 	    dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP)
 		r.pixel_format = DRM_FORMAT_XBGR2101010;
 
-	ret = drm_mode_addfb2(dev, &r, file_priv);
+	ret = drm_mode_addfb2_ioctl(dev, &r, file_priv);
 	if (ret)
 		return ret;
 
@@ -310,23 +310,23 @@ drm_internal_framebuffer_create(struct drm_device *dev,
 
 /**
  * drm_mode_addfb2 - add an FB to the graphics configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
+ * @dev: drm device
+ * @r: pointer to request structure
+ * @file_priv: drm file
+ * @comm: optionally override the allocator name used for debug output
  *
  * Add a new FB to the specified CRTC, given a user request with format. This is
  * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
  * and uses fourcc codes as pixel format specifiers.
  *
- * Called by the user via ioctl.
+ * Called by the user via ioctl, or by an in-kernel client.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_addfb2(struct drm_device *dev,
-		    void *data, struct drm_file *file_priv)
+int drm_mode_addfb2(struct drm_device *dev, struct drm_mode_fb_cmd2 *r,
+		    struct drm_file *file_priv, const char *comm)
 {
-	struct drm_mode_fb_cmd2 *r = data;
 	struct drm_framebuffer *fb;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -336,6 +336,9 @@ int drm_mode_addfb2(struct drm_device *dev,
 	if (IS_ERR(fb))
 		return PTR_ERR(fb);
 
+	if (comm)
+		strscpy(fb->comm, comm, TASK_COMM_LEN);
+
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 	r->fb_id = fb->base.id;
 
@@ -347,6 +350,12 @@ int drm_mode_addfb2(struct drm_device *dev,
 	return 0;
 }
 
+int drm_mode_addfb2_ioctl(struct drm_device *dev,
+			  void *data, struct drm_file *file_priv)
+{
+	return drm_mode_addfb2(dev, data, file_priv, NULL);
+}
+
 struct drm_mode_rmfb_work {
 	struct work_struct work;
 	struct list_head fbs;
@@ -367,29 +376,28 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w)
 
 /**
  * drm_mode_rmfb - remove an FB from the configuration
- * @dev: drm device for the ioctl
- * @data: data pointer for the ioctl
- * @file_priv: drm file for the ioctl call
+ * @dev: drm device
+ * @fb_id: id of framebuffer to remove
+ * @file_priv: drm file
  *
- * Remove the FB specified by the user.
+ * Remove the specified FB.
  *
- * Called by the user via ioctl.
+ * Called by the user via ioctl, or by an in-kernel client.
  *
  * Returns:
  * Zero on success, negative errno on failure.
  */
-int drm_mode_rmfb(struct drm_device *dev,
-		   void *data, struct drm_file *file_priv)
+int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
+		  struct drm_file *file_priv)
 {
 	struct drm_framebuffer *fb = NULL;
 	struct drm_framebuffer *fbl = NULL;
-	uint32_t *id = data;
 	int found = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	fb = drm_framebuffer_lookup(dev, file_priv, *id);
+	fb = drm_framebuffer_lookup(dev, file_priv, fb_id);
 	if (!fb)
 		return -ENOENT;
 
@@ -435,6 +443,14 @@ int drm_mode_rmfb(struct drm_device *dev,
 	return -ENOENT;
 }
 
+int drm_mode_rmfb_ioctl(struct drm_device *dev,
+			void *data, struct drm_file *file_priv)
+{
+	uint32_t *fb_id = data;
+
+	return drm_mode_rmfb(dev, *fb_id, file_priv);
+}
+
 /**
  * drm_mode_getfb - get FB info
  * @dev: drm device for the ioctl
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 40179c5fc6b8..3f5d7706bcc9 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -37,6 +37,9 @@ void drm_pci_agp_destroy(struct drm_device *dev);
 int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master);
 
 /* drm_prime.c */
+int drm_prime_handle_to_fd(struct drm_device *dev,
+			   struct drm_prime_handle *args,
+			   struct drm_file *file_priv);
 int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
 				 struct drm_file *file_priv);
 int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index f8e96e648acf..576d00b7dad5 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -884,7 +884,7 @@ static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
 			   sizeof(req64.modifier)))
 		return -EFAULT;
 
-	err = drm_ioctl_kernel(file, drm_mode_addfb2, &req64,
+	err = drm_ioctl_kernel(file, drm_mode_addfb2_ioctl, &req64,
 				DRM_CONTROL_ALLOW|DRM_UNLOCKED);
 	if (err)
 		return err;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index af782911c505..c69fda5d3875 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -635,8 +635,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
-	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index caf675e3e692..e6052ab2bec4 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -866,11 +866,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
 
-int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
-				 struct drm_file *file_priv)
+int drm_prime_handle_to_fd(struct drm_device *dev,
+			   struct drm_prime_handle *args,
+			   struct drm_file *file_priv)
 {
-	struct drm_prime_handle *args = data;
-
 	if (!drm_core_check_feature(dev, DRIVER_PRIME))
 		return -EINVAL;
 
@@ -885,6 +884,12 @@ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
 			args->handle, args->flags, &args->fd);
 }
 
+int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
+				 struct drm_file *file_priv)
+{
+	return drm_prime_handle_to_fd(dev, data, file_priv);
+}
+
 int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 				 struct drm_file *file_priv)
 {
-- 
2.15.1

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

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

* [RFC v4 17/25] drm/client: Bail out if there's a DRM master
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (15 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 16/25] drm: Make ioctls available for in-kernel clients Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:45   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 18/25] drm/client: Make the display modes available to clients Noralf Trønnes
                   ` (8 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

If there's a DRM master, return -EBUSY.
Block userspace from becoming master by taking the master lock while
the client is setting the mode.

Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_auth.c      | 33 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_client.c    | 34 +++++++++++++++++++++++++++++-----
 drivers/gpu/drm/drm_fb_helper.c |  8 ++++----
 drivers/gpu/drm/drm_internal.h  |  2 ++
 include/drm/drm_client.h        |  4 ++--
 5 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index d9c0f7573905..d656d0d93da3 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -366,3 +366,36 @@ void drm_master_put(struct drm_master **master)
 	*master = NULL;
 }
 EXPORT_SYMBOL(drm_master_put);
+
+/**
+ * drm_master_block - Block DRM master operations
+ * @dev: DRM device
+ *
+ * This function checks if there is a master on @dev. If there is no master it
+ * blocks anyone from becoming master. In-kernel clients can use this to know
+ * when they can act as master. Use drm_master_unblock() to unblock.
+ *
+ * Returns:
+ * True if there is no master, false otherwise.
+ */
+bool drm_master_block(struct drm_device *dev)
+{
+	mutex_lock(&dev->master_mutex);
+	if (dev->master) {
+		mutex_unlock(&dev->master_mutex);
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * drm_master_unblock - Unblock DRM master operations
+ * @dev: DRM device
+ *
+ * Unblock and allow userspace to become master.
+ */
+void drm_master_unblock(struct drm_device *dev)
+{
+	mutex_unlock(&dev->master_mutex);
+}
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 27818a467b09..764c556630b8 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -18,6 +18,8 @@
 #include <drm/drm_device.h>
 #include <drm/drm_modes.h>
 
+#include "drm_internal.h"
+
 struct drm_client_display_offset {
 	int x, y;
 };
@@ -313,18 +315,30 @@ static int drm_client_display_restore_legacy(struct drm_client_display *display)
 /**
  * drm_client_display_restore() - Restore client display
  * @display: Client display
+ * @force: If true, restore even if there's a DRM master
  *
  * Restore client display using the current modeset configuration.
  *
  * Return:
  * Zero on succes or negative error code on failure.
  */
-int drm_client_display_restore(struct drm_client_display *display)
+int drm_client_display_restore(struct drm_client_display *display, bool force)
 {
-	if (drm_drv_uses_atomic_modeset(display->dev))
-		return drm_client_display_restore_atomic(display, true);
+	struct drm_device *dev = display->dev;
+	int ret;
+
+	if (!force && !drm_master_block(dev))
+		return -EBUSY;
+
+	if (drm_drv_uses_atomic_modeset(dev))
+		ret = drm_client_display_restore_atomic(display, true);
 	else
-		return drm_client_display_restore_legacy(display);
+		ret = drm_client_display_restore_legacy(display);
+
+	if (!force)
+		drm_master_unblock(dev);
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_client_display_restore);
 
@@ -354,13 +368,23 @@ static void drm_client_display_dpms_legacy(struct drm_client_display *display, i
  * drm_client_display_dpms() - Set display DPMS mode
  * @display: Client display
  * @mode: DPMS mode
+ *
+ * Returns:
+ * Zero on success, -EBUSY if there's a DRM master.
  */
-void drm_client_display_dpms(struct drm_client_display *display, int mode)
+int drm_client_display_dpms(struct drm_client_display *display, int mode)
 {
+	if (!drm_master_block(display->dev))
+		return -EBUSY;
+
 	if (drm_drv_uses_atomic_modeset(display->dev))
 		drm_client_display_restore_atomic(display, mode == DRM_MODE_DPMS_ON);
 	else
 		drm_client_display_dpms_legacy(display, mode);
+
+	drm_master_unblock(display->dev);
+
+	return 0;
 }
 EXPORT_SYMBOL(drm_client_display_dpms);
 
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 01d8840930a3..98e5bc92c9f2 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -181,7 +181,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 		return 0;
 
 	mutex_lock(&fb_helper->lock);
-	ret = drm_client_display_restore(fb_helper->display);
+	ret = drm_client_display_restore(fb_helper->display, false);
 
 	do_delayed = fb_helper->delayed_hotplug;
 	if (do_delayed)
@@ -243,7 +243,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
 			continue;
 
 		mutex_lock(&helper->lock);
-		ret = drm_client_display_restore(helper->display);
+		ret = drm_client_display_restore(helper->display, true);
 		if (ret)
 			error = true;
 		mutex_unlock(&helper->lock);
@@ -1254,7 +1254,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
 
 	pan_set(fb_helper, var->xoffset, var->yoffset);
 
-	ret = drm_client_display_restore(fb_helper->display);
+	ret = drm_client_display_restore(fb_helper->display, false);
 	if (!ret) {
 		info->var.xoffset = var->xoffset;
 		info->var.yoffset = var->yoffset;
@@ -1423,7 +1423,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 && !READ_ONCE(fb_helper->dev->master))
-			drm_client_display_restore(fb_helper->display);
+			drm_client_display_restore(fb_helper->display, false);
 		return -EAGAIN;
 	}
 
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 3f5d7706bcc9..f38dcaf139d7 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -92,6 +92,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_block(struct drm_device *dev);
+void drm_master_unblock(struct drm_device *dev);
 
 /* drm_sysfs.c */
 extern struct class *drm_class;
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 27d2a46cd94a..3befd879a0b0 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -46,8 +46,8 @@ drm_client_display_find_modeset(struct drm_client_display *display, struct drm_c
 bool drm_client_display_panel_rotation(struct drm_connector *connector,
 				       struct drm_plane *plane,
 				       unsigned int *rotation);
-int drm_client_display_restore(struct drm_client_display *display);
-void drm_client_display_dpms(struct drm_client_display *display, int mode);
+int drm_client_display_restore(struct drm_client_display *display, bool force);
+int drm_client_display_dpms(struct drm_client_display *display, int mode);
 struct drm_client_display *
 drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height);
 
-- 
2.15.1

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

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

* [RFC v4 18/25] drm/client: Make the display modes available to clients
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (16 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 17/25] drm/client: Bail out if there's a DRM master Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 19/25] drm/client: Finish the in-kernel client API Noralf Trønnes
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

Give clients easy access to the display modes.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c | 159 +++++++++++++++++++++++++++++++++----------
 include/drm/drm_client.h     |  25 +++++++
 2 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 764c556630b8..bce1630a0db2 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,6 +8,7 @@
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
  */
 
+#include <linux/list.h>
 #include <linux/slab.h>
 
 #include <drm/drm_atomic.h>
@@ -54,6 +55,7 @@ struct drm_client_display *drm_client_display_create(struct drm_device *dev)
 	}
 
 	display->dev = dev;
+	INIT_LIST_HEAD(&display->modes);
 	display->modeset_count = num_crtc;
 
 	drm_for_each_crtc(crtc, dev)
@@ -84,12 +86,16 @@ EXPORT_SYMBOL(drm_client_display_create);
  */
 void drm_client_display_free(struct drm_client_display *display)
 {
+	struct drm_display_mode *mode, *tmp;
 	struct drm_mode_set *modeset;
 	unsigned int i;
 
 	if (!display)
 		return;
 
+	list_for_each_entry_safe(mode, tmp, &display->modes, head)
+		drm_mode_destroy(display->dev, mode);
+
 	drm_client_display_for_each_modeset(modeset, display) {
 		if (modeset->mode)
 			drm_mode_destroy(display->dev, modeset->mode);
@@ -670,22 +676,70 @@ static int drm_pick_crtcs(struct drm_client_display *display,
 	return best_score;
 }
 
-/**
- * drm_client_find_display() - Find display
- * @dev: DRM device
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function returns a display the client can use if available.
- *
- * Free resources by calling drm_client_display_free().
- *
- * Returns:
- * A &drm_client_display on success, NULL if no connectors are found
- * or error pointer on failure.
- */
-struct drm_client_display *
-drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+/* Give the client a static list of display modes */
+static int drm_client_display_copy_modes(struct drm_client_display *display)
+{
+	int hdisplay = 0, vdisplay = 0, vrefresh;
+	struct drm_device *dev = display->dev;
+	struct drm_display_mode *mode, *copy;
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	unsigned int count = 0;
+
+	drm_client_display_for_each_modeset(modeset, display) {
+		if (!modeset->num_connectors || !modeset->mode)
+			continue;
+
+		connector = modeset->connectors[0];
+		mode = modeset->mode;
+		count++;
+
+		if (modeset->num_connectors == 2) {
+			/* Cloned output */
+			copy = drm_mode_duplicate(dev, modeset->mode);
+			if (!copy)
+				return -ENOMEM;
+			list_add_tail(&copy->head, &display->modes);
+			display->mode = copy;
+
+			return 0;
+		}
+
+		if (!modeset->y)
+			hdisplay += modeset->mode->hdisplay;
+		if (!modeset->x)
+			vdisplay += modeset->mode->vdisplay;
+		vrefresh = modeset->mode->vrefresh;
+	}
+
+	if (!count)
+		return 0;
+
+	if (count == 1) {
+		struct drm_display_mode *iter;
+
+		list_for_each_entry(iter, &connector->modes, head) {
+			copy = drm_mode_duplicate(dev, iter);
+			if (!copy)
+				return -ENOMEM;
+			list_add_tail(&copy->head, &display->modes);
+			if (!display->mode && drm_mode_equal(iter, mode))
+				display->mode = copy;
+		}
+	} else {
+		/* Combined tile mode. Only the default one for now */
+		copy = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, false, false, false);
+		if (!copy)
+			return -ENOMEM;
+		list_add_tail(&copy->head, &display->modes);
+		display->mode = copy;
+	}
+
+	return 0;
+}
+
+static struct drm_client_display *
+drm_client_find_display_default(struct drm_device *dev, unsigned int width, unsigned int height)
 {
 	struct drm_client_display_offset *offsets;
 	struct drm_client_display *display;
@@ -695,25 +749,6 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 	int i, connector_count;
 	bool *enabled;
 
-	DRM_DEBUG_KMS("\n");
-
-	if (!width)
-		width = dev->mode_config.max_width;
-	if (!height)
-		height = dev->mode_config.max_height;
-
-	mutex_lock(&dev->mode_config.mutex);
-	if (!drm_client_probe_connector_modes(dev, width, height))
-		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-
-	if (dev->driver->initial_client_display) {
-		display = dev->driver->initial_client_display(dev, width, height);
-		if (display) {
-			mutex_unlock(&dev->mode_config.mutex);
-			return display;
-		}
-	}
-
 	connector_count = drm_connector_get_all(dev, &connectors);
 	if (connector_count < 1)
 		return NULL;
@@ -772,7 +807,6 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 		}
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
 	drm_connector_put_all(connectors, connector_count);
 	kfree(crtcs);
 	kfree(modes);
@@ -781,4 +815,57 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 
 	return display;
 }
+
+/**
+ * drm_client_find_display() - Find display
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function returns a display the client can use if one is found.
+ *
+ * Free resources by calling drm_client_display_free().
+ *
+ * Returns:
+ * A &drm_client_display on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_client_display *
+drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+{
+	struct drm_client_display *display = NULL;
+	int ret;
+
+	DRM_DEBUG_KMS("\n");
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	if (!drm_client_probe_connector_modes(dev, width, height))
+		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+
+	if (dev->driver->initial_client_display)
+		display = dev->driver->initial_client_display(dev, width, height);
+
+	if (!display)
+		display = drm_client_find_display_default(dev, width, height);
+
+	if (IS_ERR_OR_NULL(display))
+		goto out_unlock;
+
+	ret = drm_client_display_copy_modes(display);
+	if (ret) {
+		drm_client_display_free(display);
+		display = ERR_PTR(ret);
+	}
+
+out_unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return display;
+}
 EXPORT_SYMBOL(drm_client_find_display);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 3befd879a0b0..524f793d6e7b 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,9 +3,12 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+#include <linux/types.h>
+
 struct drm_connector;
 struct drm_crtc;
 struct drm_device;
+struct drm_display_mode;
 struct drm_mode_set;
 struct drm_plane;
 
@@ -33,6 +36,20 @@ struct drm_client_display {
 	 * Number of modesets
 	 */
 	unsigned int modeset_count;
+
+	/**
+	 * @modes:
+	 *
+	 * Display modes available on this display.
+	 */
+	struct list_head modes;
+
+	/**
+	 * @mode:
+	 *
+	 * The current display mode.
+	 */
+	struct drm_display_mode *mode;
 };
 
 struct drm_client_display *drm_client_display_create(struct drm_device *dev);
@@ -51,4 +68,12 @@ int drm_client_display_dpms(struct drm_client_display *display, int mode);
 struct drm_client_display *
 drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height);
 
+/**
+ * drm_client_display_for_each_mode - Iterate over the available display modes
+ * @mode: A @drm_display_mode loop cursor
+ * @display: Client display
+ */
+#define drm_client_display_for_each_mode(mode, display) \
+	list_for_each_entry(mode, &display->modes, head)
+
 #endif
-- 
2.15.1

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

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

* [RFC v4 19/25] drm/client: Finish the in-kernel client API
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (17 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 18/25] drm/client: Make the display modes available to clients Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:27   ` [Intel-gfx] " Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 20/25] drm/prime: Don't pin module on export for in-kernel clients Noralf Trønnes
                   ` (6 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

The modesetting code is already present, this adds the rest of the API.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c       | 573 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_debugfs.c      |   7 +
 drivers/gpu/drm/drm_drv.c          |  11 +
 drivers/gpu/drm/drm_file.c         |   3 +
 drivers/gpu/drm/drm_probe_helper.c |   3 +
 drivers/gpu/drm/drm_sysfs.c        |  20 ++
 include/drm/drm_client.h           | 103 +++++++
 include/drm/drm_device.h           |   4 +
 8 files changed, 724 insertions(+)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index bce1630a0db2..760f1795f812 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,7 +8,9 @@
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
  */
 
+#include <linux/dma-buf.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 
 #include <drm/drm_atomic.h>
@@ -17,14 +19,280 @@
 #include <drm/drm_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_device.h>
+#include <drm/drm_file.h>
 #include <drm/drm_modes.h>
 
+#include "drm_crtc_internal.h"
 #include "drm_internal.h"
 
 struct drm_client_display_offset {
 	int x, y;
 };
 
+static int drm_client_alloc_file(struct drm_client_dev *client)
+{
+	struct drm_device *dev = client->dev;
+	struct drm_file *file;
+
+	file = drm_file_alloc(dev->primary);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	drm_dev_get(dev);
+
+	mutex_lock(&dev->filelist_mutex);
+	list_add(&file->lhead, &dev->filelist_internal);
+	mutex_unlock(&dev->filelist_mutex);
+
+	client->file = file;
+
+	return 0;
+}
+
+static void drm_client_free_file(struct drm_client_dev *client)
+{
+	struct drm_device *dev = client->dev;
+
+	mutex_lock(&dev->filelist_mutex);
+	list_del(&client->file->lhead);
+	mutex_unlock(&dev->filelist_mutex);
+
+	drm_file_free(client->file);
+	drm_dev_put(dev);
+}
+
+struct drm_client_dev *
+drm_client_new(struct drm_device *dev, const struct drm_client_funcs *funcs)
+{
+	struct drm_client_dev *client;
+	int ret;
+
+	if (WARN_ON(!funcs->name))
+		return ERR_PTR(-EINVAL);
+
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
+		return ERR_PTR(-ENOMEM);
+
+	client->dev = dev;
+	client->funcs = funcs;
+
+	ret = drm_client_alloc_file(client);
+	if (ret) {
+		kfree(client);
+		return ERR_PTR(ret);
+	}
+
+	mutex_lock(&dev->clientlist_mutex);
+	list_add(&client->list, &dev->clientlist);
+	mutex_unlock(&dev->clientlist_mutex);
+
+	return client;
+}
+EXPORT_SYMBOL(drm_client_new);
+
+struct drm_client_dev *
+drm_client_new_from_id(unsigned int dev_id, const struct drm_client_funcs *funcs)
+{
+	struct drm_client_dev *client;
+	struct drm_minor *minor;
+
+	minor = drm_minor_acquire(dev_id);
+	if (IS_ERR(minor))
+		return ERR_CAST(minor);
+
+	client = drm_client_new(minor->dev, funcs);
+
+	drm_minor_release(minor);
+
+	return client;
+}
+EXPORT_SYMBOL(drm_client_new_from_id);
+
+/**
+ * drm_client_free - Free DRM client resources
+ * @client: DRM client
+ *
+ * This is called automatically on client removal unless the client returns
+ * non-zero in the &drm_client_funcs->remove callback. The fbdev client does
+ * this when it can't close &drm_file because userspace has an open fd.
+ *
+ * Note:
+ * If the client can't release it's resources on remove, it needs to hold a
+ * reference on the driver module to prevent the code from going away.
+ */
+void drm_client_free(struct drm_client_dev *client)
+{
+	DRM_DEV_DEBUG_KMS(client->dev->dev, "%s\n", client->funcs->name);
+	drm_client_free_file(client);
+	kfree(client);
+}
+EXPORT_SYMBOL(drm_client_free);
+
+static void drm_client_remove_locked(struct drm_client_dev *client)
+{
+	list_del(&client->list);
+
+	if (!client->funcs->remove || !client->funcs->remove(client))
+		drm_client_free(client);
+}
+
+static void drm_client_remove_safe(struct drm_device *dev,
+				   struct drm_client_dev *client)
+{
+	struct drm_client_dev *iter;
+
+	mutex_lock(&dev->clientlist_mutex);
+	list_for_each_entry(iter, &dev->clientlist, list) {
+		if (iter == client) {
+			drm_client_remove_locked(client);
+			break;
+		}
+	}
+	mutex_unlock(&dev->clientlist_mutex);
+}
+
+/**
+ * drm_client_remove - Remove client
+ * @client: Client
+ *
+ * Remove a client.
+ */
+void drm_client_remove(struct drm_client_dev *client)
+{
+	struct drm_device *dev;
+
+	if (!client)
+		return;
+
+	dev = client->dev;
+	drm_dev_get(dev);
+	drm_client_remove_safe(dev, client);
+	drm_dev_put(dev);
+}
+EXPORT_SYMBOL(drm_client_remove);
+
+struct drm_client_remove_defer {
+	struct list_head list;
+	struct drm_device *dev;
+	struct drm_client_dev *client;
+};
+
+static LIST_HEAD(drm_client_remove_defer_list);
+static DEFINE_MUTEX(drm_client_remove_defer_list_lock);
+
+static void drm_client_remove_defer_work_fn(struct work_struct *work)
+{
+	struct drm_client_remove_defer *defer, *tmp;
+
+	mutex_lock(&drm_client_remove_defer_list_lock);
+	list_for_each_entry_safe(defer, tmp, &drm_client_remove_defer_list, list) {
+		drm_client_remove_safe(defer->dev, defer->client);
+		drm_dev_put(defer->dev);
+		list_del(&defer->list);
+		kfree(defer);
+	}
+	mutex_unlock(&drm_client_remove_defer_list_lock);
+}
+
+static DECLARE_WORK(drm_client_remove_defer_work, drm_client_remove_defer_work_fn);
+
+/**
+ * drm_client_remove_defer - Deferred client removal
+ * @client: Client
+ *
+ * Defer client removal to a worker. This makes it possible for a client running
+ * in a worker to remove itself.
+ *
+ * Returns:
+ * Zero on success, or -ENOMEM on allocation failure.
+ */
+int drm_client_remove_defer(struct drm_client_dev *client)
+{
+	struct drm_client_remove_defer *defer;
+
+	if (!client)
+		return 0;
+
+	defer = kzalloc(sizeof(*defer), GFP_KERNEL);
+	if (!defer)
+		return -ENOMEM;
+
+	defer->dev = client->dev;
+	defer->client = client;
+	drm_dev_get(client->dev);
+
+	mutex_lock(&drm_client_remove_defer_list_lock);
+	list_add(&defer->list, &drm_client_remove_defer_list);
+	mutex_unlock(&drm_client_remove_defer_list_lock);
+
+	schedule_work(&drm_client_remove_defer_work);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_client_remove_defer);
+
+void drm_client_init(void)
+{
+}
+
+void drm_client_exit(void)
+{
+	flush_work(&drm_client_remove_defer_work);
+}
+
+void drm_client_dev_unregister(struct drm_device *dev)
+{
+	struct drm_client_dev *client, *tmp;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return;
+
+	mutex_lock(&dev->clientlist_mutex);
+	list_for_each_entry_safe(client, tmp, &dev->clientlist, list)
+		drm_client_remove_locked(client);
+	mutex_unlock(&dev->clientlist_mutex);
+}
+
+void drm_client_dev_hotplug(struct drm_device *dev)
+{
+	struct drm_client_dev *client;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return;
+
+	mutex_lock(&dev->clientlist_mutex);
+	list_for_each_entry(client, &dev->clientlist, list) {
+		if (!client->funcs->hotplug)
+			continue;
+
+		ret = client->funcs->hotplug(client);
+		DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->funcs->name, ret);
+	}
+	mutex_unlock(&dev->clientlist_mutex);
+}
+EXPORT_SYMBOL(drm_client_dev_hotplug);
+
+void drm_client_dev_lastclose(struct drm_device *dev)
+{
+	struct drm_client_dev *client;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return;
+
+	mutex_lock(&dev->clientlist_mutex);
+	list_for_each_entry(client, &dev->clientlist, list) {
+		if (!client->funcs->lastclose)
+			continue;
+
+		ret = client->funcs->lastclose(client);
+		DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->funcs->name, ret);
+	}
+	mutex_unlock(&dev->clientlist_mutex);
+}
+
 /**
  * drm_client_display_create() - Create display structure
  * @dev: DRM device
@@ -348,6 +616,90 @@ int drm_client_display_restore(struct drm_client_display *display, bool force)
 }
 EXPORT_SYMBOL(drm_client_display_restore);
 
+/**
+ * drm_client_display_commit_mode - Commit a mode/fb to the CRTC(s)
+ * @display: Client display
+ * @fb: Framebuffer (if NULL the current fb is used)
+ * @mode: Display mode (if NULL the current mode is used)
+ *
+ * Returns:
+ * Zero on success, negative error code on failure.
+ */
+int drm_client_display_commit(struct drm_client_display *display,
+			      struct drm_framebuffer *fb, struct drm_display_mode *mode)
+{
+	struct drm_display_mode *use_mode = NULL;
+	struct drm_mode_set *modeset;
+	unsigned int count = 0;
+
+	if (mode) {
+		struct drm_display_mode *iter;
+
+		drm_client_display_for_each_mode(iter, display) {
+			if (!use_mode && drm_mode_equal(iter, mode))
+				use_mode = iter;
+			count++;
+		}
+
+		if (!use_mode)
+			return -EINVAL;
+
+		/*
+		 * Don't actually set the mode in the single mode case since it
+		 * might be a tiled display which consists of multiple modes.
+		 * Just keep the current mode.
+		 */
+		if (count == 1)
+			use_mode = NULL;
+	}
+
+	count = 0;
+	drm_client_display_for_each_modeset(modeset, display) {
+		if (!modeset->num_connectors)
+			continue;
+
+		if (fb)
+			modeset->fb = fb;
+
+		if (use_mode) {
+			if (WARN_ON(++count > 1))
+				return -EINVAL;
+
+			if (modeset->mode)
+				drm_mode_destroy(display->dev, modeset->mode);
+			modeset->mode = drm_mode_duplicate(display->dev, use_mode);
+			if (!modeset->mode)
+				return -ENOMEM;
+		}
+	}
+
+	return drm_client_display_restore(display, false);
+}
+EXPORT_SYMBOL(drm_client_display_commit);
+
+struct drm_framebuffer *drm_client_display_current_fb(struct drm_client_display *display)
+{
+	struct drm_mode_set *modeset;
+
+	drm_client_display_for_each_modeset(modeset, display) {
+		struct drm_crtc *crtc = modeset->crtc;
+		struct drm_framebuffer *fb = NULL;
+
+		drm_modeset_lock(&crtc->primary->mutex, NULL);
+		if (crtc->primary->state && crtc->primary->state->fb)
+			fb = crtc->primary->state->fb;
+		else if (!crtc->primary->state && crtc->primary->fb)
+			fb = crtc->primary->fb;
+		drm_modeset_unlock(&crtc->primary->mutex);
+
+		if (fb)
+			return fb;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(drm_client_display_current_fb);
+
 static void drm_client_display_dpms_legacy(struct drm_client_display *display, int dpms_mode)
 {
 	struct drm_device *dev = display->dev;
@@ -869,3 +1221,224 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 	return display;
 }
 EXPORT_SYMBOL(drm_client_find_display);
+
+static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
+{
+	if (!buffer)
+		return;
+
+	if (buffer->vaddr)
+		dma_buf_vunmap(buffer->dma_buf, buffer->vaddr);
+
+	if (buffer->dma_buf)
+		dma_buf_put(buffer->dma_buf);
+
+	drm_mode_destroy_dumb(buffer->client->dev, buffer->handle, buffer->client->file);
+	kfree(buffer);
+}
+
+/* For testing __close_fd() */
+#include <linux/fdtable.h>
+
+static struct drm_client_buffer *
+drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
+{
+	struct drm_mode_create_dumb dumb_args = { };
+	struct drm_prime_handle prime_args = { };
+	struct drm_client_buffer *buffer;
+	struct dma_buf *dma_buf;
+	void *vaddr;
+	int ret;
+
+	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+	if (!buffer)
+		return ERR_PTR(-ENOMEM);
+
+	buffer->client = client;
+	buffer->width = width;
+	buffer->height = height;
+	buffer->format = format;
+
+	dumb_args.width = buffer->width;
+	dumb_args.height = buffer->height;
+	dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
+	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
+	if (ret)
+		goto err_free;
+
+	buffer->handle = dumb_args.handle;
+	buffer->pitch = dumb_args.pitch;
+	buffer->size = dumb_args.size;
+
+	prime_args.handle = dumb_args.handle;
+	ret = drm_prime_handle_to_fd(client->dev, &prime_args, client->file);
+	if (ret)
+		goto err_delete;
+
+	dma_buf = dma_buf_get(prime_args.fd);
+	if (IS_ERR(dma_buf)) {
+		ret = PTR_ERR(dma_buf);
+		goto err_delete;
+	}
+
+	/*
+	 * If called from a worker the dmabuf fd isn't closed and the ref
+	 * doesn't drop to zero on free.
+	 * If I use __close_fd() it's all fine, but that function is not exported.
+	 *
+	 * How do I get rid of this fd when in a worker/kernel thread?
+	 * The fd isn't used beyond this function.
+	 */
+//	WARN_ON(__close_fd(current->files, prime_args.fd));
+
+	pr_info("%s: PF_KTHREAD=%u\n", __func__, !!(current->flags & PF_KTHREAD));
+
+	buffer->dma_buf = dma_buf;
+
+	vaddr = dma_buf_vmap(dma_buf);
+	if (!vaddr) {
+		ret = -ENOMEM;
+		goto err_delete;
+	}
+
+	buffer->vaddr = vaddr;
+
+	return buffer;
+
+err_delete:
+	drm_client_buffer_delete(buffer);
+err_free:
+	kfree(buffer);
+
+	return ERR_PTR(ret);
+}
+
+static int drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
+{
+	int ret;
+
+	if (!buffer || !buffer->fb)
+		return 0;
+
+	ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
+	if (ret)
+		DRM_DEV_ERROR(buffer->client->dev->dev,
+			      "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
+
+	buffer->fb = NULL;
+
+	return 0;
+}
+
+static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
+				   struct drm_display_mode *mode)
+{
+	struct drm_client_dev *client = buffer->client;
+	struct drm_mode_fb_cmd2 fb_req = { };
+	int ret;
+
+	if (mode->hdisplay > buffer->width || mode->vdisplay > buffer->height)
+		return -EINVAL;
+
+	fb_req.width = mode->hdisplay;
+	fb_req.height = mode->vdisplay;
+	fb_req.pixel_format = buffer->format;
+	fb_req.handles[0] = buffer->handle;
+	fb_req.pitches[0] = buffer->pitch;
+
+	ret = drm_mode_addfb2(client->dev, &fb_req, client->file, client->funcs->name);
+	if (ret)
+		return ret;
+
+	buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
+	if (WARN_ON(!buffer->fb))
+		return -ENOENT;
+
+	/* drop the reference we picked up in framebuffer lookup */
+	drm_framebuffer_put(buffer->fb);
+
+	return 0;
+}
+
+/**
+ * drm_client_framebuffer_create - Create a client framebuffer
+ * @client: DRM client
+ * @mode: Display mode to create a buffer for
+ * @format: Buffer format
+ *
+ * This function creates a &drm_client_buffer which consists of a
+ * &drm_framebuffer backed by a dumb buffer. The dumb buffer is &dma_buf
+ * exported to aquire a virtual address which is stored in
+ * &drm_client_buffer->vaddr.
+ * Call drm_client_framebuffer_delete() to free the buffer.
+ *
+ * Returns:
+ * Pointer to a client buffer or an error pointer on failure.
+ */
+struct drm_client_buffer *
+drm_client_framebuffer_create(struct drm_client_dev *client,
+			      struct drm_display_mode *mode, u32 format)
+{
+	struct drm_client_buffer *buffer;
+	int ret;
+
+	buffer = drm_client_buffer_create(client, mode->hdisplay,
+					  mode->vdisplay, format);
+	if (IS_ERR(buffer))
+		return buffer;
+
+	ret = drm_client_buffer_addfb(buffer, mode);
+	if (ret) {
+		drm_client_buffer_delete(buffer);
+		return ERR_PTR(ret);
+	}
+
+	return buffer;
+}
+EXPORT_SYMBOL(drm_client_framebuffer_create);
+
+void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
+{
+	drm_client_buffer_rmfb(buffer);
+	drm_client_buffer_delete(buffer);
+}
+EXPORT_SYMBOL(drm_client_framebuffer_delete);
+
+int drm_client_framebuffer_flush(struct drm_client_buffer *buffer,
+				 struct drm_clip_rect *rect)
+{
+	if (!buffer->fb || !buffer->fb->funcs->dirty)
+		return 0;
+
+	return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
+					0, 0, rect, rect ? 1 : 0);
+}
+EXPORT_SYMBOL(drm_client_framebuffer_flush);
+
+#ifdef CONFIG_DEBUG_FS
+static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_printer p = drm_seq_file_printer(m);
+	struct drm_client_dev *client;
+
+	mutex_lock(&dev->clientlist_mutex);
+	list_for_each_entry(client, &dev->clientlist, list)
+		drm_printf(&p, "%s\n", client->funcs->name);
+	mutex_unlock(&dev->clientlist_mutex);
+
+	return 0;
+}
+
+static const struct drm_info_list drm_client_debugfs_list[] = {
+	{ "internal_clients", drm_client_debugfs_internal_clients, 0 },
+};
+
+int drm_client_debugfs_init(struct drm_minor *minor)
+{
+	return drm_debugfs_create_files(drm_client_debugfs_list,
+					ARRAY_SIZE(drm_client_debugfs_list),
+					minor->debugfs_root, minor);
+}
+#endif
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index b2482818fee8..50a20bfc07ea 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 
+#include <drm/drm_client.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_atomic.h>
@@ -164,6 +165,12 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
 			DRM_ERROR("Failed to create framebuffer debugfs file\n");
 			return ret;
 		}
+
+		ret = drm_client_debugfs_init(minor);
+		if (ret) {
+			DRM_ERROR("Failed to create client debugfs file\n");
+			return ret;
+		}
 	}
 
 	if (dev->driver->debugfs_init) {
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 32a83b41ab61..6f21bafb29be 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -34,6 +34,7 @@
 #include <linux/slab.h>
 #include <linux/srcu.h>
 
+#include <drm/drm_client.h>
 #include <drm/drm_drv.h>
 #include <drm/drmP.h>
 
@@ -507,6 +508,8 @@ int drm_dev_init(struct drm_device *dev,
 	dev->driver = driver;
 
 	INIT_LIST_HEAD(&dev->filelist);
+	INIT_LIST_HEAD(&dev->filelist_internal);
+	INIT_LIST_HEAD(&dev->clientlist);
 	INIT_LIST_HEAD(&dev->ctxlist);
 	INIT_LIST_HEAD(&dev->vmalist);
 	INIT_LIST_HEAD(&dev->maplist);
@@ -516,6 +519,7 @@ int drm_dev_init(struct drm_device *dev,
 	spin_lock_init(&dev->event_lock);
 	mutex_init(&dev->struct_mutex);
 	mutex_init(&dev->filelist_mutex);
+	mutex_init(&dev->clientlist_mutex);
 	mutex_init(&dev->ctxlist_mutex);
 	mutex_init(&dev->master_mutex);
 
@@ -572,6 +576,7 @@ int drm_dev_init(struct drm_device *dev,
 err_free:
 	mutex_destroy(&dev->master_mutex);
 	mutex_destroy(&dev->ctxlist_mutex);
+	mutex_destroy(&dev->clientlist_mutex);
 	mutex_destroy(&dev->filelist_mutex);
 	mutex_destroy(&dev->struct_mutex);
 	return ret;
@@ -607,6 +612,7 @@ void drm_dev_fini(struct drm_device *dev)
 
 	mutex_destroy(&dev->master_mutex);
 	mutex_destroy(&dev->ctxlist_mutex);
+	mutex_destroy(&dev->clientlist_mutex);
 	mutex_destroy(&dev->filelist_mutex);
 	mutex_destroy(&dev->struct_mutex);
 	kfree(dev->unique);
@@ -862,6 +868,8 @@ void drm_dev_unregister(struct drm_device *dev)
 {
 	struct drm_map_list *r_list, *list_temp;
 
+	drm_client_dev_unregister(dev);
+
 	if (drm_core_check_feature(dev, DRIVER_LEGACY))
 		drm_lastclose(dev);
 
@@ -968,6 +976,7 @@ static const struct file_operations drm_stub_fops = {
 
 static void drm_core_exit(void)
 {
+	drm_client_exit();
 	unregister_chrdev(DRM_MAJOR, "drm");
 	debugfs_remove(drm_debugfs_root);
 	drm_sysfs_destroy();
@@ -1001,6 +1010,8 @@ static int __init drm_core_init(void)
 	if (ret < 0)
 		goto error;
 
+	drm_client_init();
+
 	drm_core_init_complete = true;
 
 	DRM_DEBUG("Initialized\n");
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index 55505378df47..bcc688e58776 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
+#include <drm/drm_client.h>
 #include <drm/drm_file.h>
 #include <drm/drmP.h>
 
@@ -443,6 +444,8 @@ void drm_lastclose(struct drm_device * dev)
 
 	if (drm_core_check_feature(dev, DRIVER_LEGACY))
 		drm_legacy_dev_reinit(dev);
+
+	drm_client_dev_lastclose(dev);
 }
 
 /**
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 527743394150..26be57e28a9d 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -33,6 +33,7 @@
 #include <linux/moduleparam.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_client.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_crtc_helper.h>
@@ -563,6 +564,8 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev)
 	drm_sysfs_hotplug_event(dev);
 	if (dev->mode_config.funcs->output_poll_changed)
 		dev->mode_config.funcs->output_poll_changed(dev);
+
+	drm_client_dev_hotplug(dev);
 }
 EXPORT_SYMBOL(drm_kms_helper_hotplug_event);
 
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 1c5b5ce1fd7f..1fc066c41861 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -18,6 +18,7 @@
 #include <linux/err.h>
 #include <linux/export.h>
 
+#include <drm/drm_client.h>
 #include <drm/drm_sysfs.h>
 #include <drm/drmP.h>
 #include "drm_internal.h"
@@ -320,6 +321,24 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_sysfs_hotplug_event);
 
+static ssize_t remove_internal_clients_store(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t len)
+{
+	struct drm_minor *minor = dev_get_drvdata(dev);
+
+	drm_client_dev_unregister(minor->dev);
+
+	return len;
+}
+static DEVICE_ATTR_WO(remove_internal_clients);
+
+static struct attribute *minor_attrs[] = {
+	&dev_attr_remove_internal_clients.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(minor);
+
 static void drm_sysfs_release(struct device *dev)
 {
 	kfree(dev);
@@ -347,6 +366,7 @@ struct device *drm_sysfs_minor_alloc(struct drm_minor *minor)
 	kdev->class = drm_class;
 	kdev->type = &drm_sysfs_device_minor;
 	kdev->parent = minor->dev->dev;
+	kdev->groups = minor_groups;
 	kdev->release = drm_sysfs_release;
 	dev_set_drvdata(kdev, minor);
 
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 524f793d6e7b..6fd2fcaae826 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -5,13 +5,91 @@
 
 #include <linux/types.h>
 
+struct drm_clip_rect;
 struct drm_connector;
 struct drm_crtc;
 struct drm_device;
 struct drm_display_mode;
+struct drm_framebuffer;
+struct drm_minor;
 struct drm_mode_set;
 struct drm_plane;
 
+struct drm_client_dev;
+
+/**
+ * struct drm_client_funcs - DRM client callbacks
+ */
+struct drm_client_funcs {
+	/**
+	 * @name:
+	 *
+	 * Name of the client. Mandatory.
+	 */
+	const char *name;
+
+	/**
+	 * @remove:
+	 *
+	 * Called when a &drm_device is unregistered or the client is
+	 * unregistered. If zero is returned drm_client_free() is called
+	 * automatically. If the client can't drop it's resources it should
+	 * return non-zero and call drm_client_free() later.
+	 *
+	 * This callback is optional.
+	 */
+	int (*remove)(struct drm_client_dev *client);
+
+	/**
+	 * @lastclose:
+	 *
+	 * Called on drm_lastclose(). The first client instance in the list
+	 * that returns zero gets the privilege to restore and no more clients
+	 * are called.
+	 *
+	 * This callback is optional.
+	 */
+	int (*lastclose)(struct drm_client_dev *client);
+
+	/**
+	 * @hotplug:
+	 *
+	 * Called on drm_kms_helper_hotplug_event().
+	 *
+	 * This callback is optional.
+	 */
+	int (*hotplug)(struct drm_client_dev *client);
+};
+
+/**
+ * struct drm_client_dev - DRM client instance
+ */
+struct drm_client_dev {
+	struct list_head list;
+	struct drm_device *dev;
+	const struct drm_client_funcs *funcs;
+	struct drm_file *file;
+	unsigned int file_ref_count;
+	void *private;
+};
+
+struct drm_client_dev *
+drm_client_new(struct drm_device *dev, const struct drm_client_funcs *funcs);
+struct drm_client_dev *
+drm_client_new_from_id(unsigned int dev_id, const struct drm_client_funcs *funcs);
+void drm_client_remove(struct drm_client_dev *client);
+int drm_client_remove_defer(struct drm_client_dev *client);
+void drm_client_free(struct drm_client_dev *client);
+
+void drm_client_dev_unregister(struct drm_device *dev);
+void drm_client_dev_hotplug(struct drm_device *dev);
+void drm_client_dev_lastclose(struct drm_device *dev);
+
+void drm_client_init(void);
+void drm_client_exit(void);
+
+int drm_client_debugfs_init(struct drm_minor *minor);
+
 /**
  * struct drm_client_display - DRM client display
  */
@@ -76,4 +154,29 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 #define drm_client_display_for_each_mode(mode, display) \
 	list_for_each_entry(mode, &display->modes, head)
 
+int drm_client_display_commit(struct drm_client_display *display,
+			      struct drm_framebuffer *fb, struct drm_display_mode *mode);
+struct drm_framebuffer *drm_client_display_current_fb(struct drm_client_display *display);
+
+struct drm_client_buffer {
+	struct drm_client_dev *client;
+	u32 width;
+	u32 height;
+	u32 format;
+	u32 handle;
+	u32 pitch;
+	u64 size;
+	struct dma_buf *dma_buf;
+	void *vaddr;
+	struct drm_framebuffer *fb;
+};
+
+struct drm_client_buffer *
+drm_client_framebuffer_create(struct drm_client_dev *client,
+			      struct drm_display_mode *mode, u32 format);
+void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
+
+int drm_client_framebuffer_flush(struct drm_client_buffer *buffer,
+				 struct drm_clip_rect *rect);
+
 #endif
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 3a0eac2885b7..17edadf8b691 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -74,6 +74,10 @@ struct drm_device {
 
 	struct mutex filelist_mutex;
 	struct list_head filelist;
+	struct list_head filelist_internal;
+
+	struct mutex clientlist_mutex;
+	struct list_head clientlist;
 
 	/** \name Memory management */
 	/*@{ */
-- 
2.15.1

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

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

* [RFC v4 20/25] drm/prime: Don't pin module on export for in-kernel clients
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (18 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 19/25] drm/client: Finish the in-kernel client API Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release() Noralf Trønnes
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

Avoid pinning the module when exporting a GEM object as a dmabuf. This
makes it possible to unload drivers that has in-kernel clients using it.
The client is removed on drm_dev_unregister() so no need to pin the driver.

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

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index e6052ab2bec4..f9dbe3b9db20 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -567,6 +567,30 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
 		.flags = flags,
 		.priv = obj,
 	};
+	bool is_internal = false;
+	struct drm_file *file;
+
+	mutex_lock(&dev->filelist_mutex);
+	list_for_each_entry(file, &dev->filelist_internal, lhead) {
+		struct drm_gem_object *iter;
+		int id;
+
+		spin_lock(&file->table_lock);
+		idr_for_each_entry(&file->object_idr, iter, id) {
+			if (iter == obj) {
+				is_internal = true;
+				break;
+			}
+		}
+		spin_unlock(&file->table_lock);
+
+		if (is_internal)
+			break;
+	}
+	mutex_unlock(&dev->filelist_mutex);
+
+	if (is_internal)
+		exp_info.owner = NULL;
 
 	if (dev->driver->gem_prime_res_obj)
 		exp_info.resv = dev->driver->gem_prime_res_obj(obj);
-- 
2.15.1

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

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

* [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release()
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (19 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 20/25] drm/prime: Don't pin module on export for in-kernel clients Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:46   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
                   ` (4 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

These helpers keep track of fbdev users and drm_driver.last_close will
only restore fbdev when actually in use. Additionally the display is
turned off when the last user is closing. fbcon is a user in this context.

If struct fb_ops is defined in a library, fb_open() takes a ref on the
library (fb_ops.owner) instead of the driver module. Fix that by ensuring
that the driver module is pinned.

The functions are not added to the DRM_FB_HELPER_DEFAULT_OPS() macro,
because some of its users do set fb_open/release themselves.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_fb_helper.c | 54 ++++++++++++++++++++++++++++++++++++++++-
 include/drm/drm_fb_helper.h     | 29 ++++++++++++++++++++++
 2 files changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 98e5bc92c9f2..b1124c08b1ed 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -177,7 +177,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
 	if (!drm_fbdev_emulation || !fb_helper)
 		return -ENODEV;
 
-	if (READ_ONCE(fb_helper->deferred_setup))
+	if (READ_ONCE(fb_helper->deferred_setup) || !READ_ONCE(fb_helper->open_count))
 		return 0;
 
 	mutex_lock(&fb_helper->lock);
@@ -368,6 +368,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
 	INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
 	helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
 	mutex_init(&helper->lock);
+	helper->open_count = 1;
 	helper->funcs = funcs;
 	helper->dev = dev;
 }
@@ -620,6 +621,53 @@ int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
 }
 EXPORT_SYMBOL(drm_fb_helper_defio_init);
 
+/**
+ * drm_fb_helper_fb_open - implementation for &fb_ops.fb_open
+ * @info: fbdev registered by the helper
+ * @user: 1=userspace, 0=fbcon
+ *
+ * Increase fbdev use count.
+ * If &fb_ops is wrapped in a library, pin the driver module.
+ */
+int drm_fb_helper_fb_open(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
+
+	if (info->fbops->owner != dev->driver->fops->owner) {
+		if (!try_module_get(dev->driver->fops->owner))
+			return -ENODEV;
+	}
+
+	fb_helper->open_count++;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_fb_open);
+
+/**
+ * drm_fb_helper_fb_release - implementation for &fb_ops.fb_release
+ * @info: fbdev registered by the helper
+ * @user: 1=userspace, 0=fbcon
+ *
+ * Decrease fbdev use count and turn off if there are no users left.
+ * If &fb_ops is wrapped in a library, unpin the driver module.
+ */
+int drm_fb_helper_fb_release(struct fb_info *info, int user)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_device *dev = fb_helper->dev;
+
+	if (!(--fb_helper->open_count))
+		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
+
+	if (info->fbops->owner != dev->driver->fops->owner)
+		module_put(dev->driver->fops->owner);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fb_helper_fb_release);
+
 /**
  * drm_fb_helper_sys_read - wrapper around fb_sys_read
  * @info: fb_info struct pointer
@@ -1436,6 +1484,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	if (ret < 0)
 		return ret;
 
+	/* Block restore without users if we do track it */
+	if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open)
+		fb_helper->open_count = 0;
+
 	strcpy(fb_helper->fb->comm, "[fbcon]");
 	return 0;
 }
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5f66f253a97b..330983975d5e 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -184,6 +184,22 @@ struct drm_fb_helper {
 	 * See also: @deferred_setup
 	 */
 	int preferred_bpp;
+
+	/**
+	 * @open_count:
+	 *
+	 * Keeps track of fbdev use to know when to not restore fbdev and to
+	 * disable the pipeline when the last user is gone.
+	 *
+	 * Drivers that use drm_fb_helper_fb_open() as their \.fb_open
+	 * callback will get an initial value of 0 and get restore based on
+	 * actual use. Others will get an initial value of 1 which means that
+	 * fbdev will always be restored. Drivers that call
+	 * drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the
+	 * initial value to 0 themselves in their &drm_fb_helper_funcs->fb_probe
+	 * callback.
+	 */
+	unsigned int open_count;
 };
 
 /**
@@ -230,6 +246,9 @@ void drm_fb_helper_deferred_io(struct fb_info *info,
 			       struct list_head *pagelist);
 int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper);
 
+int drm_fb_helper_fb_open(struct fb_info *info, int user);
+int drm_fb_helper_fb_release(struct fb_info *info, int user);
+
 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
 			       size_t count, loff_t *ppos);
 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
@@ -376,6 +395,16 @@ static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
 	return -ENODEV;
 }
 
+static inline int drm_fb_helper_fb_open(struct fb_info *info, int user)
+{
+	return -ENODEV;
+}
+
+static inline int drm_fb_helper_fb_release(struct fb_info *info, int user)
+{
+	return -ENODEV;
+}
+
 static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
 					     char __user *buf, size_t count,
 					     loff_t *ppos)
-- 
2.15.1

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

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

* [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (20 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release() Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:52   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 23/25] drm: Add DRM device registered notifier Noralf Trønnes
                   ` (3 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

This adds generic fbdev emulation for drivers that supports
dumb buffers which they can export.

All the driver has to do is call drm_fbdev_generic_setup().

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

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b1124c08b1ed..1954de5b13e0 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,6 +30,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/console.h>
+#include <linux/dma-buf.h>
 #include <linux/kernel.h>
 #include <linux/sysrq.h>
 #include <linux/slab.h>
@@ -1995,6 +1996,260 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
 
+static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+
+	return dma_buf_mmap(fb_helper->buffer->dma_buf, vma, 0);
+}
+
+/*
+ * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
+ * unregister_framebuffer() or fb_release().
+ */
+static void drm_fbdev_fb_destroy(struct fb_info *info)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct fb_ops *fbops = NULL;
+
+	DRM_DEBUG("\n");
+
+	if (fb_helper->fbdev->fbdefio)
+		fbops = fb_helper->fbdev->fbops;
+
+	drm_fb_helper_fini(fb_helper);
+	drm_client_framebuffer_delete(fb_helper->buffer);
+	drm_client_free(fb_helper->client);
+	kfree(fb_helper);
+	kfree(fbops);
+}
+
+static struct fb_ops drm_fbdev_fb_ops = {
+	/*
+	 * No need to set owner, this module is already pinned by the driver.
+	 * A reference is taken on the driver module in drm_fb_helper_fb_open()
+	 * to prevent the driver going away with open fd's.
+	 */
+	DRM_FB_HELPER_DEFAULT_OPS,
+	.fb_open	= drm_fb_helper_fb_open,
+	.fb_release	= drm_fb_helper_fb_release,
+	.fb_destroy	= drm_fbdev_fb_destroy,
+	.fb_mmap	= drm_fbdev_fb_mmap,
+	.fb_read	= drm_fb_helper_sys_read,
+	.fb_write	= drm_fb_helper_sys_write,
+	.fb_fillrect	= drm_fb_helper_sys_fillrect,
+	.fb_copyarea	= drm_fb_helper_sys_copyarea,
+	.fb_imageblit	= drm_fb_helper_sys_imageblit,
+};
+
+static struct fb_deferred_io drm_fbdev_defio = {
+	.delay		= HZ / 20,
+	.deferred_io	= drm_fb_helper_deferred_io,
+};
+
+/* Hack to test tinydrm before converting to vmalloc buffers */
+static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info,
+					  struct vm_area_struct *vma)
+{
+	fb_deferred_io_mmap(info, vma);
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	return 0;
+}
+
+static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
+				       struct drm_fb_helper_surface_size *sizes)
+{
+	struct drm_client_dev *client = fb_helper->client;
+	struct drm_display_mode sizes_mode = {
+		.hdisplay = sizes->surface_width,
+		.vdisplay = sizes->surface_height,
+	};
+	struct drm_client_buffer *buffer;
+	struct drm_framebuffer *fb;
+	struct fb_info *fbi;
+	u32 format;
+	int ret;
+
+	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
+		      sizes->surface_width, sizes->surface_height,
+		      sizes->surface_bpp);
+
+	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+	buffer = drm_client_framebuffer_create(client, &sizes_mode, format);
+	if (IS_ERR(buffer))
+		return PTR_ERR(buffer);
+
+	fb_helper->buffer = buffer;
+	fb_helper->fb = buffer->fb;
+	fb = buffer->fb;
+
+	fbi = drm_fb_helper_alloc_fbi(fb_helper);
+	if (IS_ERR(fbi)) {
+		ret = PTR_ERR(fbi);
+		goto err_free_buffer;
+	}
+
+	fbi->par = fb_helper;
+	fbi->fbops = &drm_fbdev_fb_ops;
+	fbi->screen_size = fb->height * fb->pitches[0];
+	fbi->fix.smem_len = fbi->screen_size;
+	fbi->screen_buffer = buffer->vaddr;
+	strcpy(fbi->fix.id, "DRM emulated");
+
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
+	drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height);
+
+	/*
+	 * Drivers that set the dirty callback:
+	 * - Doesn't use defio:
+	 *   i915, virtio, rockchip
+	 * - defio with vmalloc buffer blitted on the real one:
+	 *   vmwgfx
+	 * - defio is disabled because it doesn't work with shmem:
+	 *   udl
+	 * - defio with special dirty callback for fbdev, uses vmalloc for fbdev:
+	 *   qxl
+	 * - defio with cma buffer, will move to vmalloc buffers:
+	 *   tinydrm
+	 *
+	 * TODO:
+	 * Maybe add vmalloc shadow buffer support.
+	 */
+
+	if (fb->funcs->dirty) {
+		struct fb_ops *fbops;
+
+		/*
+		 * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per
+		 * instance version is necessary.
+		 */
+		fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+		if (!fbops) {
+			ret = -ENOMEM;
+			goto err_fb_info_destroy;
+		}
+
+		*fbops = *fbi->fbops;
+		fbi->fbops = fbops;
+
+		fbi->fbdefio = &drm_fbdev_defio;
+
+		/* Hack so I can test with tinydrm */
+		fbi->fix.smem_start = page_to_phys(virt_to_page(buffer->vaddr));
+
+		fb_deferred_io_init(fbi);
+
+		/* Hack so I can test with tinydrm */
+		fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap;
+	}
+
+	return 0;
+
+err_fb_info_destroy:
+	drm_fb_helper_fini(fb_helper);
+err_free_buffer:
+	drm_client_framebuffer_delete(buffer);
+
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
+	.fb_probe = drm_fb_helper_generic_probe,
+};
+
+static int drm_fbdev_client_remove(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = client->private;
+
+	if (!fb_helper->fbdev) {
+		kfree(fb_helper);
+		return 0;
+	}
+
+	unregister_framebuffer(fb_helper->fbdev);
+
+	/*
+	 * If userspace is closed the client is now freed by
+	 * drm_fbdev_fb_destroy(), otherwise it will be freed on the last close.
+	 * Return 1 to tell that freeing is taken care of.
+	 */
+
+	return 1;
+}
+
+static int drm_fbdev_client_lastclose(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = client->private;
+
+	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
+
+	return 0;
+}
+
+static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_fb_helper *fb_helper = client->private;
+
+	if (fb_helper->fbdev)
+		return 0;
+
+	return drm_fb_helper_fbdev_setup(client->dev, fb_helper,
+					 &drm_fb_helper_generic_funcs,
+					 fb_helper->preferred_bpp, 0);
+}
+
+static const struct drm_client_funcs drm_fbdev_client_funcs = {
+	.name		= "fbdev",
+	.remove		= drm_fbdev_client_remove,
+	.lastclose	= drm_fbdev_client_lastclose,
+	.hotplug	= drm_fbdev_client_hotplug,
+};
+
+/**
+ * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ *
+ * This function sets up generic fbdev emulation for drivers that supports
+ * dumb buffers which can be exported.
+ *
+ * Restore, hotplug events and teardown are all taken care of. Drivers that does
+ * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
+ * Simple drivers might use drm_mode_config_helper_suspend().
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{
+	struct drm_fb_helper *fb_helper;
+	struct drm_client_dev *client;
+
+	if (!drm_fbdev_emulation)
+		return 0;
+
+	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
+	if (!fb_helper)
+		return -ENOMEM;
+
+	client = drm_client_new(dev, &drm_fbdev_client_funcs);
+	if (IS_ERR(client)) {
+		kfree(fb_helper);
+		return PTR_ERR(client);
+	}
+
+	client->private = fb_helper;
+	fb_helper->client = client;
+	fb_helper->preferred_bpp = preferred_bpp;
+
+	drm_fbdev_client_hotplug(client);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbdev_generic_setup);
+
 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
  * but the module doesn't depend on any fb console symbols.  At least
  * attempt to load fbcon to avoid leaving the system without a usable console.
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 330983975d5e..711da1747836 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -126,6 +126,20 @@ struct drm_fb_helper {
 	 */
 	struct drm_client_display *display;
 
+	/**
+	 * @client:
+	 *
+	 * DRM client used by the generic fbdev emulation.
+	 */
+	struct drm_client_dev *client;
+
+	/**
+	 * @buffer:
+	 *
+	 * Framebuffer used by the generic fbdev emulation.
+	 */
+	struct drm_client_buffer *buffer;
+
 	const struct drm_fb_helper_funcs *funcs;
 	struct fb_info *fbdev;
 	u32 pseudo_palette[17];
@@ -219,6 +233,7 @@ struct drm_fb_helper {
 	.fb_ioctl	= drm_fb_helper_ioctl
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
+int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp);
 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
 			   const struct drm_fb_helper_funcs *funcs);
 int drm_fb_helper_init(struct drm_device *dev,
@@ -297,6 +312,11 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev);
 void drm_fb_helper_lastclose(struct drm_device *dev);
 void drm_fb_helper_output_poll_changed(struct drm_device *dev);
 #else
+static inline int
+drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
+{
+}
+
 static inline void drm_fb_helper_prepare(struct drm_device *dev,
 					struct drm_fb_helper *helper,
 					const struct drm_fb_helper_funcs *funcs)
-- 
2.15.1

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

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

* [RFC v4 23/25] drm: Add DRM device registered notifier
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (21 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-17 10:16   ` Daniel Vetter
  2018-04-14 11:53 ` [RFC v4 24/25] drm/client: Hack: Add bootsplash Noralf Trønnes
                   ` (2 subsequent siblings)
  25 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

Add a notifier that fires when a new DRM device is registered.
This can be used by the bootsplash client to connect to all devices.

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

diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 6f21bafb29be..e42ce320ad07 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/mount.h>
+#include <linux/notifier.h>
 #include <linux/slab.h>
 #include <linux/srcu.h>
 
@@ -79,6 +80,8 @@ static struct dentry *drm_debugfs_root;
 
 DEFINE_STATIC_SRCU(drm_unplug_srcu);
 
+static BLOCKING_NOTIFIER_HEAD(drm_dev_notifier);
+
 /*
  * DRM Minors
  * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
@@ -837,6 +840,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 		 dev->dev ? dev_name(dev->dev) : "virtual device",
 		 dev->primary->index);
 
+	blocking_notifier_call_chain(&drm_dev_notifier, 0, dev);
+
 	goto out_unlock;
 
 err_minors:
@@ -894,6 +899,33 @@ void drm_dev_unregister(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_dev_unregister);
 
+/**
+ * drm_dev_register_notifier - Register a notifier for new DRM devices
+ * @nb: Notifier block
+ *
+ * Register a notifier that fires when a new &drm_device is registered.
+ *
+ * Note:
+ * Users of this function has to be linked into drm.ko. This is done to make
+ * life simple avoiding tricky race situations.
+ */
+void drm_dev_register_notifier(struct notifier_block *nb)
+{
+	/* Currently this can't fail, but catch it in case this changes */
+	WARN_ON(blocking_notifier_chain_register(&drm_dev_notifier, nb));
+}
+
+/**
+ * drm_dev_unregister_notifier - Unregister DRM device notifier
+ * @nb: Notifier block
+ *
+ * This is a no-op if the notifier isn't registered.
+ */
+void drm_dev_unregister_notifier(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&drm_dev_notifier, nb);
+}
+
 /**
  * drm_dev_set_unique - Set the unique name of a DRM device
  * @dev: device of which to set the unique name
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index 13356e6fd40c..5e6c6ed0d59d 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -40,6 +40,7 @@ struct drm_minor;
 struct dma_buf_attachment;
 struct drm_display_mode;
 struct drm_mode_create_dumb;
+struct notifier_block;
 struct drm_printer;
 
 /* driver capabilities and requirements mask */
@@ -641,6 +642,9 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
 int drm_dev_register(struct drm_device *dev, unsigned long flags);
 void drm_dev_unregister(struct drm_device *dev);
 
+void drm_dev_register_notifier(struct notifier_block *nb);
+void drm_dev_unregister_notifier(struct notifier_block *nb);
+
 void drm_dev_get(struct drm_device *dev);
 void drm_dev_put(struct drm_device *dev);
 void drm_dev_unref(struct drm_device *dev);
-- 
2.15.1

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

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

* [RFC v4 24/25] drm/client: Hack: Add bootsplash
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (22 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 23/25] drm: Add DRM device registered notifier Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-14 11:53 ` [RFC v4 25/25] drm/client: Hack: Add DRM VT console client Noralf Trønnes
  2018-04-16  8:21 ` [RFC v4 00/25] drm: Add generic fbdev emulation Daniel Vetter
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx, Noralf Trønnes

A hack to test the client API.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Kconfig                 |   2 +
 drivers/gpu/drm/Makefile                |   1 +
 drivers/gpu/drm/client/Kconfig          |   9 ++
 drivers/gpu/drm/client/drm_bootsplash.c | 248 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/client/internal.h       |  19 +++
 drivers/gpu/drm/drm_client.c            |   4 +
 6 files changed, 283 insertions(+)
 create mode 100644 drivers/gpu/drm/client/Kconfig
 create mode 100644 drivers/gpu/drm/client/drm_bootsplash.c
 create mode 100644 drivers/gpu/drm/client/internal.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 757825ac60df..1328202ce17d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -154,6 +154,8 @@ config DRM_SCHED
 	tristate
 	depends on DRM
 
+source "drivers/gpu/drm/client/Kconfig"
+
 source "drivers/gpu/drm/i2c/Kconfig"
 
 source "drivers/gpu/drm/arm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d25afa136d8f..388527093f80 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -30,6 +30,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) += client/drm_bootsplash.o
 
 drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
 		drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
diff --git a/drivers/gpu/drm/client/Kconfig b/drivers/gpu/drm/client/Kconfig
new file mode 100644
index 000000000000..6b01f2e51fb3
--- /dev/null
+++ b/drivers/gpu/drm/client/Kconfig
@@ -0,0 +1,9 @@
+menu "DRM Clients"
+	depends on DRM
+
+config DRM_CLIENT_BOOTSPLASH
+	bool "DRM Bootsplash"
+	help
+	  DRM Bootsplash
+
+endmenu
diff --git a/drivers/gpu/drm/client/drm_bootsplash.c b/drivers/gpu/drm/client/drm_bootsplash.c
new file mode 100644
index 000000000000..bec3105f9b02
--- /dev/null
+++ b/drivers/gpu/drm/client/drm_bootsplash.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/keyboard.h>
+#include <linux/module.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/drmP.h>
+#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 drm_client_display *display;
+	struct drm_client_buffer *buffer[2];
+	struct work_struct worker;
+	bool stop;
+};
+
+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 u32 drm_bootsplash_color_table[3] = {
+	0x00ff0000, 0x0000ff00, 0x000000ff,
+};
+
+/* Draw a box with changing colors */
+static void
+drm_bootsplash_draw(struct drm_client_buffer *buffer, unsigned int sequence)
+{
+	unsigned int x, y;
+	u32 *pix;
+
+	pix = buffer->vaddr;
+	pix += ((buffer->height / 2) - 50) * buffer->width;
+	pix += (buffer->width / 2) - 50;
+
+	for (y = 0; y < 100; y++) {
+		for (x = 0; x < 100; x++)
+			*pix++ = drm_bootsplash_color_table[sequence];
+		pix += buffer->width - 100;
+	}
+}
+
+static void drm_bootsplash_worker(struct work_struct *work)
+{
+	struct drm_bootsplash *splash = container_of(work, struct drm_bootsplash, worker);
+	struct drm_device *dev = splash->client->dev;
+	unsigned int i = 0, sequence = 0;
+	struct drm_framebuffer *fb;
+	int ret = 0;
+
+	while (!splash->stop && !drm_bootsplash_key_pressed) {
+		/* Did someone take over, like another in-kernel client, except fbdev? */
+		fb = drm_client_display_current_fb(splash->display);
+		if (splash->buffer[i]->fb != fb &&
+		    !(dev->fb_helper && dev->fb_helper->fb == fb))
+			break;
+
+		i = !i;
+		drm_bootsplash_draw(splash->buffer[i], sequence++);
+		if (sequence == 3)
+			sequence = 0;
+
+		ret = drm_client_display_commit(splash->display, splash->buffer[i]->fb, NULL);
+		/* Is userspace in charge or is the device unplugged? */
+		if (ret == -EBUSY || ret == -ENODEV)
+			break;
+
+		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)
+		drm_lastclose(dev);
+
+	for (i = 0; i < 2; i++)
+		drm_client_framebuffer_delete(splash->buffer[i]);
+	drm_client_display_free(splash->display);
+	drm_client_remove_defer(splash->client);
+	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_setup(struct drm_bootsplash *splash)
+{
+	struct drm_client_dev *client = splash->client;
+	struct drm_client_buffer *buffer[2];
+	struct drm_client_display *display;
+	int ret, i;
+
+	display = drm_client_find_display(client->dev, 0, 0);
+	if (IS_ERR(display))
+		return PTR_ERR(display);
+	if (!display)
+		return -ENOENT;
+
+	if (WARN_ON(!display->mode))
+		return -ENOENT;
+
+	for (i = 0; i < 2; i++) {
+		buffer[i] = drm_client_framebuffer_create(client, display->mode,
+							  DRM_FORMAT_XRGB8888);
+		if (IS_ERR(buffer[i])) {
+			ret = PTR_ERR(buffer[i]);
+			goto err_free_buffer;
+		}
+	}
+
+	ret = drm_client_display_commit(display, buffer[0]->fb, display->mode);
+	if (ret)
+		goto err_free_buffer;
+
+	splash->display = display;
+	splash->buffer[0] = buffer[0];
+	splash->buffer[1] = buffer[1];
+
+	schedule_work(&splash->worker);
+
+	return 0;
+
+err_free_buffer:
+	for (i--; i >= 0; i--)
+		drm_client_framebuffer_delete(buffer[i]);
+	drm_client_display_free(display);
+
+	return ret;
+}
+
+static int drm_bootsplash_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = client->private;
+	int ret = 0;
+
+	if (splash->display)
+		return 0;
+
+	ret = drm_bootsplash_setup(splash);
+	if (ret) {
+		DRM_DEV_DEBUG_KMS(client->dev->dev, "ret=%d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int drm_bootsplash_client_remove(struct drm_client_dev *client)
+{
+	struct drm_bootsplash *splash = client->private;
+
+	/* Don't hook up to any new devices showing up */
+	drm_bootsplash_enabled = false;
+
+	splash->stop = true;
+	flush_work(&splash->worker);
+	kfree(splash);
+
+	return 0;
+}
+
+static const struct drm_client_funcs drm_bootsplash_client_funcs = {
+	.name		= "bootsplash",
+	.remove		= drm_bootsplash_client_remove,
+	.hotplug	= drm_bootsplash_client_hotplug,
+};
+
+static int drm_bootsplash_dev_notify(struct notifier_block *nb,
+				     unsigned long action, void *data)
+{
+	struct drm_device *dev = data;
+	struct drm_client_dev *client;
+	struct drm_bootsplash *splash;
+
+	if (!drm_bootsplash_enabled)
+		return 0;
+
+	splash = kzalloc(sizeof(*splash), GFP_KERNEL);
+	if (!splash)
+		return 0;
+
+	client = drm_client_new(dev, &drm_bootsplash_client_funcs);
+	if (IS_ERR(client)) {
+		DRM_DEV_ERROR(dev->dev, "Failed to create client, ret=%ld\n", PTR_ERR(client));
+		kfree(splash);
+		return 0;
+	}
+
+	INIT_WORK(&splash->worker, drm_bootsplash_worker);
+
+	splash->client = client;
+	client->private = splash;
+
+	/*
+	 * vc4 isn't done with it's setup when drm_dev_register() is called.
+	 * It should have shouldn't it?
+	 * So to keep it from crashing defer setup to hotplug...
+	 */
+	if (client->dev->mode_config.max_width)
+		drm_bootsplash_client_hotplug(client);
+
+	return 0;
+}
+
+static struct notifier_block drm_bootsplash_dev_notifier = {
+	.notifier_call	= drm_bootsplash_dev_notify,
+};
+
+void drm_bootsplash_register(void)
+{
+	register_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+
+	if (!drm_bootsplash_enabled)
+		return;
+
+	drm_dev_register_notifier(&drm_bootsplash_dev_notifier);
+}
+
+void drm_bootsplash_unregister(void)
+{
+	drm_dev_unregister_notifier(&drm_bootsplash_dev_notifier);
+	unregister_keyboard_notifier(&drm_bootsplash_keyboard_notifier_block);
+}
diff --git a/drivers/gpu/drm/client/internal.h b/drivers/gpu/drm/client/internal.h
new file mode 100644
index 000000000000..22e2120c493b
--- /dev/null
+++ b/drivers/gpu/drm/client/internal.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _DRM_CLIENT_INTERNAL_H_
+#define _DRM_CLIENT_INTERNAL_H_
+
+#ifdef CONFIG_DRM_CLIENT_BOOTSPLASH
+void drm_bootsplash_register(void);
+void drm_bootsplash_unregister(void);
+#else
+static inline void drm_bootsplash_register(void)
+{
+}
+
+static inline void drm_bootsplash_unregister(void)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 760f1795f812..cd8c084c8801 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -24,6 +24,7 @@
 
 #include "drm_crtc_internal.h"
 #include "drm_internal.h"
+#include "client/internal.h"
 
 struct drm_client_display_offset {
 	int x, y;
@@ -234,10 +235,13 @@ EXPORT_SYMBOL(drm_client_remove_defer);
 
 void drm_client_init(void)
 {
+	drm_bootsplash_register();
 }
 
 void drm_client_exit(void)
 {
+	drm_bootsplash_unregister();
+
 	flush_work(&drm_client_remove_defer_work);
 }
 
-- 
2.15.1

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

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

* [RFC v4 25/25] drm/client: Hack: Add DRM VT console client
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (23 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 24/25] drm/client: Hack: Add bootsplash Noralf Trønnes
@ 2018-04-14 11:53 ` Noralf Trønnes
  2018-04-16  8:21 ` [RFC v4 00/25] drm: Add generic fbdev emulation Daniel Vetter
  25 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-14 11:53 UTC (permalink / raw)
  To: dri-devel; +Cc: intel-gfx

A hack to test the client API.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/Makefile           |   1 +
 drivers/gpu/drm/client/Kconfig     |   5 +
 drivers/gpu/drm/client/Makefile    |   3 +
 drivers/gpu/drm/client/drm_vtcon.c | 785 +++++++++++++++++++++++++++++++++++++
 4 files changed, 794 insertions(+)
 create mode 100644 drivers/gpu/drm/client/Makefile
 create mode 100644 drivers/gpu/drm/client/drm_vtcon.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 388527093f80..ea63eb9e93ec 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 obj-$(CONFIG_DRM_DEBUG_MM_SELFTEST) += selftests/
 
 obj-$(CONFIG_DRM)	+= drm.o
+obj-y			+= client/
 obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
 obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
 obj-$(CONFIG_DRM_ARM)	+= arm/
diff --git a/drivers/gpu/drm/client/Kconfig b/drivers/gpu/drm/client/Kconfig
index 6b01f2e51fb3..b03f3baf8b3f 100644
--- a/drivers/gpu/drm/client/Kconfig
+++ b/drivers/gpu/drm/client/Kconfig
@@ -6,4 +6,9 @@ config DRM_CLIENT_BOOTSPLASH
 	help
 	  DRM Bootsplash
 
+config DRM_CLIENT_VTCON
+	tristate "DRM VT console"
+	help
+	  DRM VT console
+
 endmenu
diff --git a/drivers/gpu/drm/client/Makefile b/drivers/gpu/drm/client/Makefile
new file mode 100644
index 000000000000..7d39f1bc2b68
--- /dev/null
+++ b/drivers/gpu/drm/client/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DRM_CLIENT_VTCON) += drm_vtcon.o
diff --git a/drivers/gpu/drm/client/drm_vtcon.c b/drivers/gpu/drm/client/drm_vtcon.c
new file mode 100644
index 000000000000..910b4ec1a686
--- /dev/null
+++ b/drivers/gpu/drm/client/drm_vtcon.c
@@ -0,0 +1,785 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright 2018 Noralf Trønnes
+
+#include <linux/console.h>
+#include <linux/font.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vt_buffer.h>
+#include <linux/vt_kern.h>
+#include <linux/workqueue.h>
+
+#include <drm/drm_client.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_print.h>
+
+/* TODO: Scrolling */
+
+/*
+ * The code consists of 3 parts:
+ *
+ * 1. The DRM client
+ *    Gets a display, uses the first mode to find a font,
+ *    sets the max cols/rows and a matching text buffer.
+ *
+ * 2. The VT console
+ *    Writes to the text buffer which consists of CGA colored characters.
+ *    Schedules the worker when it needs rendering or blanking.
+ *
+ * 3. Worker
+ *    Does modesetting, blanking and rendering.
+ *    It takes a snapshot of the VT text buffer and renders the changes since
+ *    last.
+ */
+
+struct drm_vtcon_vc {
+	struct mutex lock;
+
+	u16 *text_buf;
+	size_t buf_len;
+
+	unsigned int rows;
+	unsigned int cols;
+	unsigned int max_rows;
+	unsigned int max_cols;
+	const struct font_desc *font;
+	bool blank;
+	unsigned long cursor_blink_jiffies;
+};
+
+static struct drm_vtcon_vc *drm_vtcon_vc;
+
+struct drm_vtcon {
+	struct drm_client_dev *client;
+	struct drm_client_display *display;
+	struct drm_client_buffer *buffer;
+
+	unsigned int rows;
+	unsigned int cols;
+
+	u16 *text_buf[2];
+	size_t buf_len;
+	unsigned int buf_idx;
+	bool blank;
+};
+
+static struct drm_vtcon *vtcon_instance;
+
+static int drm_vtcon_dev_id;
+module_param_named(dev, drm_vtcon_dev_id, int, 0600);
+MODULE_PARM_DESC(drm_vtcon_dev_id, "DRM device id [default=0]");
+
+#define drm_vtcon_debug(vc, fmt, ...) \
+	pr_debug("%s[%u]: " fmt, __func__, vc->vc_num, ##__VA_ARGS__)
+
+/* CGA color palette: 4-bit RGBI: intense red green blue */
+static const u32 drm_vtcon_paletteX888[16] = {
+	0x00000000, /*  0 black */
+	0x000000aa, /*  1 blue */
+	0x0000aa00, /*  2 green */
+	0x0000aaaa, /*  3 cyan */
+	0x00aa0000, /*  4 red */
+	0x00aa00aa, /*  5 magenta */
+	0x00aa5500, /*  6 brown */
+	0x00aaaaaa, /*  7 light gray */
+	0x00555555, /*  8 dark gray */
+	0x005555ff, /*  9 bright blue */
+	0x0055ff55, /* 10 bright green */
+	0x0055ffff, /* 11 bright cyan */
+	0x00ff5555, /* 12 bright red */
+	0x00ff55ff, /* 13 bright magenta */
+	0x00ffff55, /* 14 yellow */
+	0x00ffffff  /* 15 white */
+};
+
+static void
+drm_vtcon_render_char(struct drm_vtcon *vtcon, unsigned int x, unsigned int y,
+		      u16 cc, const struct font_desc *font)
+{
+	struct drm_client_buffer *buffer = vtcon->buffer;
+	unsigned int h, w;
+	const u8 *src;
+	void *dst;
+	u32 *pix;
+	u32 fg_col = drm_vtcon_paletteX888[(cc & 0x0f00) >> 8];
+	u32 bg_col = drm_vtcon_paletteX888[cc >> 12];
+
+	src = font->data + (cc & 0xff) * font->height;
+	dst = vtcon->buffer->vaddr + y * buffer->pitch + x * sizeof(u32);
+
+	for (h = 0; h < font->height; h++) {
+		u8 fontline = *(src + h);
+
+		pix = dst;
+		for (w = 0; w < font->width; w++)
+			pix[w] = fontline & BIT(7 - w) ? fg_col : bg_col;
+		dst += buffer->pitch;
+	}
+}
+
+static int drm_vtcon_modeset(struct drm_vtcon *vtcon, unsigned int cols,
+			     unsigned int rows, const struct font_desc *font)
+{
+	struct drm_client_display *display = vtcon->display;
+	struct drm_client_dev *client = vtcon->client;
+	struct drm_display_mode *mode, *best_mode = NULL;
+	unsigned int best_cols = ~0, best_rows = ~0;
+	struct drm_client_buffer *buffer;
+	int ret;
+
+	DRM_DEV_INFO(client->dev->dev, "IN %ux%u\n", cols, rows);
+
+	/* Find the smallest mode that fits */
+	drm_client_display_for_each_mode(mode, display) {
+		unsigned int mode_cols = mode->hdisplay / font->width;
+		unsigned int mode_rows = mode->vdisplay / font->height;
+
+		DRM_DEV_INFO(client->dev->dev,
+			     "try: %ux%u\n", mode_cols, mode_rows);
+
+		if (mode_cols < cols || mode_rows < rows)
+			break;
+
+		if (mode_cols >= best_cols || mode_rows >= best_rows)
+			continue;
+
+		best_cols = mode_cols;
+		best_rows = mode_rows;
+		best_mode = mode;
+	}
+
+	if (!best_mode) {
+		DRM_DEV_INFO(client->dev->dev, "Couldn't find mode for %ux%u\n", cols, rows);
+		return -EINVAL;
+	}
+
+	DRM_DEV_INFO(client->dev->dev, "Chosen: %ux%u\n", best_cols, best_rows);
+
+	buffer = drm_client_framebuffer_create(client, best_mode, DRM_FORMAT_XRGB8888);
+	if (IS_ERR(buffer)) {
+		ret = PTR_ERR(buffer);
+		DRM_DEV_ERROR(client->dev->dev,
+			      "Failed to create framebuffer: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_client_display_commit(display, buffer->fb, best_mode);
+	if (ret) {
+		DRM_DEV_ERROR(client->dev->dev,
+			      "Failed to commit mode: %d\n", ret);
+		goto err_free_buffer;
+	}
+
+	drm_client_framebuffer_delete(vtcon->buffer);
+
+	vtcon->buffer = buffer;
+	vtcon->cols = cols;
+	vtcon->rows = rows;
+
+	DRM_DEV_INFO(client->dev->dev, "OUT\n");
+
+	return 0;
+
+err_free_buffer:
+	drm_client_framebuffer_delete(buffer);
+
+	DRM_DEV_INFO(client->dev->dev, "OUT ret=%d\n", ret);
+
+	return ret;
+}
+
+static void drm_vtcon_blank(struct drm_vtcon *vtcon, bool blank)
+{
+	int mode = blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON;
+
+	drm_client_display_dpms(vtcon->display, mode);
+	vtcon->blank = blank;
+}
+
+static int drm_vtcon_resize_buf(struct drm_vtcon *vtcon, size_t len)
+{
+	u16 *text_buf[2];
+
+	text_buf[0] = kzalloc(len, GFP_KERNEL);
+	text_buf[1] = kzalloc(len, GFP_KERNEL);
+	if (!text_buf[0] || !text_buf[1]) {
+		kfree(text_buf[0]);
+		kfree(text_buf[1]);
+		return -ENOMEM;
+	}
+
+	kfree(vtcon->text_buf[0]);
+	kfree(vtcon->text_buf[1]);
+
+	vtcon->text_buf[0] = text_buf[0];
+	vtcon->text_buf[1] = text_buf[1];
+	vtcon->buf_len = len;
+
+	return 0;
+}
+
+static void drm_vtcon_work_fn(struct work_struct *work)
+{
+	struct drm_vtcon *vtcon = vtcon_instance;
+	unsigned int vc_cols, vc_rows, col, row, x, y;
+	const struct font_desc *font;
+	u16 prev, curr;
+	bool blank, render_all = false;
+	struct drm_clip_rect clip = {
+		.x1 = ~0,
+		.y1 = ~0,
+		.x2 = 0,
+		.y2 = 0,
+	};
+	char *str;
+	int ret;
+
+	if (!vtcon->display)
+		return;
+
+	mutex_lock(&drm_vtcon_vc->lock);
+
+	vc_cols = drm_vtcon_vc->cols;
+	vc_rows = drm_vtcon_vc->rows;
+	font = drm_vtcon_vc->font;
+	blank = drm_vtcon_vc->blank;
+
+	if (vtcon->buf_len != drm_vtcon_vc->buf_len) {
+		ret = drm_vtcon_resize_buf(vtcon, drm_vtcon_vc->buf_len);
+		if (ret) {
+			mutex_unlock(&drm_vtcon_vc->lock);
+			return;
+		}
+		render_all = true;
+	}
+
+	vtcon->buf_idx = !vtcon->buf_idx;
+	memcpy(vtcon->text_buf[vtcon->buf_idx], drm_vtcon_vc->text_buf,
+	       vc_cols * vc_rows * sizeof(u16));
+
+	mutex_unlock(&drm_vtcon_vc->lock);
+
+	if (vtcon->cols != vc_cols || vtcon->rows != vc_rows) {
+		ret = drm_vtcon_modeset(vtcon, vc_cols, vc_rows, font);
+		if (ret)
+			return;
+		render_all = true;
+	} else if (vtcon->blank != blank) {
+		drm_vtcon_blank(vtcon, blank);
+	}
+
+	str = kmalloc(vc_cols + 1, GFP_KERNEL);
+	if (!str)
+		return;
+
+	for (row = 0; row < vc_rows; row++) {
+		for (col = 0; col < vc_cols; col++) {
+			prev = vtcon->text_buf[!vtcon->buf_idx][col + (row * vc_cols)];
+			curr = vtcon->text_buf[vtcon->buf_idx][col + (row * vc_cols)];
+
+			if (render_all || prev != curr) {
+				str[col] = curr;
+				x = col * font->width;
+				y = row * font->height;
+
+				clip.x1 = min_t(u32, clip.x1, x);
+				clip.y1 = min_t(u32, clip.y1, y);
+				clip.x2 = max_t(u32, clip.x2, x + font->width);
+				clip.y2 = max_t(u32, clip.y2, y + font->height);
+
+				drm_vtcon_render_char(vtcon, x, y, curr, font);
+			} else {
+				str[col] = ' ';
+			}
+		}
+		str[vc_cols] = '\0';
+//		pr_info("%02u|%s\n", row, str);
+	}
+
+	kfree(str);
+
+	if (clip.x1 < clip.x2)
+		drm_client_framebuffer_flush(vtcon->buffer, &clip);
+}
+
+static DECLARE_WORK(drm_vtcon_work, drm_vtcon_work_fn);
+
+static const char *drm_vtcon_con_startup(void)
+{
+	return "drm-vt";
+}
+
+static void drm_vtcon_con_init(struct vc_data *vc, int init)
+{
+	drm_vtcon_debug(vc, "(init=%d) drm_vtcon_vc=%p\n", init, drm_vtcon_vc);
+
+	vc->vc_can_do_color = 1;
+
+	if (init) {
+		vc->vc_cols = drm_vtcon_vc->cols;
+		vc->vc_rows = drm_vtcon_vc->rows;
+	} else {
+		vc_resize(vc, drm_vtcon_vc->cols, drm_vtcon_vc->rows);
+	}
+}
+
+static void drm_vtcon_con_deinit(struct vc_data *vc)
+{
+	drm_vtcon_debug(vc, "\n");
+}
+
+static void drm_vtcon_con_putcs(struct vc_data *vc, const unsigned short *s,
+				int count, int y, int x)
+{
+	u16 *dest;
+
+	dest = &drm_vtcon_vc->text_buf[x + (y * drm_vtcon_vc->cols)];
+
+	for (; count > 0; count--)
+		scr_writew(scr_readw(s++), dest++);
+
+	schedule_work(&drm_vtcon_work);
+}
+
+static void drm_vtcon_con_putc(struct vc_data *vc, int ch, int y, int x)
+{
+	unsigned short chr;
+
+	scr_writew(ch, &chr);
+	drm_vtcon_con_putcs(vc, &chr, 1, y, x);
+}
+
+/* TODO: How do I actually test this? */
+static void drm_vtcon_con_clear(struct vc_data *vc, int y, int x,
+				int height, int width)
+{
+	drm_vtcon_debug(vc, "\n");
+
+	scr_memcpyw(drm_vtcon_vc->text_buf, (unsigned short *)vc->vc_pos,
+		    vc->vc_cols * vc->vc_rows);
+	schedule_work(&drm_vtcon_work);
+}
+
+static int drm_vtcon_con_switch(struct vc_data *vc)
+{
+	drm_vtcon_debug(vc, "%ux%u\n", vc->vc_cols, vc->vc_rows);
+
+	mutex_lock(&drm_vtcon_vc->lock);
+	drm_vtcon_vc->cols = vc->vc_cols;
+	drm_vtcon_vc->rows = vc->vc_rows;
+	mutex_unlock(&drm_vtcon_vc->lock);
+
+	return 1; /* redraw */
+}
+
+static int drm_vtcon_con_resize(struct vc_data *vc, unsigned int width,
+				unsigned int height, unsigned int user)
+{
+	int ret = 0;
+
+	drm_vtcon_debug(vc, "width=%u, height=%u, user=%u\n", width, height, user);
+
+	mutex_lock(&drm_vtcon_vc->lock);
+
+	if (width > drm_vtcon_vc->max_cols || height > drm_vtcon_vc->max_rows)
+		ret = -EINVAL;
+
+	mutex_unlock(&drm_vtcon_vc->lock);
+
+	drm_vtcon_debug(vc, "ret=%d\n", ret);
+
+	return ret;
+}
+
+static void drm_vtcon_con_set_palette(struct vc_data *vc,
+				      const unsigned char *table)
+{
+	drm_vtcon_debug(vc, "\n");
+}
+
+static int drm_vtcon_con_blank(struct vc_data *vc, int blank, int mode_switch)
+{
+	drm_vtcon_debug(vc, "(blank=%d, mode_switch=%d)\n", blank, mode_switch);
+
+	mutex_lock(&drm_vtcon_vc->lock);
+	drm_vtcon_vc->blank = blank;
+	mutex_unlock(&drm_vtcon_vc->lock);
+
+	schedule_work(&drm_vtcon_work);
+
+	return 0;
+}
+
+static void drm_vtcon_con_scrolldelta(struct vc_data *vc, int lines)
+{
+	drm_vtcon_debug(vc, "(lines=%d)\n", lines);
+}
+
+static void drm_vtcon_con_cursor_draw(bool show)
+{
+	static unsigned short set_chr, saved_chr;
+	static int prev_x, prev_y;
+	struct vc_data *vc = vc_cons[fg_console].d;
+	unsigned short *pos;
+
+	if (saved_chr) {
+		pos = &drm_vtcon_vc->text_buf[prev_x + (prev_y * drm_vtcon_vc->cols)];
+		if (*pos == set_chr)
+			*pos = saved_chr;
+		saved_chr = 0;
+	}
+
+	if (show) {
+		pos = &drm_vtcon_vc->text_buf[vc->vc_x + (vc->vc_y * drm_vtcon_vc->cols)];
+		*pos = scr_readw((u16 *)vc->vc_pos);
+		saved_chr = *pos;
+		set_chr = *pos & 0xff00;
+		set_chr |= '_';
+		*pos = set_chr;
+		prev_x = vc->vc_x;
+		prev_y = vc->vc_y;
+	}
+
+	schedule_work(&drm_vtcon_work);
+}
+
+static void drm_vtcon_con_cursor_timer_handler(struct timer_list *t)
+{
+	static bool show;
+
+	show = !show;
+	drm_vtcon_con_cursor_draw(show);
+	mod_timer(t, jiffies + drm_vtcon_vc->cursor_blink_jiffies);
+}
+
+static DEFINE_TIMER(drm_vtcon_con_cursor_timer, drm_vtcon_con_cursor_timer_handler);
+
+static void drm_vtcon_con_cursor(struct vc_data *vc, int mode)
+{
+	//drm_vtcon_debug(vc, "(mode=%d)\n", mode);
+
+	switch (mode) {
+	case CM_ERASE:
+		drm_vtcon_con_cursor_draw(false);
+		del_timer_sync(&drm_vtcon_con_cursor_timer);
+		break;
+	case CM_MOVE:
+	case CM_DRAW:
+		drm_vtcon_vc->cursor_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+		mod_timer(&drm_vtcon_con_cursor_timer,
+			  jiffies + drm_vtcon_vc->cursor_blink_jiffies);
+		break;
+	}
+}
+
+static bool drm_vtcon_con_scroll(struct vc_data *vc, unsigned int top,
+				 unsigned int bottom, enum con_scroll dir,
+				 unsigned int lines)
+{
+	size_t count;
+
+	switch (dir) {
+	case SM_UP:
+		count = vc->vc_cols * (vc->vc_rows - lines);
+		memmove(drm_vtcon_vc->text_buf, drm_vtcon_vc->text_buf + vc->vc_cols, count * sizeof(u16));
+		memset(drm_vtcon_vc->text_buf + count, 0, vc->vc_cols * lines * sizeof(u16));
+		break;
+	case SM_DOWN:
+		drm_vtcon_debug(vc, "TODO\n");
+		break;
+	}
+
+	return false;
+}
+
+static const struct consw drm_vtcon_consw = {
+	/* owner is not set, it blocks module unload */
+	.con_startup		= drm_vtcon_con_startup,
+	.con_init		= drm_vtcon_con_init,
+	.con_deinit		= drm_vtcon_con_deinit,
+	.con_clear		= drm_vtcon_con_clear,
+	.con_putc		= drm_vtcon_con_putc,
+	.con_putcs		= drm_vtcon_con_putcs,
+	.con_cursor		= drm_vtcon_con_cursor,
+	.con_scroll		= drm_vtcon_con_scroll,
+	.con_switch		= drm_vtcon_con_switch,
+	.con_blank		= drm_vtcon_con_blank,
+	.con_resize		= drm_vtcon_con_resize,
+	.con_set_palette	= drm_vtcon_con_set_palette,
+	.con_scrolldelta	= drm_vtcon_con_scrolldelta,
+};
+
+static int drm_vtcon_vc_set_max(struct drm_display_mode *mode)
+{
+	u16 *new_buf = NULL, *old_buf = NULL;
+	const struct font_desc *font;
+	unsigned int cols, rows, i;
+	size_t buf_len;
+
+	/* only 8 bit wide and 8 or 16-bit high */
+	font = get_default_font(mode->hdisplay, mode->vdisplay,
+				BIT(8 - 1), BIT(8 - 1) | BIT(16 - 1));
+	if (!font)
+		return -ENODEV;
+
+	pr_info("%s: font: %s\n", __func__, font->name);
+
+	cols = mode->hdisplay / font->width;
+	rows = mode->vdisplay / font->height;
+
+	pr_info("%s: ASKED: cols=%u, rows=%u\n", __func__, cols, rows);
+
+	if (drm_vtcon_vc->max_cols == cols && drm_vtcon_vc->max_rows == rows &&
+	    drm_vtcon_vc->font == font)
+		return 0;
+
+	buf_len = cols * rows * sizeof(u16);
+	if (buf_len > drm_vtcon_vc->buf_len) {
+		new_buf = kzalloc(buf_len, GFP_KERNEL);
+		if (!new_buf)
+			return -ENOMEM;
+	}
+
+	mutex_lock(&drm_vtcon_vc->lock);
+
+	if (new_buf) {
+		DRM_INFO("Allocated new buf: buf_len=%zu\n", buf_len);
+		old_buf = drm_vtcon_vc->text_buf;
+		drm_vtcon_vc->text_buf = new_buf;
+		drm_vtcon_vc->buf_len = buf_len;
+	}
+
+	drm_vtcon_vc->max_cols = cols;
+	drm_vtcon_vc->max_rows = rows;
+	drm_vtcon_vc->font = font;
+
+	mutex_unlock(&drm_vtcon_vc->lock);
+
+	pr_info("%s: max_cols=%u, max_rows=%u\n", __func__, drm_vtcon_vc->max_cols,
+		drm_vtcon_vc->max_rows);
+
+	console_lock();
+	for (i = 0; i < 2; i++)
+		vc_resize(vc_cons[i].d, drm_vtcon_vc->max_cols,
+			  drm_vtcon_vc->max_rows);
+	console_unlock();
+
+	kfree(old_buf);
+
+	return 0;
+}
+
+static int drm_vtcon_setup_dev(struct drm_vtcon *vtcon)
+{
+	struct drm_client_dev *client = vtcon->client;
+	struct drm_client_display *display;
+	struct drm_display_mode *mode;
+	int ret;
+
+	display = drm_client_find_display(client->dev, 0, 0);
+	if (IS_ERR(display))
+		return PTR_ERR(display);
+	if (!display)
+		return -ENOENT;
+
+	mode = display->mode;
+	if (!mode) {
+		ret = -EINVAL;
+		goto err_free_display;
+	}
+
+	ret = drm_vtcon_vc_set_max(mode);
+	if (ret)
+		goto err_free_display;
+
+	pr_info("%s: cols=%u, rows=%u\n", __func__, drm_vtcon_vc->cols, drm_vtcon_vc->rows);
+
+	vtcon->display = display;
+
+	schedule_work(&drm_vtcon_work);
+
+	return 0;
+
+err_free_display:
+	drm_client_display_free(display);
+
+	return ret;
+}
+
+static int drm_vtcon_client_hotplug(struct drm_client_dev *client)
+{
+	struct drm_vtcon *vtcon = client->private;
+	int ret = 0;
+
+	if (!vtcon->display)
+		ret = drm_vtcon_setup_dev(vtcon);
+
+	return ret;
+}
+
+static struct drm_client_dev *vtcon_client;
+static DEFINE_MUTEX(vtcon_client_lock);
+
+static int drm_vtcon_client_remove(struct drm_client_dev *client)
+{
+	struct drm_vtcon *vtcon = client->private;
+	struct drm_client_display *display = vtcon->display;
+
+	mutex_lock(&vtcon_client_lock);
+
+	vtcon_client = NULL;
+
+	if (!display)
+		goto out_unlock;
+
+	vtcon->display = NULL;
+	flush_work(&drm_vtcon_work);
+	kfree(vtcon->text_buf[0]);
+	kfree(vtcon->text_buf[1]);
+	drm_client_framebuffer_delete(vtcon->buffer);
+	vtcon->buffer = NULL;
+	drm_client_display_free(display);
+
+out_unlock:
+	mutex_unlock(&vtcon_client_lock);
+
+	return 0;
+}
+
+static const struct drm_client_funcs drm_vtcon_client_funcs = {
+	.name		= "vtcon",
+	.remove		= drm_vtcon_client_remove,
+	.hotplug	= drm_vtcon_client_hotplug,
+};
+
+static struct drm_client_dev *drm_vtcon_client_new(unsigned int dev_id)
+{
+	struct drm_vtcon *vtcon = vtcon_instance;
+	struct drm_client_dev *client;
+
+	if (vtcon->client)
+		return ERR_PTR(-EBUSY);
+
+	client = drm_client_new_from_id(dev_id, &drm_vtcon_client_funcs);
+	if (IS_ERR(client))
+		return client;
+
+	vtcon->client = client;
+	client->private = vtcon;
+
+	/*
+	 * vc4 isn't done with it's setup when drm_dev_register() is called.
+	 * It should have shouldn't it?
+	 * So to keep it from crashing defer setup to hotplug...
+	 */
+	if (client->dev->mode_config.max_width)
+		drm_vtcon_client_hotplug(client);
+
+	return 0;
+}
+
+static void drm_vtcon_teardown(void)
+{
+	struct drm_vtcon *vtcon = vtcon_instance;
+
+	if (!drm_vtcon_vc)
+		return;
+
+	kfree(drm_vtcon_vc->text_buf);
+	mutex_destroy(&drm_vtcon_vc->lock);
+	kfree(drm_vtcon_vc);
+	kfree(vtcon);
+}
+
+static int __init drm_vtcon_setup(void)
+{
+	struct drm_vtcon *vtcon;
+
+	drm_vtcon_vc = kzalloc(sizeof(*drm_vtcon_vc), GFP_KERNEL);
+	vtcon = kzalloc(sizeof(*vtcon), GFP_KERNEL);
+	if (!drm_vtcon_vc || !vtcon)
+		goto err_free;
+
+	drm_vtcon_vc->max_cols = 80;
+	drm_vtcon_vc->max_rows = 25;
+	drm_vtcon_vc->cols = drm_vtcon_vc->max_cols;
+	drm_vtcon_vc->rows = drm_vtcon_vc->max_rows;
+	pr_info("%s: cols=%u, rows=%u\n", __func__, drm_vtcon_vc->cols, drm_vtcon_vc->rows);
+
+	drm_vtcon_vc->buf_len = drm_vtcon_vc->max_cols * drm_vtcon_vc->max_rows * sizeof(u16);
+	drm_vtcon_vc->text_buf = kzalloc(drm_vtcon_vc->buf_len, GFP_KERNEL);
+	if (!drm_vtcon_vc->text_buf)
+		goto err_free;
+
+	mutex_init(&drm_vtcon_vc->lock);
+	vtcon_instance = vtcon;
+
+	return 0;
+
+err_free:
+	kfree(drm_vtcon_vc);
+	kfree(vtcon);
+
+	return -ENOMEM;
+}
+
+static int __init drm_vtcon_module_init(void)
+{
+	int ret;
+
+	if (drm_vtcon_dev_id < 0)
+		return 0;
+
+	ret = drm_vtcon_setup();
+	if (ret)
+		return ret;
+
+	vtcon_client = drm_vtcon_client_new(drm_vtcon_dev_id);
+	if (IS_ERR(vtcon_client)) {
+		ret = PTR_ERR(vtcon_client);
+		drm_vtcon_dev_id = ret;
+		goto err_free;
+	}
+
+	console_lock();
+	ret = do_take_over_console(&drm_vtcon_consw, 0, 1, 0);
+	console_unlock();
+	if (ret)
+		goto err_remove;
+
+	return 0;
+
+err_remove:
+	drm_client_remove(vtcon_client);
+err_free:
+	drm_vtcon_teardown();
+
+	return ret;
+}
+module_init(drm_vtcon_module_init);
+
+static void __exit drm_vtcon_module_exit(void)
+{
+	if (drm_vtcon_dev_id < 0)
+		return;
+
+	mutex_lock(&vtcon_client_lock);
+	drm_client_remove(vtcon_client);
+	mutex_unlock(&vtcon_client_lock);
+
+	console_lock();
+	do_unbind_con_driver(&drm_vtcon_consw, 0, 1, 0);
+	do_unregister_con_driver(&drm_vtcon_consw);
+	console_unlock();
+
+	del_timer_sync(&drm_vtcon_con_cursor_timer);
+	flush_work(&drm_vtcon_work);
+	drm_vtcon_teardown();
+}
+module_exit(drm_vtcon_module_exit);
+
+MODULE_LICENSE("GPL");
-- 
2.15.1

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

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

* Re: [RFC v4 00/25] drm: Add generic fbdev emulation
  2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
                   ` (24 preceding siblings ...)
  2018-04-14 11:53 ` [RFC v4 25/25] drm/client: Hack: Add DRM VT console client Noralf Trønnes
@ 2018-04-16  8:21 ` Daniel Vetter
  2018-04-16 18:49   ` Noralf Trønnes
  25 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:21 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:52:53PM +0200, Noralf Trønnes wrote:
> This patchset explores the possibility of having generic fbdev emulation
> in DRM for drivers that supports dumb buffers which they can export. An
> API is added to support in-kernel clients in general.
> 
> In this version I was able to reuse the modesetting code from
> drm_fb_helper in the client API. This avoids code duplication, carries
> over lessons learned and the modesetting code is bisectable. The
> downside is that it takes +10 patches to rip drm_fb_helper in two, so
> maybe it's not worth it wrt possible breakage and a challenging review.

So my idea wasn't to rip the fbdev helper in  half first (that's indeed a
lot of work). But start out right away with using every piece of the
drm_client infrastructure you're adding in the existing fbdev code.

That way there's not a huge patch series which just adds code, with no
users, but every step of the way and every addition is tested almost right
away. That makes more gradual merging also easier. The things I have in
mind here is the generic fb_probe, or the drm_client block/unblock masters
and all that stuff.

Then, once we've demonstrated all these auxiliary pieces necessary for
drm_client.c work, we can cut the fb-helper in half and move the modeset
code into the drm_client library.

I still prefer an even more gradual path like this compared to what you
have in your patch series, but I understand that's yet another huge
shuffle. And the current series seems like a good enough approach to get
to essentially the same place.

> Does the Intel CI test the fbdev emulation?

We have fbdev emulation enabled, and iirc there's even a few tests for
fbdev. Just booting it on 20+ machines is a lot of testing itsefl already.

> 
> Daniel had this concern with the previous version:
> 
>     The register/unregister model needs more thought. Allowing both clients
>     to register whenever they want to, and drm_device instances to come and
>     go is what fbcon has done, and the resulting locking is a horror show.
> 
>     I think if we require that all in-kernel drm_clients are registers when
>     loading drm.ko (and enabled/disabled only per module options and
>     Kconfig), then we can throw out all the locking. That avoids a lot of
>     the headaches.
> 
> I have solved this by adding a notifier that fires when a new DRM device
> is registered (I've removed the new() callback). Currently only
> bootsplash uses this. The fbdev client needs to be setup from the driver
> since it can't know on device registration if the driver will setup it's
> own fbdev emulation later and the vtcon client hooks up to a user
> provided device id.

Ugh, notifier is exactly what fbcon also uses. It just hides the locking
horror show slightly, but it's equally bad. I'm working on a multi-year
plan to rip out the fbcon notifier, please don't start another one. See

commit 6104c37094e729f3d4ce65797002112735d49cd1
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Tue Aug 1 17:32:07 2017 +0200

    fbcon: Make fbcon a built-time depency for fbdev

for full details.

> Since fbcon can't handle fb_open failing, the buffer has to be
> pre-allocated. Exporting a GEM buffer pins the driver module making it
> impossible to unload it.
> I have included 2 solutions to the problem:
> - sysfs file to remove/close clients: remove_internal_clients

This is the same thing that defacto happens already with fbcon: You have
to remove fbcon first (which holds a full ref on the fbdev, which prevents
the drm driver from unloading). I think explicitly asking for that
reference to disappear is ok.

It does mean everyone has to update their unload scripts, but oh well.

> - Change drm_gem_prime_export() so it doesn't pin on client buffers

The double-loop in that patch definitely doesn't cut it, but worst case I
think something like that could be made to work.

> If a dumb buffer is exported from a kernel thread (worker) context, the
> file descriptor isn't closed and I leak a reference so the buffer isn't
> freed. Please look at drm_client_buffer_create() in patch
> 'drm/client: Finish the in-kernel client API'.
> This is a blocker that needs a solution.

Hm, missed that in my first cursory read of the series, I'l take another
look.
-Daniel

> 
> 
> Noralf.
> 
> Changes since version 3:
> Client API changes:
> - Drop drm_client_register_funcs() which attached clients indirectly.
>   Let clients attach directly using drm_client_new{_from_id}(). Clients
>   that wants to attach to all devices must be linked into drm.ko and use
>   the DRM device notifier. This is done to avoid the lock/race
>   register/unregister hell we have with fbcon. (Daniel Vetter)
> - drm_client_display_restore() checks if there is a master and if so
>   returns -EBUSY. (Daniel Vetter)
> - Allocate drm_file up front instead of on-demand. Since fbdev can't do
>   on demand buffer allocation because of fbcon, there's no need for this.
> - Add sysfs file to remove clients
> - Don't pin driver module when exporting gem client buffers
> - Dropped page flip support since drm_fb_helper is now used for fbdev
>   emulation.
> 
> - The bootsplash client now switches over to fbdev on keypress.
> 
> Changes since version 2:
> - Don't set drm master for in-kernel clients. (Daniel Vetter)
> - Add in-kernel client API
> 
> Changes since version 1:
> - Don't add drm_fb_helper_fb_open() and drm_fb_helper_fb_release() to
>   DRM_FB_HELPER_DEFAULT_OPS(). (Fi.CI.STATIC)
>   The following uses that macro and sets fb_open/close: udlfb_ops,
>   amdgpufb_ops, drm_fb_helper_generic_fbdev_ops, nouveau_fbcon_ops,
>   nouveau_fbcon_sw_ops, radeonfb_ops.
>   This results in: warning: Initializer entry defined twice
> - Support CONFIG_DRM_KMS_HELPER=m (kbuild test robot)
>   ERROR: <function> [drivers/gpu/drm/drm_kms_helper.ko] undefined!
> - Drop buggy patch: (Chris Wilson)
>   drm/prime: Clear drm_gem_object->dma_buf on release
> - Defer buffer creation until fb_open.
> 
> 
> David Herrmann (1):
>   drm: provide management functions for drm_file
> 
> Noralf Trønnes (24):
>   drm/file: Don't set master on in-kernel clients
>   drm/fb-helper: No need to cache rotation and sw_rotations
>   drm/fb-helper: Remove drm_fb_helper_debug_enter/leave()
>   drm/fb-helper: dpms_legacy(): Only set on connectors in use
>   drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>   drm: Begin an API for in-kernel clients
>   drm/fb-helper: Use struct drm_client_display
>   drm/fb-helper: Move modeset commit code to drm_client
>   drm/connector: Add
>     drm_connector_has_preferred_mode/pick_cmdline_mode()
>   drm/connector: Add connector array functions
>   drm/i915: Add drm_driver->initial_client_display callback
>   drm/fb-helper: Remove struct drm_fb_helper_crtc
>   drm/fb-helper: Remove struct drm_fb_helper_connector
>   drm/fb-helper: Move modeset config code to drm_client
>   drm: Make ioctls available for in-kernel clients
>   drm/client: Bail out if there's a DRM master
>   drm/client: Make the display modes available to clients
>   drm/client: Finish the in-kernel client API
>   drm/prime: Don't pin module on export for in-kernel clients
>   drm/fb-helper: Add drm_fb_helper_fb_open/release()
>   drm/fb-helper: Add generic fbdev emulation
>   drm: Add DRM device registered notifier
>   drm/client: Hack: Add bootsplash
>   drm/client: Hack: Add DRM VT console client
> 
>  drivers/gpu/drm/Kconfig                 |    2 +
>  drivers/gpu/drm/Makefile                |    4 +-
>  drivers/gpu/drm/client/Kconfig          |   14 +
>  drivers/gpu/drm/client/Makefile         |    3 +
>  drivers/gpu/drm/client/drm_bootsplash.c |  248 ++++++
>  drivers/gpu/drm/client/drm_vtcon.c      |  785 +++++++++++++++++
>  drivers/gpu/drm/client/internal.h       |   19 +
>  drivers/gpu/drm/drm_atomic.c            |  168 ++++
>  drivers/gpu/drm/drm_atomic_helper.c     |  168 +---
>  drivers/gpu/drm/drm_auth.c              |   33 +
>  drivers/gpu/drm/drm_client.c            | 1448 +++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_connector.c         |  199 +++++
>  drivers/gpu/drm/drm_crtc_internal.h     |   18 +-
>  drivers/gpu/drm/drm_debugfs.c           |    7 +
>  drivers/gpu/drm/drm_drv.c               |   43 +
>  drivers/gpu/drm/drm_dumb_buffers.c      |   33 +-
>  drivers/gpu/drm/drm_fb_helper.c         | 1420 ++++++++----------------------
>  drivers/gpu/drm/drm_file.c              |  304 ++++---
>  drivers/gpu/drm/drm_framebuffer.c       |   50 +-
>  drivers/gpu/drm/drm_internal.h          |    7 +
>  drivers/gpu/drm/drm_ioc32.c             |    2 +-
>  drivers/gpu/drm/drm_ioctl.c             |    4 +-
>  drivers/gpu/drm/drm_prime.c             |   37 +-
>  drivers/gpu/drm/drm_probe_helper.c      |    3 +
>  drivers/gpu/drm/drm_sysfs.c             |   20 +
>  drivers/gpu/drm/i915/i915_drv.c         |    1 +
>  drivers/gpu/drm/i915/intel_drv.h        |   11 +
>  drivers/gpu/drm/i915/intel_fbdev.c      |  112 +--
>  include/drm/drm_atomic.h                |    5 +
>  include/drm/drm_atomic_helper.h         |    4 -
>  include/drm/drm_client.h                |  182 ++++
>  include/drm/drm_connector.h             |   11 +
>  include/drm/drm_device.h                |    4 +
>  include/drm/drm_drv.h                   |   25 +
>  include/drm/drm_fb_helper.h             |  126 ++-
>  35 files changed, 4007 insertions(+), 1513 deletions(-)
>  create mode 100644 drivers/gpu/drm/client/Kconfig
>  create mode 100644 drivers/gpu/drm/client/Makefile
>  create mode 100644 drivers/gpu/drm/client/drm_bootsplash.c
>  create mode 100644 drivers/gpu/drm/client/drm_vtcon.c
>  create mode 100644 drivers/gpu/drm/client/internal.h
>  create mode 100644 drivers/gpu/drm/drm_client.c
>  create mode 100644 include/drm/drm_client.h
> 
> --
> 2.15.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
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] 46+ messages in thread

* Re: [Intel-gfx] [RFC v4 19/25] drm/client: Finish the in-kernel client API
  2018-04-14 11:53 ` [RFC v4 19/25] drm/client: Finish the in-kernel client API Noralf Trønnes
@ 2018-04-16  8:27   ` Daniel Vetter
  2018-04-16 15:58     ` Noralf Trønnes
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:27 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:12PM +0200, Noralf Trønnes wrote:
> The modesetting code is already present, this adds the rest of the API.

Mentioning the TODO in the commit message would be good. Helps readers
like me who have an attention span measured in seconds :-)

Just commenting on the create_buffer leak here

> +static struct drm_client_buffer *
> +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
> +{
> +	struct drm_mode_create_dumb dumb_args = { };
> +	struct drm_prime_handle prime_args = { };
> +	struct drm_client_buffer *buffer;
> +	struct dma_buf *dma_buf;
> +	void *vaddr;
> +	int ret;
> +
> +	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
> +	if (!buffer)
> +		return ERR_PTR(-ENOMEM);
> +
> +	buffer->client = client;
> +	buffer->width = width;
> +	buffer->height = height;
> +	buffer->format = format;
> +
> +	dumb_args.width = buffer->width;
> +	dumb_args.height = buffer->height;
> +	dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
> +	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
> +	if (ret)
> +		goto err_free;
> +
> +	buffer->handle = dumb_args.handle;
> +	buffer->pitch = dumb_args.pitch;
> +	buffer->size = dumb_args.size;
> +
> +	prime_args.handle = dumb_args.handle;
> +	ret = drm_prime_handle_to_fd(client->dev, &prime_args, client->file);
> +	if (ret)
> +		goto err_delete;
> +
> +	dma_buf = dma_buf_get(prime_args.fd);
> +	if (IS_ERR(dma_buf)) {
> +		ret = PTR_ERR(dma_buf);
> +		goto err_delete;
> +	}
> +
> +	/*
> +	 * If called from a worker the dmabuf fd isn't closed and the ref
> +	 * doesn't drop to zero on free.
> +	 * If I use __close_fd() it's all fine, but that function is not exported.
> +	 *
> +	 * How do I get rid of this fd when in a worker/kernel thread?
> +	 * The fd isn't used beyond this function.
> +	 */
> +//	WARN_ON(__close_fd(current->files, prime_args.fd));

Hm, this isn't 100% what I had in mind as the sequence for generic buffer
creation. Pseudo-code:

	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
	if (ret)
		goto err_free;
	
	gem_bo = drm_gem_object_lookup(client->file, dumb_args.handle);

gives you _really_ directly the underlying gem_bo. Of course this doesn't
work for non-gem based driver, but reality is that (almost) all of them
are. And we will not accept any new drivers which aren't gem based. So
ignoring vmwgfx for this drm_client work is imo perfectly fine. We should
ofc keep the option in the fb helpers to use non-gem buffers (so that
vmwgfx could switch over from their own in-driver fbdev helpers). All we
need for that is to keep the fb_probe callback.

Was there any other reason than vmwgfx for using prime buffers instead of
just directly using gem?

Cheers, Daniel
-- 
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] 46+ messages in thread

* Re: [RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
  2018-04-14 11:52 ` [RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
@ 2018-04-16  8:30   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:30 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:52:59PM +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.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_atomic.c        | 168 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_atomic_helper.c | 168 +-----------------------------------
>  drivers/gpu/drm/drm_fb_helper.c     |   8 +-
>  include/drm/drm_atomic.h            |   5 ++
>  include/drm/drm_atomic_helper.h     |   4 -
>  5 files changed, 179 insertions(+), 174 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 7d25c42f22db..1fb602b6c8b1 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -2060,6 +2060,174 @@ void drm_atomic_clean_old_fb(struct drm_device *dev,
>  }
>  EXPORT_SYMBOL(drm_atomic_clean_old_fb);
>  
> +/* just used from drm_client and atomic-helper: */

In that case please put the prototype for these into the internal header
drm_crtc_internal.h. Just to avoid drivers abusing this (they really
shouldn't).
-Daniel

> +int drm_atomic_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_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_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_set_config);
> +
>  /**
>   * DOC: explicit fencing properties
>   *
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index ee03c1ed2521..4f20eb58dd4f 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -2673,7 +2673,7 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane,
>  	if (plane_state->crtc && plane_state->crtc->cursor == plane)
>  		plane_state->state->legacy_cursor_update = true;
>  
> -	ret = __drm_atomic_helper_disable_plane(plane, plane_state);
> +	ret = drm_atomic_disable_plane(plane, plane_state);
>  	if (ret != 0)
>  		goto fail;
>  
> @@ -2684,95 +2684,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
> @@ -2801,7 +2712,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set,
>  		return -ENOMEM;
>  
>  	state->acquire_ctx = ctx;
> -	ret = __drm_atomic_helper_set_config(set, state);
> +	ret = drm_atomic_set_config(set, state);
>  	if (ret != 0)
>  		goto fail;
>  
> @@ -2817,81 +2728,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;
> -}
> -
>  static int __drm_atomic_helper_disable_all(struct drm_device *dev,
>  					   struct drm_modeset_acquire_ctx *ctx,
>  					   bool clean_old_fbs)
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index d0936671a9a6..2eef24db21f8 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -358,7 +358,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
>  		if (plane->type == DRM_PLANE_TYPE_PRIMARY)
>  			continue;
>  
> -		ret = __drm_atomic_helper_disable_plane(plane, plane_state);
> +		ret = drm_atomic_disable_plane(plane, plane_state);
>  		if (ret != 0)
>  			goto out_state;
>  	}
> @@ -374,13 +374,13 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool activ
>  			plane_state->rotation = rotation;
>  		}
>  
> -		ret = __drm_atomic_helper_set_config(mode_set, state);
> +		ret = drm_atomic_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
> +		 * drm_atomic_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;
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index a57a8aa90ffb..0b0827ff2169 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -604,6 +604,11 @@ drm_atomic_add_affected_planes(struct drm_atomic_state *state,
>  void
>  drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret);
>  
> +int drm_atomic_disable_plane(struct drm_plane *plane,
> +			     struct drm_plane_state *plane_state);
> +int drm_atomic_set_config(struct drm_mode_set *set,
> +			  struct drm_atomic_state *state);
> +
>  int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
>  int __must_check drm_atomic_commit(struct drm_atomic_state *state);
>  int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 26aaba58d6ce..8d88a8b2ad52 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -114,12 +114,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.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
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] 46+ messages in thread

* Re: [RFC v4 11/25] drm/connector: Add connector array functions
  2018-04-14 11:53 ` [RFC v4 11/25] drm/connector: Add connector array functions Noralf Trønnes
@ 2018-04-16  8:33   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:33 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:04PM +0200, Noralf Trønnes wrote:
> Add functions to deal with the registred connectors as an array:
> - drm_connector_get_all()
> - drm_connector_put_all()
> 
> And to get the enabled status of those connectors:
> drm_connector_get_enabled_status()
> 
> This is prep work to remove struct drm_fb_helper_connector.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_connector.c | 105 ++++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_connector.h     |   5 ++
>  2 files changed, 110 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index b9eb143d70fc..25c333c05a4e 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1854,3 +1854,108 @@ drm_connector_pick_cmdline_mode(struct drm_connector *connector)
>  	return mode;
>  }
>  EXPORT_SYMBOL(drm_connector_pick_cmdline_mode);
> +
> +/**
> + * drm_connector_get_all - Get all connectors into an array
> + * @dev: DRM device
> + * @connectors: Returned connector array
> + *
> + * This function iterates through all registered connectors and adds them to an
> + * array allocated by this function. A ref is taken on the connectors.
> + *
> + * Use drm_connector_put_all() to drop refs and free the array.
> + *
> + * Returns:
> + * Number of connectors or -ENOMEM on failure.
> + */
> +int drm_connector_get_all(struct drm_device *dev, struct drm_connector ***connectors)

I honestly don't like the fbdev pattern of having connector arrays all
that much. I think in a world of hotplug we should have as much code as
possible iterating over the life connector list using the special
functions.

Given that these functions here set a bit a bad example imo I'd drop them
and just live with the code duplication.
-Daniel

> +{
> +	struct drm_connector *connector, **temp, **conns = NULL;
> +	struct drm_connector_list_iter conn_iter;
> +	int connector_count = 0;
> +
> +	drm_connector_list_iter_begin(dev, &conn_iter);
> +	drm_for_each_connector_iter(connector, &conn_iter) {
> +		temp = krealloc(conns, (connector_count + 1) * sizeof(*conns), GFP_KERNEL);
> +		if (!temp)
> +			goto err_put_free;
> +
> +		conns = temp;
> +		conns[connector_count++] = connector;
> +		drm_connector_get(connector);
> +	}
> +	drm_connector_list_iter_end(&conn_iter);
> +
> +	*connectors = conns;
> +
> +	return connector_count;
> +
> +err_put_free:
> +	drm_connector_list_iter_end(&conn_iter);
> +	drm_connector_put_all(conns, connector_count);
> +
> +	return -ENOMEM;
> +}
> +EXPORT_SYMBOL(drm_connector_get_all);
> +
> +/**
> + * drm_connector_put_all - Put and free connector array
> + * @connectors: Array of connectors
> + * @connector_count: Number of connectors in the array (can be negative or zero)
> + *
> + * This function drops the ref on the connectors an frees the array.
> + */
> +void drm_connector_put_all(struct drm_connector **connectors, int connector_count)
> +{
> +	int i;
> +
> +	if (connector_count < 1)
> +		return;
> +
> +	for (i = 0; i < connector_count; i++)
> +		drm_connector_put(connectors[i]);
> +	kfree(connectors);
> +}
> +EXPORT_SYMBOL(drm_connector_put_all);
> +
> +/**
> + * drm_connector_get_enabled_status - Get enabled status on connectors
> + * @connectors: Array of connectors
> + * @connector_count: Number of connectors in the array
> + *
> + * This loops over the connector array and sets enabled if connector status is
> + * _connected_. If no connectors are connected, a new pass is done and
> + * connectors that are not _disconnected_ are set enabled.
> + *
> + * The caller is responsible for freeing the array using kfree().
> + *
> + * Returns:
> + * A boolean array of connector enabled statuses or NULL on allocation failure.
> + */
> +bool *drm_connector_get_enabled_status(struct drm_connector **connectors,
> +				       unsigned int connector_count)
> +{
> +	bool *enabled, any_enabled = false;
> +	unsigned int i;
> +
> +	enabled = kcalloc(connector_count, sizeof(*enabled), GFP_KERNEL);
> +	if (!enabled)
> +		return NULL;
> +
> +	for (i = 0; i < connector_count; i++) {
> +		if (connectors[i]->status == connector_status_connected) {
> +			enabled[i] = true;
> +			any_enabled = true;
> +		}
> +	}
> +
> +	if (any_enabled)
> +		return enabled;
> +
> +	for (i = 0; i < connector_count; i++)
> +		if (connectors[i]->status != connector_status_disconnected)
> +			enabled[i] = true;
> +
> +	return enabled;
> +}
> +EXPORT_SYMBOL(drm_connector_get_enabled_status);
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 9cb4ca42373c..c3556a5f40c9 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1169,4 +1169,9 @@ drm_connector_has_preferred_mode(struct drm_connector *connector,
>  struct drm_display_mode *
>  drm_connector_pick_cmdline_mode(struct drm_connector *connector);
>  
> +int drm_connector_get_all(struct drm_device *dev, struct drm_connector ***connectors);
> +void drm_connector_put_all(struct drm_connector **connectors, int connector_count);
> +bool *drm_connector_get_enabled_status(struct drm_connector **connectors,
> +				       unsigned int connector_count);
> +
>  #endif
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
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] 46+ messages in thread

* Re: [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback
  2018-04-14 11:53 ` [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
@ 2018-04-16  8:38   ` Daniel Vetter
  2019-03-01 11:46     ` [Intel-gfx] " Noralf Trønnes
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:38 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:05PM +0200, Noralf Trønnes wrote:
> As part of moving the modesetting code out of drm_fb_helper and into
> drm_client, the drm_fb_helper_funcs->initial_config callback needs to go.
> Replace it with a drm_driver->initial_client_display callback that can
> work for all in-kernel clients.
> 
> TODO:
> - Add a patch that moves the function out of intel_fbdev.c since it's not
>   fbdev specific anymore.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

So the reason we originally added this callback for i915 fast boot was
that there wasn't any atomic around yet. And it was all an experiment to
figure out how to best go about designing fastboot.

But now we have fbdev, and fastboot design is also pretty clear:

1. driver loads
2. driver reads out current hw state, reconstructs a full atomic state for
everything and stuffs it into connector/crtc/plane->state pointers.
3. fbdev and any other client read out current state (with some caveats)
and just take it over.

What non-fastboot drivers do:
1. drivers load
2. reset both hw and sw state to everything off.

Now the intel_fb_initial_config is all generic code really, and it will
neatly fall back to the default config if everything is off. This means we
could:
1. Move the intel_fb_initial_config into the fbdev helpers.
2. Nuke the ->initial_config callback.

And pronto! every driver which implements hw state readout will get fbdev
fastboot for free.

And since you've already rewritting the intel code to use drm_client, it's
practically done already. Just need to s/intel_/drm_fbdev_helper_ or
something like that :-)
-Daniel

> ---
>  drivers/gpu/drm/drm_fb_helper.c    |  19 +++++--
>  drivers/gpu/drm/i915/i915_drv.c    |   1 +
>  drivers/gpu/drm/i915/intel_drv.h   |  11 ++++
>  drivers/gpu/drm/i915/intel_fbdev.c | 113 ++++++++++++++++++-------------------
>  include/drm/drm_drv.h              |  21 +++++++
>  5 files changed, 104 insertions(+), 61 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index b992f59dad30..5407bf6dc8c0 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -2103,6 +2103,20 @@ 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);
>  
> +	mutex_lock(&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");
> +
> +	if (dev->driver->initial_client_display) {
> +		display = dev->driver->initial_client_display(dev, width, height);
> +		if (display) {
> +			drm_client_display_free(fb_helper->display);
> +			fb_helper->display = display;
> +			mutex_unlock(&dev->mode_config.mutex);
> +			return;
> +		}
> +	}
> +
>  	crtcs = kcalloc(fb_helper->connector_count,
>  			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
>  	modes = kcalloc(fb_helper->connector_count,
> @@ -2120,9 +2134,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  	if (IS_ERR(display))
>  		goto out;
>  
> -	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");
>  	drm_enable_connectors(fb_helper, enabled);
>  
>  	if (!(fb_helper->funcs->initial_config &&
> @@ -2144,7 +2155,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  
>  		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
>  	}
> -	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 */
> @@ -2182,6 +2192,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>  	drm_client_display_free(fb_helper->display);
>  	fb_helper->display = display;
>  out:
> +	mutex_unlock(&dev->mode_config.mutex);
>  	kfree(crtcs);
>  	kfree(modes);
>  	kfree(offsets);
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 07c07d55398b..b746c0cbaa4b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -2857,6 +2857,7 @@ static struct drm_driver driver = {
>  
>  	.dumb_create = i915_gem_dumb_create,
>  	.dumb_map_offset = i915_gem_mmap_gtt,
> +	.initial_client_display = i915_initial_client_display,
>  	.ioctls = i915_ioctls,
>  	.num_ioctls = ARRAY_SIZE(i915_ioctls),
>  	.fops = &i915_driver_fops,
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index d4368589b355..f77f510617c5 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1720,6 +1720,9 @@ extern void intel_fbdev_fini(struct drm_i915_private *dev_priv);
>  extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
>  extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
>  extern void intel_fbdev_restore_mode(struct drm_device *dev);
> +struct drm_client_display *
> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
> +			    unsigned int height);
>  #else
>  static inline int intel_fbdev_init(struct drm_device *dev)
>  {
> @@ -1749,6 +1752,14 @@ static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
>  static inline void intel_fbdev_restore_mode(struct drm_device *dev)
>  {
>  }
> +
> +static inline struct drm_client_display *
> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
> +			    unsigned int height)
> +{
> +	return NULL;
> +}
> +
>  #endif
>  
>  /* intel_fbc.c */
> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> index a4ab8575a72e..b7f44c9475a8 100644
> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> @@ -38,6 +38,7 @@
>  #include <linux/vga_switcheroo.h>
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_client.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_fb_helper.h>
>  #include "intel_drv.h"
> @@ -287,18 +288,6 @@ 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.
> @@ -326,44 +315,48 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
>   * 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_client_display *
> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
> +			    unsigned int height)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
> +	struct drm_i915_private *dev_priv = to_i915(dev);
>  	unsigned long conn_configured, conn_seq, mask;
> -	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
> -	int i, j;
> -	bool *save_enabled;
> -	bool fallback = true, ret = true;
> +	bool fallback = true, *enabled = NULL;
> +	struct drm_client_display *display;
> +	struct drm_connector **connectors;
> +	int i, connector_count;
> +	unsigned int count;
>  	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;
> +	display = drm_client_display_create(dev);
> +	if (IS_ERR(display))
> +		return NULL;
>  
>  	drm_modeset_acquire_init(&ctx, 0);
>  
> -	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
> +	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
>  		drm_modeset_backoff(&ctx);
>  
> -	memcpy(save_enabled, enabled, count);
> +	connector_count = drm_connector_get_all(dev, &connectors);
> +	if (connector_count < 1)
> +		goto bail;
> +
> +	enabled = drm_connector_get_enabled_status(connectors, connector_count);
> +	if (!enabled)
> +		goto bail;
> +
> +	count = min(connector_count, BITS_PER_LONG);
>  	mask = GENMASK(count - 1, 0);
>  	conn_configured = 0;
>  retry:
>  	conn_seq = conn_configured;
>  	for (i = 0; i < count; i++) {
> -		struct drm_fb_helper_connector *fb_conn;
> -		struct drm_connector *connector;
> +		struct drm_connector *connector = connectors[i];
> +		struct drm_display_mode *mode;
> +		struct drm_mode_set *modeset;
>  		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;
> @@ -402,16 +395,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>  
>  		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_client_display_for_each_modeset(modeset, display) {
> +			if (modeset->connectors[0] == connector) {
>  				DRM_DEBUG_KMS("fallback: cloned configuration\n");
>  				goto bail;
>  			}
> @@ -421,28 +411,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>  			      connector->name);
>  
>  		/* go for command line mode first */
> -		modes[i] = drm_connector_pick_cmdline_mode(connector);
> +		mode = drm_connector_pick_cmdline_mode(connector);
>  
>  		/* try for preferred next */
> -		if (!modes[i]) {
> +		if (!mode) {
>  			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);
> +			mode = 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)) {
> +		if (!mode && !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);
> +			mode = list_first_entry(&connector->modes,
> +						struct drm_display_mode, head);
>  		}
>  
>  		/* last resort: use current mode */
> -		if (!modes[i]) {
> +		if (!mode) {
>  			/*
>  			 * IMPORTANT: We want to use the adjusted mode (i.e.
>  			 * after the panel fitter upscaling) as the initial
> @@ -458,16 +446,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>  			 */
>  			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
>  				      connector->name);
> -			modes[i] = &connector->state->crtc->mode;
> +			mode = &connector->state->crtc->mode;
>  		}
> -		crtcs[i] = new_crtc;
> +
> +		modeset = drm_client_display_find_modeset(display, connector->state->crtc);
> +		if (WARN_ON(!modeset))
> +			goto bail;
> +
> +		modeset->mode = drm_mode_duplicate(dev, mode);
> +		drm_connector_get(connector);
> +		modeset->connectors[0] = connector;
> +		modeset->num_connectors = 1;
> +		modeset->x = 0;
> +		modeset->y = 0;
>  
>  		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" :"");
> +			      mode->hdisplay, mode->vdisplay,
> +			      mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
>  
>  		fallback = false;
>  		conn_configured |= BIT(i);
> @@ -492,19 +490,20 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>  	if (fallback) {
>  bail:
>  		DRM_DEBUG_KMS("Not using firmware configuration\n");
> -		memcpy(enabled, save_enabled, count);
> -		ret = false;
> +		drm_client_display_free(display);
> +		display = NULL;
>  	}
>  
>  	drm_modeset_drop_locks(&ctx);
>  	drm_modeset_acquire_fini(&ctx);
>  
> -	kfree(save_enabled);
> -	return ret;
> +	drm_connector_put_all(connectors, connector_count);
> +	kfree(enabled);
> +
> +	return display;
>  }
>  
>  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_drv.h b/include/drm/drm_drv.h
> index 7e545f5f94d3..13356e6fd40c 100644
> --- a/include/drm/drm_drv.h
> +++ b/include/drm/drm_drv.h
> @@ -32,6 +32,7 @@
>  
>  #include <drm/drm_device.h>
>  
> +struct drm_client_display;
>  struct drm_file;
>  struct drm_gem_object;
>  struct drm_master;
> @@ -553,6 +554,26 @@ struct drm_driver {
>  			    struct drm_device *dev,
>  			    uint32_t handle);
>  
> +	/**
> +	 * @initial_client_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.
> +	 */
> +	struct drm_client_display *(*initial_client_display)(struct drm_device *dev,
> +					unsigned int width, unsigned int height);
> +
>  	/**
>  	 * @gem_vm_ops: Driver private ops for this object
>  	 */
> -- 
> 2.15.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
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] 46+ messages in thread

* Re: [RFC v4 17/25] drm/client: Bail out if there's a DRM master
  2018-04-14 11:53 ` [RFC v4 17/25] drm/client: Bail out if there's a DRM master Noralf Trønnes
@ 2018-04-16  8:45   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:45 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:10PM +0200, Noralf Trønnes wrote:
> If there's a DRM master, return -EBUSY.
> Block userspace from becoming master by taking the master lock while
> the client is setting the mode.
> 
> Suggested-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_auth.c      | 33 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/drm_client.c    | 34 +++++++++++++++++++++++++++++-----
>  drivers/gpu/drm/drm_fb_helper.c |  8 ++++----
>  drivers/gpu/drm/drm_internal.h  |  2 ++
>  include/drm/drm_client.h        |  4 ++--
>  5 files changed, 70 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
> index d9c0f7573905..d656d0d93da3 100644
> --- a/drivers/gpu/drm/drm_auth.c
> +++ b/drivers/gpu/drm/drm_auth.c
> @@ -366,3 +366,36 @@ void drm_master_put(struct drm_master **master)
>  	*master = NULL;
>  }
>  EXPORT_SYMBOL(drm_master_put);
> +
> +/**
> + * drm_master_block - Block DRM master operations
> + * @dev: DRM device
> + *
> + * This function checks if there is a master on @dev. If there is no master it
> + * blocks anyone from becoming master. In-kernel clients can use this to know
> + * when they can act as master. Use drm_master_unblock() to unblock.
> + *
> + * Returns:
> + * True if there is no master, false otherwise.
> + */
> +bool drm_master_block(struct drm_device *dev)
> +{
> +	mutex_lock(&dev->master_mutex);
> +	if (dev->master) {
> +		mutex_unlock(&dev->master_mutex);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/**
> + * drm_master_unblock - Unblock DRM master operations
> + * @dev: DRM device
> + *
> + * Unblock and allow userspace to become master.
> + */
> +void drm_master_unblock(struct drm_device *dev)
> +{
> +	mutex_unlock(&dev->master_mutex);
> +}
> diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
> index 27818a467b09..764c556630b8 100644
> --- a/drivers/gpu/drm/drm_client.c
> +++ b/drivers/gpu/drm/drm_client.c
> @@ -18,6 +18,8 @@
>  #include <drm/drm_device.h>
>  #include <drm/drm_modes.h>
>  
> +#include "drm_internal.h"
> +
>  struct drm_client_display_offset {
>  	int x, y;
>  };
> @@ -313,18 +315,30 @@ static int drm_client_display_restore_legacy(struct drm_client_display *display)
>  /**
>   * drm_client_display_restore() - Restore client display
>   * @display: Client display
> + * @force: If true, restore even if there's a DRM master

This smells a bit like bad interface design. Essentially this is a "should
I lock or not" flag, and if locking should/needs to be done by at least
some callers, then all of them should do that.

To make sure no one screws up, you can add a

drm_client_masters_are_blocked()
{
	lockdep_assert_held(client->dev->master_lock);
}

helper and call it at all the places you really want to have all other
masters excluded.

And locking at the code, we really do want to pull the
master_block/unblock critical section all the way out, to make sure that
an fbdev action only ever works or doesn't do any kind of damage at all.
We really don't want another master to take over while fbdev emulation is
doing stuff - drm_client_master_block/unblock is meant to fix these races.
-Daniel

>   *
>   * Restore client display using the current modeset configuration.
>   *
>   * Return:
>   * Zero on succes or negative error code on failure.
>   */
> -int drm_client_display_restore(struct drm_client_display *display)
> +int drm_client_display_restore(struct drm_client_display *display, bool force)
>  {
> -	if (drm_drv_uses_atomic_modeset(display->dev))
> -		return drm_client_display_restore_atomic(display, true);
> +	struct drm_device *dev = display->dev;
> +	int ret;
> +
> +	if (!force && !drm_master_block(dev))
> +		return -EBUSY;
> +
> +	if (drm_drv_uses_atomic_modeset(dev))
> +		ret = drm_client_display_restore_atomic(display, true);
>  	else
> -		return drm_client_display_restore_legacy(display);
> +		ret = drm_client_display_restore_legacy(display);
> +
> +	if (!force)
> +		drm_master_unblock(dev);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(drm_client_display_restore);
>  
> @@ -354,13 +368,23 @@ static void drm_client_display_dpms_legacy(struct drm_client_display *display, i
>   * drm_client_display_dpms() - Set display DPMS mode
>   * @display: Client display
>   * @mode: DPMS mode
> + *
> + * Returns:
> + * Zero on success, -EBUSY if there's a DRM master.
>   */
> -void drm_client_display_dpms(struct drm_client_display *display, int mode)
> +int drm_client_display_dpms(struct drm_client_display *display, int mode)
>  {
> +	if (!drm_master_block(display->dev))
> +		return -EBUSY;
> +
>  	if (drm_drv_uses_atomic_modeset(display->dev))
>  		drm_client_display_restore_atomic(display, mode == DRM_MODE_DPMS_ON);
>  	else
>  		drm_client_display_dpms_legacy(display, mode);
> +
> +	drm_master_unblock(display->dev);
> +
> +	return 0;
>  }
>  EXPORT_SYMBOL(drm_client_display_dpms);
>  
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 01d8840930a3..98e5bc92c9f2 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -181,7 +181,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>  		return 0;
>  
>  	mutex_lock(&fb_helper->lock);
> -	ret = drm_client_display_restore(fb_helper->display);
> +	ret = drm_client_display_restore(fb_helper->display, false);
>  
>  	do_delayed = fb_helper->delayed_hotplug;
>  	if (do_delayed)
> @@ -243,7 +243,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
>  			continue;
>  
>  		mutex_lock(&helper->lock);
> -		ret = drm_client_display_restore(helper->display);
> +		ret = drm_client_display_restore(helper->display, true);
>  		if (ret)
>  			error = true;
>  		mutex_unlock(&helper->lock);
> @@ -1254,7 +1254,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
>  
>  	pan_set(fb_helper, var->xoffset, var->yoffset);
>  
> -	ret = drm_client_display_restore(fb_helper->display);
> +	ret = drm_client_display_restore(fb_helper->display, false);
>  	if (!ret) {
>  		info->var.xoffset = var->xoffset;
>  		info->var.yoffset = var->yoffset;
> @@ -1423,7 +1423,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 && !READ_ONCE(fb_helper->dev->master))
> -			drm_client_display_restore(fb_helper->display);
> +			drm_client_display_restore(fb_helper->display, false);
>  		return -EAGAIN;
>  	}
>  
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index 3f5d7706bcc9..f38dcaf139d7 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -92,6 +92,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_block(struct drm_device *dev);
> +void drm_master_unblock(struct drm_device *dev);
>  
>  /* drm_sysfs.c */
>  extern struct class *drm_class;
> diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
> index 27d2a46cd94a..3befd879a0b0 100644
> --- a/include/drm/drm_client.h
> +++ b/include/drm/drm_client.h
> @@ -46,8 +46,8 @@ drm_client_display_find_modeset(struct drm_client_display *display, struct drm_c
>  bool drm_client_display_panel_rotation(struct drm_connector *connector,
>  				       struct drm_plane *plane,
>  				       unsigned int *rotation);
> -int drm_client_display_restore(struct drm_client_display *display);
> -void drm_client_display_dpms(struct drm_client_display *display, int mode);
> +int drm_client_display_restore(struct drm_client_display *display, bool force);
> +int drm_client_display_dpms(struct drm_client_display *display, int mode);
>  struct drm_client_display *
>  drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height);
>  
> -- 
> 2.15.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
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] 46+ messages in thread

* Re: [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release()
  2018-04-14 11:53 ` [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release() Noralf Trønnes
@ 2018-04-16  8:46   ` Daniel Vetter
  2018-04-16 16:10     ` Noralf Trønnes
  0 siblings, 1 reply; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:46 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:14PM +0200, Noralf Trønnes wrote:
> These helpers keep track of fbdev users and drm_driver.last_close will
> only restore fbdev when actually in use. Additionally the display is
> turned off when the last user is closing. fbcon is a user in this context.
> 
> If struct fb_ops is defined in a library, fb_open() takes a ref on the
> library (fb_ops.owner) instead of the driver module. Fix that by ensuring
> that the driver module is pinned.
> 
> The functions are not added to the DRM_FB_HELPER_DEFAULT_OPS() macro,
> because some of its users do set fb_open/release themselves.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_fb_helper.c | 54 ++++++++++++++++++++++++++++++++++++++++-
>  include/drm/drm_fb_helper.h     | 29 ++++++++++++++++++++++
>  2 files changed, 82 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 98e5bc92c9f2..b1124c08b1ed 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -177,7 +177,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>  	if (!drm_fbdev_emulation || !fb_helper)
>  		return -ENODEV;
>  
> -	if (READ_ONCE(fb_helper->deferred_setup))
> +	if (READ_ONCE(fb_helper->deferred_setup) || !READ_ONCE(fb_helper->open_count))
>  		return 0;
>  
>  	mutex_lock(&fb_helper->lock);
> @@ -368,6 +368,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
>  	INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
>  	helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
>  	mutex_init(&helper->lock);
> +	helper->open_count = 1;
>  	helper->funcs = funcs;
>  	helper->dev = dev;
>  }
> @@ -620,6 +621,53 @@ int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
>  }
>  EXPORT_SYMBOL(drm_fb_helper_defio_init);
>  
> +/**
> + * drm_fb_helper_fb_open - implementation for &fb_ops.fb_open
> + * @info: fbdev registered by the helper
> + * @user: 1=userspace, 0=fbcon
> + *
> + * Increase fbdev use count.
> + * If &fb_ops is wrapped in a library, pin the driver module.
> + */
> +int drm_fb_helper_fb_open(struct fb_info *info, int user)
> +{
> +	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
> +
> +	if (info->fbops->owner != dev->driver->fops->owner) {
> +		if (!try_module_get(dev->driver->fops->owner))
> +			return -ENODEV;
> +	}
> +
> +	fb_helper->open_count++;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_fb_helper_fb_open);
> +
> +/**
> + * drm_fb_helper_fb_release - implementation for &fb_ops.fb_release
> + * @info: fbdev registered by the helper
> + * @user: 1=userspace, 0=fbcon
> + *
> + * Decrease fbdev use count and turn off if there are no users left.
> + * If &fb_ops is wrapped in a library, unpin the driver module.
> + */
> +int drm_fb_helper_fb_release(struct fb_info *info, int user)
> +{
> +	struct drm_fb_helper *fb_helper = info->par;
> +	struct drm_device *dev = fb_helper->dev;
> +
> +	if (!(--fb_helper->open_count))
> +		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
> +
> +	if (info->fbops->owner != dev->driver->fops->owner)
> +		module_put(dev->driver->fops->owner);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_fb_helper_fb_release);
> +
>  /**
>   * drm_fb_helper_sys_read - wrapper around fb_sys_read
>   * @info: fb_info struct pointer
> @@ -1436,6 +1484,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>  	if (ret < 0)
>  		return ret;
>  
> +	/* Block restore without users if we do track it */
> +	if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open)
> +		fb_helper->open_count = 0;

Since we kzcalloc, isn't this entirely redundant? Looks confusing to me at
least.

Otherwise looks all reasonable.
-Daniel


> +
>  	strcpy(fb_helper->fb->comm, "[fbcon]");
>  	return 0;
>  }
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 5f66f253a97b..330983975d5e 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -184,6 +184,22 @@ struct drm_fb_helper {
>  	 * See also: @deferred_setup
>  	 */
>  	int preferred_bpp;
> +
> +	/**
> +	 * @open_count:
> +	 *
> +	 * Keeps track of fbdev use to know when to not restore fbdev and to
> +	 * disable the pipeline when the last user is gone.
> +	 *
> +	 * Drivers that use drm_fb_helper_fb_open() as their \.fb_open
> +	 * callback will get an initial value of 0 and get restore based on
> +	 * actual use. Others will get an initial value of 1 which means that
> +	 * fbdev will always be restored. Drivers that call
> +	 * drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the
> +	 * initial value to 0 themselves in their &drm_fb_helper_funcs->fb_probe
> +	 * callback.
> +	 */
> +	unsigned int open_count;
>  };
>  
>  /**
> @@ -230,6 +246,9 @@ void drm_fb_helper_deferred_io(struct fb_info *info,
>  			       struct list_head *pagelist);
>  int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper);
>  
> +int drm_fb_helper_fb_open(struct fb_info *info, int user);
> +int drm_fb_helper_fb_release(struct fb_info *info, int user);
> +
>  ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
>  			       size_t count, loff_t *ppos);
>  ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> @@ -376,6 +395,16 @@ static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
>  	return -ENODEV;
>  }
>  
> +static inline int drm_fb_helper_fb_open(struct fb_info *info, int user)
> +{
> +	return -ENODEV;
> +}
> +
> +static inline int drm_fb_helper_fb_release(struct fb_info *info, int user)
> +{
> +	return -ENODEV;
> +}
> +
>  static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
>  					     char __user *buf, size_t count,
>  					     loff_t *ppos)
> -- 
> 2.15.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
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] 46+ messages in thread

* Re: [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation
  2018-04-14 11:53 ` [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
@ 2018-04-16  8:52   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  8:52 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:15PM +0200, Noralf Trønnes wrote:
> This adds generic fbdev emulation for drivers that supports
> dumb buffers which they can export.
> 
> All the driver has to do is call drm_fbdev_generic_setup().
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_fb_helper.c | 255 ++++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_fb_helper.h     |  20 ++++
>  2 files changed, 275 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index b1124c08b1ed..1954de5b13e0 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -30,6 +30,7 @@
>  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>  
>  #include <linux/console.h>
> +#include <linux/dma-buf.h>
>  #include <linux/kernel.h>
>  #include <linux/sysrq.h>
>  #include <linux/slab.h>
> @@ -1995,6 +1996,260 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev)
>  }
>  EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
>  
> +static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
> +{
> +	struct drm_fb_helper *fb_helper = info->par;
> +
> +	return dma_buf_mmap(fb_helper->buffer->dma_buf, vma, 0);
> +}
> +
> +/*
> + * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
> + * unregister_framebuffer() or fb_release().
> + */
> +static void drm_fbdev_fb_destroy(struct fb_info *info)
> +{
> +	struct drm_fb_helper *fb_helper = info->par;
> +	struct fb_ops *fbops = NULL;
> +
> +	DRM_DEBUG("\n");
> +
> +	if (fb_helper->fbdev->fbdefio)
> +		fbops = fb_helper->fbdev->fbops;
> +
> +	drm_fb_helper_fini(fb_helper);
> +	drm_client_framebuffer_delete(fb_helper->buffer);
> +	drm_client_free(fb_helper->client);
> +	kfree(fb_helper);
> +	kfree(fbops);
> +}
> +
> +static struct fb_ops drm_fbdev_fb_ops = {
> +	/*
> +	 * No need to set owner, this module is already pinned by the driver.
> +	 * A reference is taken on the driver module in drm_fb_helper_fb_open()
> +	 * to prevent the driver going away with open fd's.
> +	 */
> +	DRM_FB_HELPER_DEFAULT_OPS,
> +	.fb_open	= drm_fb_helper_fb_open,
> +	.fb_release	= drm_fb_helper_fb_release,
> +	.fb_destroy	= drm_fbdev_fb_destroy,
> +	.fb_mmap	= drm_fbdev_fb_mmap,
> +	.fb_read	= drm_fb_helper_sys_read,
> +	.fb_write	= drm_fb_helper_sys_write,
> +	.fb_fillrect	= drm_fb_helper_sys_fillrect,
> +	.fb_copyarea	= drm_fb_helper_sys_copyarea,
> +	.fb_imageblit	= drm_fb_helper_sys_imageblit,
> +};
> +
> +static struct fb_deferred_io drm_fbdev_defio = {
> +	.delay		= HZ / 20,
> +	.deferred_io	= drm_fb_helper_deferred_io,
> +};
> +
> +/* Hack to test tinydrm before converting to vmalloc buffers */
> +static int drm_fbdev_cma_deferred_io_mmap(struct fb_info *info,
> +					  struct vm_area_struct *vma)
> +{
> +	fb_deferred_io_mmap(info, vma);
> +	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
> +
> +	return 0;
> +}
> +
> +static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
> +				       struct drm_fb_helper_surface_size *sizes)
> +{
> +	struct drm_client_dev *client = fb_helper->client;
> +	struct drm_display_mode sizes_mode = {
> +		.hdisplay = sizes->surface_width,
> +		.vdisplay = sizes->surface_height,
> +	};
> +	struct drm_client_buffer *buffer;
> +	struct drm_framebuffer *fb;
> +	struct fb_info *fbi;
> +	u32 format;
> +	int ret;
> +
> +	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
> +		      sizes->surface_width, sizes->surface_height,
> +		      sizes->surface_bpp);
> +
> +	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
> +	buffer = drm_client_framebuffer_create(client, &sizes_mode, format);
> +	if (IS_ERR(buffer))
> +		return PTR_ERR(buffer);
> +
> +	fb_helper->buffer = buffer;
> +	fb_helper->fb = buffer->fb;
> +	fb = buffer->fb;
> +
> +	fbi = drm_fb_helper_alloc_fbi(fb_helper);
> +	if (IS_ERR(fbi)) {
> +		ret = PTR_ERR(fbi);
> +		goto err_free_buffer;
> +	}
> +
> +	fbi->par = fb_helper;
> +	fbi->fbops = &drm_fbdev_fb_ops;
> +	fbi->screen_size = fb->height * fb->pitches[0];
> +	fbi->fix.smem_len = fbi->screen_size;
> +	fbi->screen_buffer = buffer->vaddr;
> +	strcpy(fbi->fix.id, "DRM emulated");
> +
> +	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
> +	drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height);
> +
> +	/*
> +	 * Drivers that set the dirty callback:
> +	 * - Doesn't use defio:
> +	 *   i915, virtio, rockchip
> +	 * - defio with vmalloc buffer blitted on the real one:
> +	 *   vmwgfx
> +	 * - defio is disabled because it doesn't work with shmem:
> +	 *   udl
> +	 * - defio with special dirty callback for fbdev, uses vmalloc for fbdev:
> +	 *   qxl
> +	 * - defio with cma buffer, will move to vmalloc buffers:
> +	 *   tinydrm
> +	 *
> +	 * TODO:
> +	 * Maybe add vmalloc shadow buffer support.
> +	 */
> +
> +	if (fb->funcs->dirty) {
> +		struct fb_ops *fbops;
> +
> +		/*
> +		 * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per
> +		 * instance version is necessary.
> +		 */
> +		fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
> +		if (!fbops) {
> +			ret = -ENOMEM;
> +			goto err_fb_info_destroy;
> +		}
> +
> +		*fbops = *fbi->fbops;
> +		fbi->fbops = fbops;
> +
> +		fbi->fbdefio = &drm_fbdev_defio;
> +
> +		/* Hack so I can test with tinydrm */
> +		fbi->fix.smem_start = page_to_phys(virt_to_page(buffer->vaddr));
> +
> +		fb_deferred_io_init(fbi);
> +
> +		/* Hack so I can test with tinydrm */
> +		fbi->fbops->fb_mmap = drm_fbdev_cma_deferred_io_mmap;
> +	}
> +
> +	return 0;
> +
> +err_fb_info_destroy:
> +	drm_fb_helper_fini(fb_helper);
> +err_free_buffer:
> +	drm_client_framebuffer_delete(buffer);
> +
> +	return ret;
> +}

I'd split this patch into 2:

- First one just adds the generic_probe callback. We could then start
  rolling that one out to lots of drivers, which would give all this code
  lots of testing.

- Second part is the generic client stuff below. Again then with follow-up
  patches to roll it out.

This way we could achieve a slightly more gradual transition of drivers.
And the first step should only be replacing the fb_probe callback.
-Daniel


> +
> +static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
> +	.fb_probe = drm_fb_helper_generic_probe,
> +};
> +
> +static int drm_fbdev_client_remove(struct drm_client_dev *client)
> +{
> +	struct drm_fb_helper *fb_helper = client->private;
> +
> +	if (!fb_helper->fbdev) {
> +		kfree(fb_helper);
> +		return 0;
> +	}
> +
> +	unregister_framebuffer(fb_helper->fbdev);
> +
> +	/*
> +	 * If userspace is closed the client is now freed by
> +	 * drm_fbdev_fb_destroy(), otherwise it will be freed on the last close.
> +	 * Return 1 to tell that freeing is taken care of.
> +	 */
> +
> +	return 1;
> +}
> +
> +static int drm_fbdev_client_lastclose(struct drm_client_dev *client)
> +{
> +	struct drm_fb_helper *fb_helper = client->private;
> +
> +	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
> +
> +	return 0;
> +}
> +
> +static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
> +{
> +	struct drm_fb_helper *fb_helper = client->private;
> +
> +	if (fb_helper->fbdev)
> +		return 0;
> +
> +	return drm_fb_helper_fbdev_setup(client->dev, fb_helper,
> +					 &drm_fb_helper_generic_funcs,
> +					 fb_helper->preferred_bpp, 0);
> +}
> +
> +static const struct drm_client_funcs drm_fbdev_client_funcs = {
> +	.name		= "fbdev",
> +	.remove		= drm_fbdev_client_remove,
> +	.lastclose	= drm_fbdev_client_lastclose,
> +	.hotplug	= drm_fbdev_client_hotplug,
> +};
> +
> +/**
> + * drm_fb_helper_generic_fbdev_setup() - Setup generic fbdev emulation
> + * @dev: DRM device
> + * @preferred_bpp: Preferred bits per pixel for the device.
> + *                 @dev->mode_config.preferred_depth is used if this is zero.
> + *
> + * This function sets up generic fbdev emulation for drivers that supports
> + * dumb buffers which can be exported.
> + *
> + * Restore, hotplug events and teardown are all taken care of. Drivers that does
> + * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
> + * Simple drivers might use drm_mode_config_helper_suspend().
> + *
> + * Returns:
> + * Zero on success or negative error code on failure.
> + */
> +int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
> +{
> +	struct drm_fb_helper *fb_helper;
> +	struct drm_client_dev *client;
> +
> +	if (!drm_fbdev_emulation)
> +		return 0;
> +
> +	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
> +	if (!fb_helper)
> +		return -ENOMEM;
> +
> +	client = drm_client_new(dev, &drm_fbdev_client_funcs);
> +	if (IS_ERR(client)) {
> +		kfree(fb_helper);
> +		return PTR_ERR(client);
> +	}
> +
> +	client->private = fb_helper;
> +	fb_helper->client = client;
> +	fb_helper->preferred_bpp = preferred_bpp;
> +
> +	drm_fbdev_client_hotplug(client);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_fbdev_generic_setup);
> +
>  /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
>   * but the module doesn't depend on any fb console symbols.  At least
>   * attempt to load fbcon to avoid leaving the system without a usable console.
> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> index 330983975d5e..711da1747836 100644
> --- a/include/drm/drm_fb_helper.h
> +++ b/include/drm/drm_fb_helper.h
> @@ -126,6 +126,20 @@ struct drm_fb_helper {
>  	 */
>  	struct drm_client_display *display;
>  
> +	/**
> +	 * @client:
> +	 *
> +	 * DRM client used by the generic fbdev emulation.
> +	 */
> +	struct drm_client_dev *client;
> +
> +	/**
> +	 * @buffer:
> +	 *
> +	 * Framebuffer used by the generic fbdev emulation.
> +	 */
> +	struct drm_client_buffer *buffer;
> +
>  	const struct drm_fb_helper_funcs *funcs;
>  	struct fb_info *fbdev;
>  	u32 pseudo_palette[17];
> @@ -219,6 +233,7 @@ struct drm_fb_helper {
>  	.fb_ioctl	= drm_fb_helper_ioctl
>  
>  #ifdef CONFIG_DRM_FBDEV_EMULATION
> +int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp);
>  void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
>  			   const struct drm_fb_helper_funcs *funcs);
>  int drm_fb_helper_init(struct drm_device *dev,
> @@ -297,6 +312,11 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev);
>  void drm_fb_helper_lastclose(struct drm_device *dev);
>  void drm_fb_helper_output_poll_changed(struct drm_device *dev);
>  #else
> +static inline int
> +drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
> +{
> +}
> +
>  static inline void drm_fb_helper_prepare(struct drm_device *dev,
>  					struct drm_fb_helper *helper,
>  					const struct drm_fb_helper_funcs *funcs)
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
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] 46+ messages in thread

* Re: [RFC v4 16/25] drm: Make ioctls available for in-kernel clients
  2018-04-14 11:53 ` [RFC v4 16/25] drm: Make ioctls available for in-kernel clients Noralf Trønnes
@ 2018-04-16  9:04   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-16  9:04 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:09PM +0200, Noralf Trønnes wrote:
> Make ioctl wrappers for functions that will be used by the in-kernel API.
> The following functions are touched:
> - drm_mode_create_dumb_ioctl()
> - drm_mode_destroy_dumb_ioctl()
> - drm_mode_addfb2()
> - drm_mode_rmfb()
> - drm_prime_handle_to_fd_ioctl()
> 
> drm_mode_addfb2() also gets the ability to override the debug name.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  drivers/gpu/drm/drm_crtc_internal.h | 18 ++++++++++---
>  drivers/gpu/drm/drm_dumb_buffers.c  | 33 ++++++++++++++++--------
>  drivers/gpu/drm/drm_framebuffer.c   | 50 ++++++++++++++++++++++++-------------
>  drivers/gpu/drm/drm_internal.h      |  3 +++
>  drivers/gpu/drm/drm_ioc32.c         |  2 +-
>  drivers/gpu/drm/drm_ioctl.c         |  4 +--
>  drivers/gpu/drm/drm_prime.c         | 13 +++++++---
>  7 files changed, 84 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
> index 3c2b82865ad2..8f8886ac0e4d 100644
> --- a/drivers/gpu/drm/drm_crtc_internal.h
> +++ b/drivers/gpu/drm/drm_crtc_internal.h
> @@ -62,6 +62,12 @@ int drm_mode_getresources(struct drm_device *dev,
>  
>  
>  /* drm_dumb_buffers.c */
> +int drm_mode_create_dumb(struct drm_device *dev,
> +			 struct drm_mode_create_dumb *args,
> +			 struct drm_file *file_priv);
> +int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle,
> +			  struct drm_file *file_priv);
> +
>  /* IOCTLs */
>  int drm_mode_create_dumb_ioctl(struct drm_device *dev,
>  			       void *data, struct drm_file *file_priv);
> @@ -163,14 +169,18 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
>  				     const struct drm_framebuffer *fb);
>  void drm_fb_release(struct drm_file *file_priv);
>  
> +int drm_mode_addfb2(struct drm_device *dev, struct drm_mode_fb_cmd2 *r,
> +		    struct drm_file *file_priv, const char *comm);
> +int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
> +		  struct drm_file *file_priv);
>  
>  /* IOCTL */
>  int drm_mode_addfb(struct drm_device *dev,
>  		   void *data, struct drm_file *file_priv);
> -int drm_mode_addfb2(struct drm_device *dev,
> -		    void *data, struct drm_file *file_priv);
> -int drm_mode_rmfb(struct drm_device *dev,
> -		  void *data, struct drm_file *file_priv);
> +int drm_mode_addfb2_ioctl(struct drm_device *dev,
> +			  void *data, struct drm_file *file_priv);
> +int drm_mode_rmfb_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv);
>  int drm_mode_getfb(struct drm_device *dev,
>  		   void *data, struct drm_file *file_priv);
>  int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
> diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c
> index 39ac15ce4702..eed9687b8698 100644
> --- a/drivers/gpu/drm/drm_dumb_buffers.c
> +++ b/drivers/gpu/drm/drm_dumb_buffers.c
> @@ -53,10 +53,10 @@
>   * a hardware-specific ioctl to allocate suitable buffer objects.
>   */
>  
> -int drm_mode_create_dumb_ioctl(struct drm_device *dev,
> -			       void *data, struct drm_file *file_priv)
> +int drm_mode_create_dumb(struct drm_device *dev,
> +			 struct drm_mode_create_dumb *args,
> +			 struct drm_file *file_priv)
>  {
> -	struct drm_mode_create_dumb *args = data;
>  	u32 cpp, stride, size;
>  
>  	if (!dev->driver->dumb_create)
> @@ -91,6 +91,12 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
>  	return dev->driver->dumb_create(file_priv, dev, args);
>  }
>  
> +int drm_mode_create_dumb_ioctl(struct drm_device *dev,
> +			       void *data, struct drm_file *file_priv)
> +{
> +	return drm_mode_create_dumb(dev, data, file_priv);
> +}
> +
>  /**
>   * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
>   * @dev: DRM device
> @@ -122,17 +128,22 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
>  					       &args->offset);
>  }
>  
> +int drm_mode_destroy_dumb(struct drm_device *dev, u32 handle,
> +			  struct drm_file *file_priv)
> +{
> +	if (!dev->driver->dumb_create)
> +		return -ENOSYS;
> +
> +	if (dev->driver->dumb_destroy)
> +		return dev->driver->dumb_destroy(file_priv, dev, handle);
> +	else
> +		return drm_gem_dumb_destroy(file_priv, dev, handle);
> +}
> +
>  int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
>  				void *data, struct drm_file *file_priv)
>  {
>  	struct drm_mode_destroy_dumb *args = data;
>  
> -	if (!dev->driver->dumb_create)
> -		return -ENOSYS;
> -
> -	if (dev->driver->dumb_destroy)
> -		return dev->driver->dumb_destroy(file_priv, dev, args->handle);
> -	else
> -		return drm_gem_dumb_destroy(file_priv, dev, args->handle);
> +	return drm_mode_destroy_dumb(dev, args->handle, file_priv);
>  }
> -
> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
> index 8c4d32adcc17..16769e4db5c0 100644
> --- a/drivers/gpu/drm/drm_framebuffer.c
> +++ b/drivers/gpu/drm/drm_framebuffer.c
> @@ -125,7 +125,7 @@ int drm_mode_addfb(struct drm_device *dev,
>  	    dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP)
>  		r.pixel_format = DRM_FORMAT_XBGR2101010;
>  
> -	ret = drm_mode_addfb2(dev, &r, file_priv);
> +	ret = drm_mode_addfb2_ioctl(dev, &r, file_priv);
>  	if (ret)
>  		return ret;
>  
> @@ -310,23 +310,23 @@ drm_internal_framebuffer_create(struct drm_device *dev,
>  
>  /**
>   * drm_mode_addfb2 - add an FB to the graphics configuration
> - * @dev: drm device for the ioctl
> - * @data: data pointer for the ioctl
> - * @file_priv: drm file for the ioctl call
> + * @dev: drm device
> + * @r: pointer to request structure
> + * @file_priv: drm file
> + * @comm: optionally override the allocator name used for debug output
>   *
>   * Add a new FB to the specified CRTC, given a user request with format. This is
>   * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
>   * and uses fourcc codes as pixel format specifiers.
>   *
> - * Called by the user via ioctl.
> + * Called by the user via ioctl, or by an in-kernel client.
>   *
>   * Returns:
>   * Zero on success, negative errno on failure.
>   */
> -int drm_mode_addfb2(struct drm_device *dev,
> -		    void *data, struct drm_file *file_priv)
> +int drm_mode_addfb2(struct drm_device *dev, struct drm_mode_fb_cmd2 *r,
> +		    struct drm_file *file_priv, const char *comm)

API bikeshed: I'd drop the 2 (it's not relevant for in-kernel users), and
maybe return the handle right away to avoid callers having to do silly
stuff? If the return value is 0, then something failed.

Could even make @r const, if we do a quick on-stack copy to reinforce that
idea.

But feel free to ignore, probably not making things better here :-)

>  {
> -	struct drm_mode_fb_cmd2 *r = data;
>  	struct drm_framebuffer *fb;
>  
>  	if (!drm_core_check_feature(dev, DRIVER_MODESET))
> @@ -336,6 +336,9 @@ int drm_mode_addfb2(struct drm_device *dev,
>  	if (IS_ERR(fb))
>  		return PTR_ERR(fb);
>  
> +	if (comm)
> +		strscpy(fb->comm, comm, TASK_COMM_LEN);
> +
>  	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
>  	r->fb_id = fb->base.id;
>  
> @@ -347,6 +350,12 @@ int drm_mode_addfb2(struct drm_device *dev,
>  	return 0;
>  }
>  
> +int drm_mode_addfb2_ioctl(struct drm_device *dev,
> +			  void *data, struct drm_file *file_priv)
> +{
> +	return drm_mode_addfb2(dev, data, file_priv, NULL);
> +}
> +
>  struct drm_mode_rmfb_work {
>  	struct work_struct work;
>  	struct list_head fbs;
> @@ -367,29 +376,28 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w)
>  
>  /**
>   * drm_mode_rmfb - remove an FB from the configuration
> - * @dev: drm device for the ioctl
> - * @data: data pointer for the ioctl
> - * @file_priv: drm file for the ioctl call
> + * @dev: drm device
> + * @fb_id: id of framebuffer to remove
> + * @file_priv: drm file
>   *
> - * Remove the FB specified by the user.
> + * Remove the specified FB.
>   *
> - * Called by the user via ioctl.
> + * Called by the user via ioctl, or by an in-kernel client.
>   *
>   * Returns:
>   * Zero on success, negative errno on failure.
>   */
> -int drm_mode_rmfb(struct drm_device *dev,
> -		   void *data, struct drm_file *file_priv)
> +int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
> +		  struct drm_file *file_priv)
>  {
>  	struct drm_framebuffer *fb = NULL;
>  	struct drm_framebuffer *fbl = NULL;
> -	uint32_t *id = data;
>  	int found = 0;
>  
>  	if (!drm_core_check_feature(dev, DRIVER_MODESET))
>  		return -EINVAL;
>  
> -	fb = drm_framebuffer_lookup(dev, file_priv, *id);
> +	fb = drm_framebuffer_lookup(dev, file_priv, fb_id);
>  	if (!fb)
>  		return -ENOENT;
>  
> @@ -435,6 +443,14 @@ int drm_mode_rmfb(struct drm_device *dev,
>  	return -ENOENT;
>  }
>  
> +int drm_mode_rmfb_ioctl(struct drm_device *dev,
> +			void *data, struct drm_file *file_priv)
> +{
> +	uint32_t *fb_id = data;
> +
> +	return drm_mode_rmfb(dev, *fb_id, file_priv);
> +}
> +
>  /**
>   * drm_mode_getfb - get FB info
>   * @dev: drm device for the ioctl
> diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
> index 40179c5fc6b8..3f5d7706bcc9 100644
> --- a/drivers/gpu/drm/drm_internal.h
> +++ b/drivers/gpu/drm/drm_internal.h
> @@ -37,6 +37,9 @@ void drm_pci_agp_destroy(struct drm_device *dev);
>  int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master);
>  
>  /* drm_prime.c */
> +int drm_prime_handle_to_fd(struct drm_device *dev,
> +			   struct drm_prime_handle *args,
> +			   struct drm_file *file_priv);
>  int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
>  				 struct drm_file *file_priv);
>  int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
> diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
> index f8e96e648acf..576d00b7dad5 100644
> --- a/drivers/gpu/drm/drm_ioc32.c
> +++ b/drivers/gpu/drm/drm_ioc32.c
> @@ -884,7 +884,7 @@ static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
>  			   sizeof(req64.modifier)))
>  		return -EFAULT;
>  
> -	err = drm_ioctl_kernel(file, drm_mode_addfb2, &req64,
> +	err = drm_ioctl_kernel(file, drm_mode_addfb2_ioctl, &req64,
>  				DRM_CONTROL_ALLOW|DRM_UNLOCKED);
>  	if (err)
>  		return err;
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index af782911c505..c69fda5d3875 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -635,8 +635,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> -	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> -	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> +	DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
>  	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
> diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
> index caf675e3e692..e6052ab2bec4 100644
> --- a/drivers/gpu/drm/drm_prime.c
> +++ b/drivers/gpu/drm/drm_prime.c
> @@ -866,11 +866,10 @@ int drm_gem_prime_fd_to_handle(struct drm_device *dev,

Like with the dumb ioctls you probably want to unwrap this some more here
for the prime stuff. I don't think you want the actual fd, but just the
underlying struct dma_buf.

Unfortunately this means a bit of rework, since atm the
drm_driver->handle_to_fd also gives us the fd, not the dma_buf. Here's
what we need (assuming we really need struct dma_buf, and not just a gem
bo, which is much easier to get at):

- Change the drm_driver->handle_to_fd interface to handle_to_dma_buf, and
  put the final dma_buf_fd into drm_prime_handle_to_fd_ioctl. Since
  dma_buf_fd should already be the very last step (otherwise an
  implementation is most likely buggy) this shouldn't be a huge step.

  If dma_buf_fd fails, then we just do a dma_but_put (aka the
  ->handle_to_dma_buf callback needs to give us a reference we can use).

- For the internal function just call ->handle_to_dmabuf directly, but
  don't convert to an fd.

- Similar for the other direction. But I think we don't really need that:
  We start with the handle from the dumb api, going back to the handle
  shouldn't ever be needed. Probably best to just remove that.

We can't just create file-descriptors in random calling context (userspace
might get upset, no idea what happens from kernel threads).

The dumb buffer internal interfaces lgtm.
-Daniel


>  }
>  EXPORT_SYMBOL(drm_gem_prime_fd_to_handle);
>  
> -int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
> -				 struct drm_file *file_priv)
> +int drm_prime_handle_to_fd(struct drm_device *dev,
> +			   struct drm_prime_handle *args,
> +			   struct drm_file *file_priv)
>  {
> -	struct drm_prime_handle *args = data;
> -
>  	if (!drm_core_check_feature(dev, DRIVER_PRIME))
>  		return -EINVAL;
>  
> @@ -885,6 +884,12 @@ int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
>  			args->handle, args->flags, &args->fd);
>  }
>  
> +int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
> +				 struct drm_file *file_priv)
> +{
> +	return drm_prime_handle_to_fd(dev, data, file_priv);
> +}
> +
>  int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
>  				 struct drm_file *file_priv)
>  {
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
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] 46+ messages in thread

* Re: [RFC v4 19/25] drm/client: Finish the in-kernel client API
  2018-04-16  8:27   ` [Intel-gfx] " Daniel Vetter
@ 2018-04-16 15:58     ` Noralf Trønnes
  2018-04-17  8:08       ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-16 15:58 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel


Den 16.04.2018 10.27, skrev Daniel Vetter:
> On Sat, Apr 14, 2018 at 01:53:12PM +0200, Noralf Trønnes wrote:
>> The modesetting code is already present, this adds the rest of the API.
> Mentioning the TODO in the commit message would be good. Helps readers
> like me who have an attention span measured in seconds :-)
>
> Just commenting on the create_buffer leak here
>
>> +static struct drm_client_buffer *
>> +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
>> +{
>> +	struct drm_mode_create_dumb dumb_args = { };
>> +	struct drm_prime_handle prime_args = { };
>> +	struct drm_client_buffer *buffer;
>> +	struct dma_buf *dma_buf;
>> +	void *vaddr;
>> +	int ret;
>> +
>> +	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
>> +	if (!buffer)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	buffer->client = client;
>> +	buffer->width = width;
>> +	buffer->height = height;
>> +	buffer->format = format;
>> +
>> +	dumb_args.width = buffer->width;
>> +	dumb_args.height = buffer->height;
>> +	dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
>> +	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
>> +	if (ret)
>> +		goto err_free;
>> +
>> +	buffer->handle = dumb_args.handle;
>> +	buffer->pitch = dumb_args.pitch;
>> +	buffer->size = dumb_args.size;
>> +
>> +	prime_args.handle = dumb_args.handle;
>> +	ret = drm_prime_handle_to_fd(client->dev, &prime_args, client->file);
>> +	if (ret)
>> +		goto err_delete;
>> +
>> +	dma_buf = dma_buf_get(prime_args.fd);
>> +	if (IS_ERR(dma_buf)) {
>> +		ret = PTR_ERR(dma_buf);
>> +		goto err_delete;
>> +	}
>> +
>> +	/*
>> +	 * If called from a worker the dmabuf fd isn't closed and the ref
>> +	 * doesn't drop to zero on free.
>> +	 * If I use __close_fd() it's all fine, but that function is not exported.
>> +	 *
>> +	 * How do I get rid of this fd when in a worker/kernel thread?
>> +	 * The fd isn't used beyond this function.
>> +	 */
>> +//	WARN_ON(__close_fd(current->files, prime_args.fd));
> Hm, this isn't 100% what I had in mind as the sequence for generic buffer
> creation. Pseudo-code:
>
> 	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
> 	if (ret)
> 		goto err_free;
> 	
> 	gem_bo = drm_gem_object_lookup(client->file, dumb_args.handle);
>
> gives you _really_ directly the underlying gem_bo. Of course this doesn't
> work for non-gem based driver, but reality is that (almost) all of them
> are. And we will not accept any new drivers which aren't gem based. So
> ignoring vmwgfx for this drm_client work is imo perfectly fine. We should
> ofc keep the option in the fb helpers to use non-gem buffers (so that
> vmwgfx could switch over from their own in-driver fbdev helpers). All we
> need for that is to keep the fb_probe callback.
>
> Was there any other reason than vmwgfx for using prime buffers instead of
> just directly using gem?

The reason for using a prime buffer is that it gives me easy access to a
dma_buf which I use to get the virtual address (dma_buf_vmap) and for
mmap (dma_buf_mmap).

Would this stripped down version of drm_gem_prime_handle_to_fd() work?

struct dma_buf *drm_gem_to_dmabuf(struct drm_gem_object *obj)
{
     struct dma_buf *dmabuf;

     mutex_lock(&obj->dev->object_name_lock);
     /* re-export the original imported object */
     if (obj->import_attach) {
         dmabuf = obj->import_attach->dmabuf;
         get_dma_buf(dmabuf);
         goto out;
     }

     if (obj->dma_buf) {
         dmabuf = obj->dma_buf;
         get_dma_buf(dmabuf);
         goto out;
     }

     dmabuf = export_and_register_object(obj->dev, obj, 0);
out:
     mutex_unlock(&obj->dev->object_name_lock);

     return dmabuf;
}

Now I could do this:

     ret = drm_mode_create_dumb(dev, &dumb_args, file);

     obj = drm_gem_object_lookup(file, dumb_args.handle);

     dmabuf = drm_gem_to_dmabuf(obj);

     vaddr = dma_buf_vmap(dmabuf);


Noralf.

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

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

* Re: [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release()
  2018-04-16  8:46   ` Daniel Vetter
@ 2018-04-16 16:10     ` Noralf Trønnes
  2018-04-17  8:14       ` [Intel-gfx] " Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-16 16:10 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel


Den 16.04.2018 10.46, skrev Daniel Vetter:
> On Sat, Apr 14, 2018 at 01:53:14PM +0200, Noralf Trønnes wrote:
>> These helpers keep track of fbdev users and drm_driver.last_close will
>> only restore fbdev when actually in use. Additionally the display is
>> turned off when the last user is closing. fbcon is a user in this context.
>>
>> If struct fb_ops is defined in a library, fb_open() takes a ref on the
>> library (fb_ops.owner) instead of the driver module. Fix that by ensuring
>> that the driver module is pinned.
>>
>> The functions are not added to the DRM_FB_HELPER_DEFAULT_OPS() macro,
>> because some of its users do set fb_open/release themselves.
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
>> ---
>>   drivers/gpu/drm/drm_fb_helper.c | 54 ++++++++++++++++++++++++++++++++++++++++-
>>   include/drm/drm_fb_helper.h     | 29 ++++++++++++++++++++++
>>   2 files changed, 82 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index 98e5bc92c9f2..b1124c08b1ed 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -177,7 +177,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
>>   	if (!drm_fbdev_emulation || !fb_helper)
>>   		return -ENODEV;
>>   
>> -	if (READ_ONCE(fb_helper->deferred_setup))
>> +	if (READ_ONCE(fb_helper->deferred_setup) || !READ_ONCE(fb_helper->open_count))
>>   		return 0;
>>   
>>   	mutex_lock(&fb_helper->lock);
>> @@ -368,6 +368,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
>>   	INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
>>   	helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
>>   	mutex_init(&helper->lock);
>> +	helper->open_count = 1;
>>   	helper->funcs = funcs;
>>   	helper->dev = dev;
>>   }
>> @@ -620,6 +621,53 @@ int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
>>   }
>>   EXPORT_SYMBOL(drm_fb_helper_defio_init);
>>   
>> +/**
>> + * drm_fb_helper_fb_open - implementation for &fb_ops.fb_open
>> + * @info: fbdev registered by the helper
>> + * @user: 1=userspace, 0=fbcon
>> + *
>> + * Increase fbdev use count.
>> + * If &fb_ops is wrapped in a library, pin the driver module.
>> + */
>> +int drm_fb_helper_fb_open(struct fb_info *info, int user)
>> +{
>> +	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>> +
>> +	if (info->fbops->owner != dev->driver->fops->owner) {
>> +		if (!try_module_get(dev->driver->fops->owner))
>> +			return -ENODEV;
>> +	}
>> +
>> +	fb_helper->open_count++;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(drm_fb_helper_fb_open);
>> +
>> +/**
>> + * drm_fb_helper_fb_release - implementation for &fb_ops.fb_release
>> + * @info: fbdev registered by the helper
>> + * @user: 1=userspace, 0=fbcon
>> + *
>> + * Decrease fbdev use count and turn off if there are no users left.
>> + * If &fb_ops is wrapped in a library, unpin the driver module.
>> + */
>> +int drm_fb_helper_fb_release(struct fb_info *info, int user)
>> +{
>> +	struct drm_fb_helper *fb_helper = info->par;
>> +	struct drm_device *dev = fb_helper->dev;
>> +
>> +	if (!(--fb_helper->open_count))
>> +		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
>> +
>> +	if (info->fbops->owner != dev->driver->fops->owner)
>> +		module_put(dev->driver->fops->owner);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(drm_fb_helper_fb_release);
>> +
>>   /**
>>    * drm_fb_helper_sys_read - wrapper around fb_sys_read
>>    * @info: fb_info struct pointer
>> @@ -1436,6 +1484,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
>>   	if (ret < 0)
>>   		return ret;
>>   
>> +	/* Block restore without users if we do track it */
>> +	if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open)
>> +		fb_helper->open_count = 0;
> Since we kzcalloc, isn't this entirely redundant? Looks confusing to me at
> least.

I have to keep the existing restore behaviour for those that don't use
drm_fb_helper_fb_open(). I do this by setting fb_helper->open_count = 1
in drm_fb_helper_prepare(). I have tried to give a describtion in the
@open_count docs.

Ofc I could have changed all drivers to use drm_fb_helper_fb_open(), but
I think that time is better spent moving drivers over to generic fbdev
instead.

Noralf.

> Otherwise looks all reasonable.
> -Daniel
>
>
>> +
>>   	strcpy(fb_helper->fb->comm, "[fbcon]");
>>   	return 0;
>>   }
>> diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
>> index 5f66f253a97b..330983975d5e 100644
>> --- a/include/drm/drm_fb_helper.h
>> +++ b/include/drm/drm_fb_helper.h
>> @@ -184,6 +184,22 @@ struct drm_fb_helper {
>>   	 * See also: @deferred_setup
>>   	 */
>>   	int preferred_bpp;
>> +
>> +	/**
>> +	 * @open_count:
>> +	 *
>> +	 * Keeps track of fbdev use to know when to not restore fbdev and to
>> +	 * disable the pipeline when the last user is gone.
>> +	 *
>> +	 * Drivers that use drm_fb_helper_fb_open() as their \.fb_open
>> +	 * callback will get an initial value of 0 and get restore based on
>> +	 * actual use. Others will get an initial value of 1 which means that
>> +	 * fbdev will always be restored. Drivers that call
>> +	 * drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the
>> +	 * initial value to 0 themselves in their &drm_fb_helper_funcs->fb_probe
>> +	 * callback.
>> +	 */
>> +	unsigned int open_count;
>>   };
>>   
>>   /**
>> @@ -230,6 +246,9 @@ void drm_fb_helper_deferred_io(struct fb_info *info,
>>   			       struct list_head *pagelist);
>>   int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper);
>>   
>> +int drm_fb_helper_fb_open(struct fb_info *info, int user);
>> +int drm_fb_helper_fb_release(struct fb_info *info, int user);
>> +
>>   ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
>>   			       size_t count, loff_t *ppos);
>>   ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
>> @@ -376,6 +395,16 @@ static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
>>   	return -ENODEV;
>>   }
>>   
>> +static inline int drm_fb_helper_fb_open(struct fb_info *info, int user)
>> +{
>> +	return -ENODEV;
>> +}
>> +
>> +static inline int drm_fb_helper_fb_release(struct fb_info *info, int user)
>> +{
>> +	return -ENODEV;
>> +}
>> +
>>   static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
>>   					     char __user *buf, size_t count,
>>   					     loff_t *ppos)
>> -- 
>> 2.15.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

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

* Re: [RFC v4 00/25] drm: Add generic fbdev emulation
  2018-04-16  8:21 ` [RFC v4 00/25] drm: Add generic fbdev emulation Daniel Vetter
@ 2018-04-16 18:49   ` Noralf Trønnes
  2018-04-17  8:10     ` [Intel-gfx] " Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-16 18:49 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel


Den 16.04.2018 10.21, skrev Daniel Vetter:
> On Sat, Apr 14, 2018 at 01:52:53PM +0200, Noralf Trønnes wrote:
>> This patchset explores the possibility of having generic fbdev emulation
>> in DRM for drivers that supports dumb buffers which they can export. An
>> API is added to support in-kernel clients in general.
>>
>> In this version I was able to reuse the modesetting code from
>> drm_fb_helper in the client API. This avoids code duplication, carries
>> over lessons learned and the modesetting code is bisectable. The
>> downside is that it takes +10 patches to rip drm_fb_helper in two, so
>> maybe it's not worth it wrt possible breakage and a challenging review.
> So my idea wasn't to rip the fbdev helper in  half first (that's indeed a
> lot of work). But start out right away with using every piece of the
> drm_client infrastructure you're adding in the existing fbdev code.
>
> That way there's not a huge patch series which just adds code, with no
> users, but every step of the way and every addition is tested almost right
> away. That makes more gradual merging also easier. The things I have in
> mind here is the generic fb_probe, or the drm_client block/unblock masters
> and all that stuff.
>
> Then, once we've demonstrated all these auxiliary pieces necessary for
> drm_client.c work, we can cut the fb-helper in half and move the modeset
> code into the drm_client library.

I agree. I wished for a way to cut this patchset in half, but I just
couldn't see how. I was tired of working on this, so I just put it out
hoping that you would provide some clarity. Which you did, thanks :-)

So, I think I'll strip this down to just the buffer part of the client API
and use that in the generic fbdev emulation, and start converting some
drivers.

I'll pick up the rest of the client API when I'm done with moving tinydrm
over to vmalloc buffers and have added support for device unplug.

Noralf.

>
> I still prefer an even more gradual path like this compared to what you
> have in your patch series, but I understand that's yet another huge
> shuffle. And the current series seems like a good enough approach to get
> to essentially the same place.
>
>> Does the Intel CI test the fbdev emulation?
> We have fbdev emulation enabled, and iirc there's even a few tests for
> fbdev. Just booting it on 20+ machines is a lot of testing itsefl already.
>
>> Daniel had this concern with the previous version:
>>
>>      The register/unregister model needs more thought. Allowing both clients
>>      to register whenever they want to, and drm_device instances to come and
>>      go is what fbcon has done, and the resulting locking is a horror show.
>>
>>      I think if we require that all in-kernel drm_clients are registers when
>>      loading drm.ko (and enabled/disabled only per module options and
>>      Kconfig), then we can throw out all the locking. That avoids a lot of
>>      the headaches.
>>
>> I have solved this by adding a notifier that fires when a new DRM device
>> is registered (I've removed the new() callback). Currently only
>> bootsplash uses this. The fbdev client needs to be setup from the driver
>> since it can't know on device registration if the driver will setup it's
>> own fbdev emulation later and the vtcon client hooks up to a user
>> provided device id.
> Ugh, notifier is exactly what fbcon also uses. It just hides the locking
> horror show slightly, but it's equally bad. I'm working on a multi-year
> plan to rip out the fbcon notifier, please don't start another one. See
>
> commit 6104c37094e729f3d4ce65797002112735d49cd1
> Author: Daniel Vetter <daniel.vetter@ffwll.ch>
> Date:   Tue Aug 1 17:32:07 2017 +0200
>
>      fbcon: Make fbcon a built-time depency for fbdev
>
> for full details.
>
>> Since fbcon can't handle fb_open failing, the buffer has to be
>> pre-allocated. Exporting a GEM buffer pins the driver module making it
>> impossible to unload it.
>> I have included 2 solutions to the problem:
>> - sysfs file to remove/close clients: remove_internal_clients
> This is the same thing that defacto happens already with fbcon: You have
> to remove fbcon first (which holds a full ref on the fbdev, which prevents
> the drm driver from unloading). I think explicitly asking for that
> reference to disappear is ok.
>
> It does mean everyone has to update their unload scripts, but oh well.
>
>> - Change drm_gem_prime_export() so it doesn't pin on client buffers
> The double-loop in that patch definitely doesn't cut it, but worst case I
> think something like that could be made to work.
>
>> If a dumb buffer is exported from a kernel thread (worker) context, the
>> file descriptor isn't closed and I leak a reference so the buffer isn't
>> freed. Please look at drm_client_buffer_create() in patch
>> 'drm/client: Finish the in-kernel client API'.
>> This is a blocker that needs a solution.
> Hm, missed that in my first cursory read of the series, I'l take another
> look.
> -Daniel
>
>>
>> Noralf.
>>
>> Changes since version 3:
>> Client API changes:
>> - Drop drm_client_register_funcs() which attached clients indirectly.
>>    Let clients attach directly using drm_client_new{_from_id}(). Clients
>>    that wants to attach to all devices must be linked into drm.ko and use
>>    the DRM device notifier. This is done to avoid the lock/race
>>    register/unregister hell we have with fbcon. (Daniel Vetter)
>> - drm_client_display_restore() checks if there is a master and if so
>>    returns -EBUSY. (Daniel Vetter)
>> - Allocate drm_file up front instead of on-demand. Since fbdev can't do
>>    on demand buffer allocation because of fbcon, there's no need for this.
>> - Add sysfs file to remove clients
>> - Don't pin driver module when exporting gem client buffers
>> - Dropped page flip support since drm_fb_helper is now used for fbdev
>>    emulation.
>>
>> - The bootsplash client now switches over to fbdev on keypress.
>>
>> Changes since version 2:
>> - Don't set drm master for in-kernel clients. (Daniel Vetter)
>> - Add in-kernel client API
>>
>> Changes since version 1:
>> - Don't add drm_fb_helper_fb_open() and drm_fb_helper_fb_release() to
>>    DRM_FB_HELPER_DEFAULT_OPS(). (Fi.CI.STATIC)
>>    The following uses that macro and sets fb_open/close: udlfb_ops,
>>    amdgpufb_ops, drm_fb_helper_generic_fbdev_ops, nouveau_fbcon_ops,
>>    nouveau_fbcon_sw_ops, radeonfb_ops.
>>    This results in: warning: Initializer entry defined twice
>> - Support CONFIG_DRM_KMS_HELPER=m (kbuild test robot)
>>    ERROR: <function> [drivers/gpu/drm/drm_kms_helper.ko] undefined!
>> - Drop buggy patch: (Chris Wilson)
>>    drm/prime: Clear drm_gem_object->dma_buf on release
>> - Defer buffer creation until fb_open.
>>
>>
>> David Herrmann (1):
>>    drm: provide management functions for drm_file
>>
>> Noralf Trønnes (24):
>>    drm/file: Don't set master on in-kernel clients
>>    drm/fb-helper: No need to cache rotation and sw_rotations
>>    drm/fb-helper: Remove drm_fb_helper_debug_enter/leave()
>>    drm/fb-helper: dpms_legacy(): Only set on connectors in use
>>    drm/atomic: Move __drm_atomic_helper_disable_plane/set_config()
>>    drm: Begin an API for in-kernel clients
>>    drm/fb-helper: Use struct drm_client_display
>>    drm/fb-helper: Move modeset commit code to drm_client
>>    drm/connector: Add
>>      drm_connector_has_preferred_mode/pick_cmdline_mode()
>>    drm/connector: Add connector array functions
>>    drm/i915: Add drm_driver->initial_client_display callback
>>    drm/fb-helper: Remove struct drm_fb_helper_crtc
>>    drm/fb-helper: Remove struct drm_fb_helper_connector
>>    drm/fb-helper: Move modeset config code to drm_client
>>    drm: Make ioctls available for in-kernel clients
>>    drm/client: Bail out if there's a DRM master
>>    drm/client: Make the display modes available to clients
>>    drm/client: Finish the in-kernel client API
>>    drm/prime: Don't pin module on export for in-kernel clients
>>    drm/fb-helper: Add drm_fb_helper_fb_open/release()
>>    drm/fb-helper: Add generic fbdev emulation
>>    drm: Add DRM device registered notifier
>>    drm/client: Hack: Add bootsplash
>>    drm/client: Hack: Add DRM VT console client
>>
>>   drivers/gpu/drm/Kconfig                 |    2 +
>>   drivers/gpu/drm/Makefile                |    4 +-
>>   drivers/gpu/drm/client/Kconfig          |   14 +
>>   drivers/gpu/drm/client/Makefile         |    3 +
>>   drivers/gpu/drm/client/drm_bootsplash.c |  248 ++++++
>>   drivers/gpu/drm/client/drm_vtcon.c      |  785 +++++++++++++++++
>>   drivers/gpu/drm/client/internal.h       |   19 +
>>   drivers/gpu/drm/drm_atomic.c            |  168 ++++
>>   drivers/gpu/drm/drm_atomic_helper.c     |  168 +---
>>   drivers/gpu/drm/drm_auth.c              |   33 +
>>   drivers/gpu/drm/drm_client.c            | 1448 +++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/drm_connector.c         |  199 +++++
>>   drivers/gpu/drm/drm_crtc_internal.h     |   18 +-
>>   drivers/gpu/drm/drm_debugfs.c           |    7 +
>>   drivers/gpu/drm/drm_drv.c               |   43 +
>>   drivers/gpu/drm/drm_dumb_buffers.c      |   33 +-
>>   drivers/gpu/drm/drm_fb_helper.c         | 1420 ++++++++----------------------
>>   drivers/gpu/drm/drm_file.c              |  304 ++++---
>>   drivers/gpu/drm/drm_framebuffer.c       |   50 +-
>>   drivers/gpu/drm/drm_internal.h          |    7 +
>>   drivers/gpu/drm/drm_ioc32.c             |    2 +-
>>   drivers/gpu/drm/drm_ioctl.c             |    4 +-
>>   drivers/gpu/drm/drm_prime.c             |   37 +-
>>   drivers/gpu/drm/drm_probe_helper.c      |    3 +
>>   drivers/gpu/drm/drm_sysfs.c             |   20 +
>>   drivers/gpu/drm/i915/i915_drv.c         |    1 +
>>   drivers/gpu/drm/i915/intel_drv.h        |   11 +
>>   drivers/gpu/drm/i915/intel_fbdev.c      |  112 +--
>>   include/drm/drm_atomic.h                |    5 +
>>   include/drm/drm_atomic_helper.h         |    4 -
>>   include/drm/drm_client.h                |  182 ++++
>>   include/drm/drm_connector.h             |   11 +
>>   include/drm/drm_device.h                |    4 +
>>   include/drm/drm_drv.h                   |   25 +
>>   include/drm/drm_fb_helper.h             |  126 ++-
>>   35 files changed, 4007 insertions(+), 1513 deletions(-)
>>   create mode 100644 drivers/gpu/drm/client/Kconfig
>>   create mode 100644 drivers/gpu/drm/client/Makefile
>>   create mode 100644 drivers/gpu/drm/client/drm_bootsplash.c
>>   create mode 100644 drivers/gpu/drm/client/drm_vtcon.c
>>   create mode 100644 drivers/gpu/drm/client/internal.h
>>   create mode 100644 drivers/gpu/drm/drm_client.c
>>   create mode 100644 include/drm/drm_client.h
>>
>> --
>> 2.15.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

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

* Re: [RFC v4 19/25] drm/client: Finish the in-kernel client API
  2018-04-16 15:58     ` Noralf Trønnes
@ 2018-04-17  8:08       ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-17  8:08 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Mon, Apr 16, 2018 at 05:58:23PM +0200, Noralf Trønnes wrote:
> 
> Den 16.04.2018 10.27, skrev Daniel Vetter:
> > On Sat, Apr 14, 2018 at 01:53:12PM +0200, Noralf Trønnes wrote:
> > > The modesetting code is already present, this adds the rest of the API.
> > Mentioning the TODO in the commit message would be good. Helps readers
> > like me who have an attention span measured in seconds :-)
> > 
> > Just commenting on the create_buffer leak here
> > 
> > > +static struct drm_client_buffer *
> > > +drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
> > > +{
> > > +	struct drm_mode_create_dumb dumb_args = { };
> > > +	struct drm_prime_handle prime_args = { };
> > > +	struct drm_client_buffer *buffer;
> > > +	struct dma_buf *dma_buf;
> > > +	void *vaddr;
> > > +	int ret;
> > > +
> > > +	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
> > > +	if (!buffer)
> > > +		return ERR_PTR(-ENOMEM);
> > > +
> > > +	buffer->client = client;
> > > +	buffer->width = width;
> > > +	buffer->height = height;
> > > +	buffer->format = format;
> > > +
> > > +	dumb_args.width = buffer->width;
> > > +	dumb_args.height = buffer->height;
> > > +	dumb_args.bpp = drm_format_plane_cpp(format, 0) * 8;
> > > +	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
> > > +	if (ret)
> > > +		goto err_free;
> > > +
> > > +	buffer->handle = dumb_args.handle;
> > > +	buffer->pitch = dumb_args.pitch;
> > > +	buffer->size = dumb_args.size;
> > > +
> > > +	prime_args.handle = dumb_args.handle;
> > > +	ret = drm_prime_handle_to_fd(client->dev, &prime_args, client->file);
> > > +	if (ret)
> > > +		goto err_delete;
> > > +
> > > +	dma_buf = dma_buf_get(prime_args.fd);
> > > +	if (IS_ERR(dma_buf)) {
> > > +		ret = PTR_ERR(dma_buf);
> > > +		goto err_delete;
> > > +	}
> > > +
> > > +	/*
> > > +	 * If called from a worker the dmabuf fd isn't closed and the ref
> > > +	 * doesn't drop to zero on free.
> > > +	 * If I use __close_fd() it's all fine, but that function is not exported.
> > > +	 *
> > > +	 * How do I get rid of this fd when in a worker/kernel thread?
> > > +	 * The fd isn't used beyond this function.
> > > +	 */
> > > +//	WARN_ON(__close_fd(current->files, prime_args.fd));
> > Hm, this isn't 100% what I had in mind as the sequence for generic buffer
> > creation. Pseudo-code:
> > 
> > 	ret = drm_mode_create_dumb(client->dev, &dumb_args, client->file);
> > 	if (ret)
> > 		goto err_free;
> > 	
> > 	gem_bo = drm_gem_object_lookup(client->file, dumb_args.handle);
> > 
> > gives you _really_ directly the underlying gem_bo. Of course this doesn't
> > work for non-gem based driver, but reality is that (almost) all of them
> > are. And we will not accept any new drivers which aren't gem based. So
> > ignoring vmwgfx for this drm_client work is imo perfectly fine. We should
> > ofc keep the option in the fb helpers to use non-gem buffers (so that
> > vmwgfx could switch over from their own in-driver fbdev helpers). All we
> > need for that is to keep the fb_probe callback.
> > 
> > Was there any other reason than vmwgfx for using prime buffers instead of
> > just directly using gem?
> 
> The reason for using a prime buffer is that it gives me easy access to a
> dma_buf which I use to get the virtual address (dma_buf_vmap) and for
> mmap (dma_buf_mmap).

Ah yes, I missed that.

Wrt mmap, not sure we should use the dma-buf mmap or the dumb mmap. I
guess in the end it wont matter much really.

> 
> Would this stripped down version of drm_gem_prime_handle_to_fd() work?
> 
> struct dma_buf *drm_gem_to_dmabuf(struct drm_gem_object *obj)
> {
>     struct dma_buf *dmabuf;
> 
>     mutex_lock(&obj->dev->object_name_lock);
>     /* re-export the original imported object */
>     if (obj->import_attach) {
>         dmabuf = obj->import_attach->dmabuf;
>         get_dma_buf(dmabuf);
>         goto out;
>     }
> 
>     if (obj->dma_buf) {
>         dmabuf = obj->dma_buf;
>         get_dma_buf(dmabuf);
>         goto out;
>     }
> 
>     dmabuf = export_and_register_object(obj->dev, obj, 0);
> out:
>     mutex_unlock(&obj->dev->object_name_lock);
> 
>     return dmabuf;
> }
> 
> Now I could do this:
> 
>     ret = drm_mode_create_dumb(dev, &dumb_args, file);
> 
>     obj = drm_gem_object_lookup(file, dumb_args.handle);
> 
>     dmabuf = drm_gem_to_dmabuf(obj);
> 
>     vaddr = dma_buf_vmap(dmabuf);

Nah, if we need the dma-buf anyway, I'd try to go directly from the handle
to the dma-buf. So roughly:

	ret = drm_mode_create_dumb(dev, &dumb_args, file);
	
	dma_buf = drm_gem_prime_handle_to_dmabuf(file, dumb_args.handle);

See my reply to the ioctl wrapper patch for details.
-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] 46+ messages in thread

* Re: [Intel-gfx] [RFC v4 00/25] drm: Add generic fbdev emulation
  2018-04-16 18:49   ` Noralf Trønnes
@ 2018-04-17  8:10     ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-17  8:10 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Mon, Apr 16, 2018 at 08:49:23PM +0200, Noralf Trønnes wrote:
> 
> Den 16.04.2018 10.21, skrev Daniel Vetter:
> > On Sat, Apr 14, 2018 at 01:52:53PM +0200, Noralf Trønnes wrote:
> > > This patchset explores the possibility of having generic fbdev emulation
> > > in DRM for drivers that supports dumb buffers which they can export. An
> > > API is added to support in-kernel clients in general.
> > > 
> > > In this version I was able to reuse the modesetting code from
> > > drm_fb_helper in the client API. This avoids code duplication, carries
> > > over lessons learned and the modesetting code is bisectable. The
> > > downside is that it takes +10 patches to rip drm_fb_helper in two, so
> > > maybe it's not worth it wrt possible breakage and a challenging review.
> > So my idea wasn't to rip the fbdev helper in  half first (that's indeed a
> > lot of work). But start out right away with using every piece of the
> > drm_client infrastructure you're adding in the existing fbdev code.
> > 
> > That way there's not a huge patch series which just adds code, with no
> > users, but every step of the way and every addition is tested almost right
> > away. That makes more gradual merging also easier. The things I have in
> > mind here is the generic fb_probe, or the drm_client block/unblock masters
> > and all that stuff.
> > 
> > Then, once we've demonstrated all these auxiliary pieces necessary for
> > drm_client.c work, we can cut the fb-helper in half and move the modeset
> > code into the drm_client library.
> 
> I agree. I wished for a way to cut this patchset in half, but I just
> couldn't see how. I was tired of working on this, so I just put it out
> hoping that you would provide some clarity. Which you did, thanks :-)

Yeah, that's why I'm also ok with things as-is. I think we've reached
agreement on the design and big picture now, which really is the important
part. How exactly we get there (as long as it's gradual steps in
bisectable patches) doesn't matter that much really.

> So, I think I'll strip this down to just the buffer part of the client API
> and use that in the generic fbdev emulation, and start converting some
> drivers.

Yes the buffer stuff is definitely the core parts. I think rolling out the
master_block/unblock stuff after that would be really neat too, since it
would fix a long-standing race in our fbdev emulation.

> I'll pick up the rest of the client API when I'm done with moving tinydrm
> over to vmalloc buffers and have added support for device unplug.

Sounds like a good plan.
-Daniel
-- 
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] 46+ messages in thread

* Re: [Intel-gfx] [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release()
  2018-04-16 16:10     ` Noralf Trønnes
@ 2018-04-17  8:14       ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-17  8:14 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Mon, Apr 16, 2018 at 06:10:07PM +0200, Noralf Trønnes wrote:
> 
> Den 16.04.2018 10.46, skrev Daniel Vetter:
> > On Sat, Apr 14, 2018 at 01:53:14PM +0200, Noralf Trønnes wrote:
> > > These helpers keep track of fbdev users and drm_driver.last_close will
> > > only restore fbdev when actually in use. Additionally the display is
> > > turned off when the last user is closing. fbcon is a user in this context.
> > > 
> > > If struct fb_ops is defined in a library, fb_open() takes a ref on the
> > > library (fb_ops.owner) instead of the driver module. Fix that by ensuring
> > > that the driver module is pinned.
> > > 
> > > The functions are not added to the DRM_FB_HELPER_DEFAULT_OPS() macro,
> > > because some of its users do set fb_open/release themselves.
> > > 
> > > Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > > ---
> > >   drivers/gpu/drm/drm_fb_helper.c | 54 ++++++++++++++++++++++++++++++++++++++++-
> > >   include/drm/drm_fb_helper.h     | 29 ++++++++++++++++++++++
> > >   2 files changed, 82 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> > > index 98e5bc92c9f2..b1124c08b1ed 100644
> > > --- a/drivers/gpu/drm/drm_fb_helper.c
> > > +++ b/drivers/gpu/drm/drm_fb_helper.c
> > > @@ -177,7 +177,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
> > >   	if (!drm_fbdev_emulation || !fb_helper)
> > >   		return -ENODEV;
> > > -	if (READ_ONCE(fb_helper->deferred_setup))
> > > +	if (READ_ONCE(fb_helper->deferred_setup) || !READ_ONCE(fb_helper->open_count))
> > >   		return 0;
> > >   	mutex_lock(&fb_helper->lock);
> > > @@ -368,6 +368,7 @@ void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
> > >   	INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
> > >   	helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
> > >   	mutex_init(&helper->lock);
> > > +	helper->open_count = 1;
> > >   	helper->funcs = funcs;
> > >   	helper->dev = dev;
> > >   }
> > > @@ -620,6 +621,53 @@ int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
> > >   }
> > >   EXPORT_SYMBOL(drm_fb_helper_defio_init);
> > > +/**
> > > + * drm_fb_helper_fb_open - implementation for &fb_ops.fb_open
> > > + * @info: fbdev registered by the helper
> > > + * @user: 1=userspace, 0=fbcon
> > > + *
> > > + * Increase fbdev use count.
> > > + * If &fb_ops is wrapped in a library, pin the driver module.
> > > + */
> > > +int drm_fb_helper_fb_open(struct fb_info *info, int user)
> > > +{
> > > +	struct drm_fb_helper *fb_helper = info->par;
> > > +	struct drm_device *dev = fb_helper->dev;
> > > +
> > > +	if (info->fbops->owner != dev->driver->fops->owner) {
> > > +		if (!try_module_get(dev->driver->fops->owner))
> > > +			return -ENODEV;
> > > +	}
> > > +
> > > +	fb_helper->open_count++;
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL(drm_fb_helper_fb_open);
> > > +
> > > +/**
> > > + * drm_fb_helper_fb_release - implementation for &fb_ops.fb_release
> > > + * @info: fbdev registered by the helper
> > > + * @user: 1=userspace, 0=fbcon
> > > + *
> > > + * Decrease fbdev use count and turn off if there are no users left.
> > > + * If &fb_ops is wrapped in a library, unpin the driver module.
> > > + */
> > > +int drm_fb_helper_fb_release(struct fb_info *info, int user)
> > > +{
> > > +	struct drm_fb_helper *fb_helper = info->par;
> > > +	struct drm_device *dev = fb_helper->dev;
> > > +
> > > +	if (!(--fb_helper->open_count))
> > > +		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
> > > +
> > > +	if (info->fbops->owner != dev->driver->fops->owner)
> > > +		module_put(dev->driver->fops->owner);
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL(drm_fb_helper_fb_release);
> > > +
> > >   /**
> > >    * drm_fb_helper_sys_read - wrapper around fb_sys_read
> > >    * @info: fb_info struct pointer
> > > @@ -1436,6 +1484,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
> > >   	if (ret < 0)
> > >   		return ret;
> > > +	/* Block restore without users if we do track it */
> > > +	if (fb_helper->fbdev->fbops->fb_open == drm_fb_helper_fb_open)
> > > +		fb_helper->open_count = 0;
> > Since we kzcalloc, isn't this entirely redundant? Looks confusing to me at
> > least.
> 
> I have to keep the existing restore behaviour for those that don't use
> drm_fb_helper_fb_open(). I do this by setting fb_helper->open_count = 1
> in drm_fb_helper_prepare(). I have tried to give a describtion in the
> @open_count docs.

Ah I missed that. I think having the fbops->fb_op == drm_fb_helper_fb_open
check in the restore function itself, plus a big comment explaining what
you're doing, would be clearer. So instead of always checking the
open_count, only check it when this helper is in use.

> Ofc I could have changed all drivers to use drm_fb_helper_fb_open(), but
> I think that time is better spent moving drivers over to generic fbdev
> instead.

Yeah FIXME (plus maybe todo.rst entry, this is perfect starting task
fodder) is totally good enough.
-Daniel

> 
> Noralf.
> 
> > Otherwise looks all reasonable.
> > -Daniel
> > 
> > 
> > > +
> > >   	strcpy(fb_helper->fb->comm, "[fbcon]");
> > >   	return 0;
> > >   }
> > > diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
> > > index 5f66f253a97b..330983975d5e 100644
> > > --- a/include/drm/drm_fb_helper.h
> > > +++ b/include/drm/drm_fb_helper.h
> > > @@ -184,6 +184,22 @@ struct drm_fb_helper {
> > >   	 * See also: @deferred_setup
> > >   	 */
> > >   	int preferred_bpp;
> > > +
> > > +	/**
> > > +	 * @open_count:
> > > +	 *
> > > +	 * Keeps track of fbdev use to know when to not restore fbdev and to
> > > +	 * disable the pipeline when the last user is gone.
> > > +	 *
> > > +	 * Drivers that use drm_fb_helper_fb_open() as their \.fb_open
> > > +	 * callback will get an initial value of 0 and get restore based on
> > > +	 * actual use. Others will get an initial value of 1 which means that
> > > +	 * fbdev will always be restored. Drivers that call
> > > +	 * drm_fb_helper_fb_open() in their \.fb_open, thus needs to set the
> > > +	 * initial value to 0 themselves in their &drm_fb_helper_funcs->fb_probe
> > > +	 * callback.
> > > +	 */
> > > +	unsigned int open_count;
> > >   };
> > >   /**
> > > @@ -230,6 +246,9 @@ void drm_fb_helper_deferred_io(struct fb_info *info,
> > >   			       struct list_head *pagelist);
> > >   int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper);
> > > +int drm_fb_helper_fb_open(struct fb_info *info, int user);
> > > +int drm_fb_helper_fb_release(struct fb_info *info, int user);
> > > +
> > >   ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
> > >   			       size_t count, loff_t *ppos);
> > >   ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
> > > @@ -376,6 +395,16 @@ static inline int drm_fb_helper_defio_init(struct drm_fb_helper *fb_helper)
> > >   	return -ENODEV;
> > >   }
> > > +static inline int drm_fb_helper_fb_open(struct fb_info *info, int user)
> > > +{
> > > +	return -ENODEV;
> > > +}
> > > +
> > > +static inline int drm_fb_helper_fb_release(struct fb_info *info, int user)
> > > +{
> > > +	return -ENODEV;
> > > +}
> > > +
> > >   static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info,
> > >   					     char __user *buf, size_t count,
> > >   					     loff_t *ppos)
> > > -- 
> > > 2.15.1
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 

-- 
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] 46+ messages in thread

* Re: [RFC v4 23/25] drm: Add DRM device registered notifier
  2018-04-14 11:53 ` [RFC v4 23/25] drm: Add DRM device registered notifier Noralf Trønnes
@ 2018-04-17 10:16   ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2018-04-17 10:16 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Sat, Apr 14, 2018 at 01:53:16PM +0200, Noralf Trønnes wrote:
> Add a notifier that fires when a new DRM device is registered.
> This can be used by the bootsplash client to connect to all devices.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

So I freaked out temporarily about your usage of notifiers here. But I
think this one of the few cases where using notifiers is actually
perfectly fine. Still not sure we really want that, instead of just
hard-coding calls to the various register functions directly (and using a
dummy no-op replacement if that part isn't enabled in Kconfig).
-Daniel

> ---
>  drivers/gpu/drm/drm_drv.c | 32 ++++++++++++++++++++++++++++++++
>  include/drm/drm_drv.h     |  4 ++++
>  2 files changed, 36 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
> index 6f21bafb29be..e42ce320ad07 100644
> --- a/drivers/gpu/drm/drm_drv.c
> +++ b/drivers/gpu/drm/drm_drv.c
> @@ -31,6 +31,7 @@
>  #include <linux/module.h>
>  #include <linux/moduleparam.h>
>  #include <linux/mount.h>
> +#include <linux/notifier.h>
>  #include <linux/slab.h>
>  #include <linux/srcu.h>
>  
> @@ -79,6 +80,8 @@ static struct dentry *drm_debugfs_root;
>  
>  DEFINE_STATIC_SRCU(drm_unplug_srcu);
>  
> +static BLOCKING_NOTIFIER_HEAD(drm_dev_notifier);
> +
>  /*
>   * DRM Minors
>   * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
> @@ -837,6 +840,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
>  		 dev->dev ? dev_name(dev->dev) : "virtual device",
>  		 dev->primary->index);
>  
> +	blocking_notifier_call_chain(&drm_dev_notifier, 0, dev);
> +
>  	goto out_unlock;
>  
>  err_minors:
> @@ -894,6 +899,33 @@ void drm_dev_unregister(struct drm_device *dev)
>  }
>  EXPORT_SYMBOL(drm_dev_unregister);
>  
> +/**
> + * drm_dev_register_notifier - Register a notifier for new DRM devices
> + * @nb: Notifier block
> + *
> + * Register a notifier that fires when a new &drm_device is registered.
> + *
> + * Note:
> + * Users of this function has to be linked into drm.ko. This is done to make
> + * life simple avoiding tricky race situations.
> + */
> +void drm_dev_register_notifier(struct notifier_block *nb)
> +{
> +	/* Currently this can't fail, but catch it in case this changes */
> +	WARN_ON(blocking_notifier_chain_register(&drm_dev_notifier, nb));
> +}
> +
> +/**
> + * drm_dev_unregister_notifier - Unregister DRM device notifier
> + * @nb: Notifier block
> + *
> + * This is a no-op if the notifier isn't registered.
> + */
> +void drm_dev_unregister_notifier(struct notifier_block *nb)
> +{
> +	blocking_notifier_chain_unregister(&drm_dev_notifier, nb);
> +}
> +
>  /**
>   * drm_dev_set_unique - Set the unique name of a DRM device
>   * @dev: device of which to set the unique name
> diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
> index 13356e6fd40c..5e6c6ed0d59d 100644
> --- a/include/drm/drm_drv.h
> +++ b/include/drm/drm_drv.h
> @@ -40,6 +40,7 @@ struct drm_minor;
>  struct dma_buf_attachment;
>  struct drm_display_mode;
>  struct drm_mode_create_dumb;
> +struct notifier_block;
>  struct drm_printer;
>  
>  /* driver capabilities and requirements mask */
> @@ -641,6 +642,9 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
>  int drm_dev_register(struct drm_device *dev, unsigned long flags);
>  void drm_dev_unregister(struct drm_device *dev);
>  
> +void drm_dev_register_notifier(struct notifier_block *nb);
> +void drm_dev_unregister_notifier(struct notifier_block *nb);
> +
>  void drm_dev_get(struct drm_device *dev);
>  void drm_dev_put(struct drm_device *dev);
>  void drm_dev_unref(struct drm_device *dev);
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
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] 46+ messages in thread

* Re: [Intel-gfx] [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback
  2018-04-16  8:38   ` Daniel Vetter
@ 2019-03-01 11:46     ` Noralf Trønnes
  2019-03-01 11:51       ` Daniel Vetter
  0 siblings, 1 reply; 46+ messages in thread
From: Noralf Trønnes @ 2019-03-01 11:46 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel



Den 16.04.2018 10.38, skrev Daniel Vetter:
> On Sat, Apr 14, 2018 at 01:53:05PM +0200, Noralf Trønnes wrote:
>> As part of moving the modesetting code out of drm_fb_helper and into
>> drm_client, the drm_fb_helper_funcs->initial_config callback needs to go.
>> Replace it with a drm_driver->initial_client_display callback that can
>> work for all in-kernel clients.
>>
>> TODO:
>> - Add a patch that moves the function out of intel_fbdev.c since it's not
>>   fbdev specific anymore.
>>
>> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> 
> So the reason we originally added this callback for i915 fast boot was
> that there wasn't any atomic around yet. And it was all an experiment to
> figure out how to best go about designing fastboot.
> 
> But now we have fbdev, and fastboot design is also pretty clear:
> 
> 1. driver loads
> 2. driver reads out current hw state, reconstructs a full atomic state for
> everything and stuffs it into connector/crtc/plane->state pointers.
> 3. fbdev and any other client read out current state (with some caveats)
> and just take it over.
> 
> What non-fastboot drivers do:
> 1. drivers load
> 2. reset both hw and sw state to everything off.
> 
> Now the intel_fb_initial_config is all generic code really, and it will
> neatly fall back to the default config if everything is off. This means we
> could:
> 1. Move the intel_fb_initial_config into the fbdev helpers.
> 2. Nuke the ->initial_config callback.
> 
> And pronto! every driver which implements hw state readout will get fbdev
> fastboot for free.
> 

I'm back working on this now and there's one intel specific thing:
num_pipes, in that function that I don't know how to handle when moving
the code into the fbdev helper:

static bool intel_fb_initial_config(...)
{
[...]
	/*
	 * 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;
	}

Noralf.

> And since you've already rewritting the intel code to use drm_client, it's
> practically done already. Just need to s/intel_/drm_fbdev_helper_ or
> something like that :-)
> -Daniel
> 
>> ---
>>  drivers/gpu/drm/drm_fb_helper.c    |  19 +++++--
>>  drivers/gpu/drm/i915/i915_drv.c    |   1 +
>>  drivers/gpu/drm/i915/intel_drv.h   |  11 ++++
>>  drivers/gpu/drm/i915/intel_fbdev.c | 113 ++++++++++++++++++-------------------
>>  include/drm/drm_drv.h              |  21 +++++++
>>  5 files changed, 104 insertions(+), 61 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
>> index b992f59dad30..5407bf6dc8c0 100644
>> --- a/drivers/gpu/drm/drm_fb_helper.c
>> +++ b/drivers/gpu/drm/drm_fb_helper.c
>> @@ -2103,6 +2103,20 @@ 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);
>>  
>> +	mutex_lock(&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");
>> +
>> +	if (dev->driver->initial_client_display) {
>> +		display = dev->driver->initial_client_display(dev, width, height);
>> +		if (display) {
>> +			drm_client_display_free(fb_helper->display);
>> +			fb_helper->display = display;
>> +			mutex_unlock(&dev->mode_config.mutex);
>> +			return;
>> +		}
>> +	}
>> +
>>  	crtcs = kcalloc(fb_helper->connector_count,
>>  			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
>>  	modes = kcalloc(fb_helper->connector_count,
>> @@ -2120,9 +2134,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  	if (IS_ERR(display))
>>  		goto out;
>>  
>> -	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");
>>  	drm_enable_connectors(fb_helper, enabled);
>>  
>>  	if (!(fb_helper->funcs->initial_config &&
>> @@ -2144,7 +2155,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  
>>  		drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
>>  	}
>> -	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 */
>> @@ -2182,6 +2192,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
>>  	drm_client_display_free(fb_helper->display);
>>  	fb_helper->display = display;
>>  out:
>> +	mutex_unlock(&dev->mode_config.mutex);
>>  	kfree(crtcs);
>>  	kfree(modes);
>>  	kfree(offsets);
>> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
>> index 07c07d55398b..b746c0cbaa4b 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.c
>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>> @@ -2857,6 +2857,7 @@ static struct drm_driver driver = {
>>  
>>  	.dumb_create = i915_gem_dumb_create,
>>  	.dumb_map_offset = i915_gem_mmap_gtt,
>> +	.initial_client_display = i915_initial_client_display,
>>  	.ioctls = i915_ioctls,
>>  	.num_ioctls = ARRAY_SIZE(i915_ioctls),
>>  	.fops = &i915_driver_fops,
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> index d4368589b355..f77f510617c5 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -1720,6 +1720,9 @@ extern void intel_fbdev_fini(struct drm_i915_private *dev_priv);
>>  extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
>>  extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
>>  extern void intel_fbdev_restore_mode(struct drm_device *dev);
>> +struct drm_client_display *
>> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
>> +			    unsigned int height);
>>  #else
>>  static inline int intel_fbdev_init(struct drm_device *dev)
>>  {
>> @@ -1749,6 +1752,14 @@ static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
>>  static inline void intel_fbdev_restore_mode(struct drm_device *dev)
>>  {
>>  }
>> +
>> +static inline struct drm_client_display *
>> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
>> +			    unsigned int height)
>> +{
>> +	return NULL;
>> +}
>> +
>>  #endif
>>  
>>  /* intel_fbc.c */
>> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
>> index a4ab8575a72e..b7f44c9475a8 100644
>> --- a/drivers/gpu/drm/i915/intel_fbdev.c
>> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
>> @@ -38,6 +38,7 @@
>>  #include <linux/vga_switcheroo.h>
>>  
>>  #include <drm/drmP.h>
>> +#include <drm/drm_client.h>
>>  #include <drm/drm_crtc.h>
>>  #include <drm/drm_fb_helper.h>
>>  #include "intel_drv.h"
>> @@ -287,18 +288,6 @@ 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.
>> @@ -326,44 +315,48 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
>>   * 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_client_display *
>> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
>> +			    unsigned int height)
>>  {
>> -	struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
>> +	struct drm_i915_private *dev_priv = to_i915(dev);
>>  	unsigned long conn_configured, conn_seq, mask;
>> -	unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
>> -	int i, j;
>> -	bool *save_enabled;
>> -	bool fallback = true, ret = true;
>> +	bool fallback = true, *enabled = NULL;
>> +	struct drm_client_display *display;
>> +	struct drm_connector **connectors;
>> +	int i, connector_count;
>> +	unsigned int count;
>>  	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;
>> +	display = drm_client_display_create(dev);
>> +	if (IS_ERR(display))
>> +		return NULL;
>>  
>>  	drm_modeset_acquire_init(&ctx, 0);
>>  
>> -	while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
>> +	while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
>>  		drm_modeset_backoff(&ctx);
>>  
>> -	memcpy(save_enabled, enabled, count);
>> +	connector_count = drm_connector_get_all(dev, &connectors);
>> +	if (connector_count < 1)
>> +		goto bail;
>> +
>> +	enabled = drm_connector_get_enabled_status(connectors, connector_count);
>> +	if (!enabled)
>> +		goto bail;
>> +
>> +	count = min(connector_count, BITS_PER_LONG);
>>  	mask = GENMASK(count - 1, 0);
>>  	conn_configured = 0;
>>  retry:
>>  	conn_seq = conn_configured;
>>  	for (i = 0; i < count; i++) {
>> -		struct drm_fb_helper_connector *fb_conn;
>> -		struct drm_connector *connector;
>> +		struct drm_connector *connector = connectors[i];
>> +		struct drm_display_mode *mode;
>> +		struct drm_mode_set *modeset;
>>  		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;
>> @@ -402,16 +395,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>>  
>>  		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_client_display_for_each_modeset(modeset, display) {
>> +			if (modeset->connectors[0] == connector) {
>>  				DRM_DEBUG_KMS("fallback: cloned configuration\n");
>>  				goto bail;
>>  			}
>> @@ -421,28 +411,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>>  			      connector->name);
>>  
>>  		/* go for command line mode first */
>> -		modes[i] = drm_connector_pick_cmdline_mode(connector);
>> +		mode = drm_connector_pick_cmdline_mode(connector);
>>  
>>  		/* try for preferred next */
>> -		if (!modes[i]) {
>> +		if (!mode) {
>>  			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);
>> +			mode = 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)) {
>> +		if (!mode && !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);
>> +			mode = list_first_entry(&connector->modes,
>> +						struct drm_display_mode, head);
>>  		}
>>  
>>  		/* last resort: use current mode */
>> -		if (!modes[i]) {
>> +		if (!mode) {
>>  			/*
>>  			 * IMPORTANT: We want to use the adjusted mode (i.e.
>>  			 * after the panel fitter upscaling) as the initial
>> @@ -458,16 +446,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>>  			 */
>>  			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
>>  				      connector->name);
>> -			modes[i] = &connector->state->crtc->mode;
>> +			mode = &connector->state->crtc->mode;
>>  		}
>> -		crtcs[i] = new_crtc;
>> +
>> +		modeset = drm_client_display_find_modeset(display, connector->state->crtc);
>> +		if (WARN_ON(!modeset))
>> +			goto bail;
>> +
>> +		modeset->mode = drm_mode_duplicate(dev, mode);
>> +		drm_connector_get(connector);
>> +		modeset->connectors[0] = connector;
>> +		modeset->num_connectors = 1;
>> +		modeset->x = 0;
>> +		modeset->y = 0;
>>  
>>  		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" :"");
>> +			      mode->hdisplay, mode->vdisplay,
>> +			      mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
>>  
>>  		fallback = false;
>>  		conn_configured |= BIT(i);
>> @@ -492,19 +490,20 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
>>  	if (fallback) {
>>  bail:
>>  		DRM_DEBUG_KMS("Not using firmware configuration\n");
>> -		memcpy(enabled, save_enabled, count);
>> -		ret = false;
>> +		drm_client_display_free(display);
>> +		display = NULL;
>>  	}
>>  
>>  	drm_modeset_drop_locks(&ctx);
>>  	drm_modeset_acquire_fini(&ctx);
>>  
>> -	kfree(save_enabled);
>> -	return ret;
>> +	drm_connector_put_all(connectors, connector_count);
>> +	kfree(enabled);
>> +
>> +	return display;
>>  }
>>  
>>  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_drv.h b/include/drm/drm_drv.h
>> index 7e545f5f94d3..13356e6fd40c 100644
>> --- a/include/drm/drm_drv.h
>> +++ b/include/drm/drm_drv.h
>> @@ -32,6 +32,7 @@
>>  
>>  #include <drm/drm_device.h>
>>  
>> +struct drm_client_display;
>>  struct drm_file;
>>  struct drm_gem_object;
>>  struct drm_master;
>> @@ -553,6 +554,26 @@ struct drm_driver {
>>  			    struct drm_device *dev,
>>  			    uint32_t handle);
>>  
>> +	/**
>> +	 * @initial_client_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.
>> +	 */
>> +	struct drm_client_display *(*initial_client_display)(struct drm_device *dev,
>> +					unsigned int width, unsigned int height);
>> +
>>  	/**
>>  	 * @gem_vm_ops: Driver private ops for this object
>>  	 */
>> -- 
>> 2.15.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback
  2019-03-01 11:46     ` [Intel-gfx] " Noralf Trønnes
@ 2019-03-01 11:51       ` Daniel Vetter
  0 siblings, 0 replies; 46+ messages in thread
From: Daniel Vetter @ 2019-03-01 11:51 UTC (permalink / raw)
  To: Noralf Trønnes; +Cc: intel-gfx, dri-devel

On Fri, Mar 1, 2019 at 12:46 PM Noralf Trønnes <noralf@tronnes.org> wrote:
>
>
>
> Den 16.04.2018 10.38, skrev Daniel Vetter:
> > On Sat, Apr 14, 2018 at 01:53:05PM +0200, Noralf Trønnes wrote:
> >> As part of moving the modesetting code out of drm_fb_helper and into
> >> drm_client, the drm_fb_helper_funcs->initial_config callback needs to go.
> >> Replace it with a drm_driver->initial_client_display callback that can
> >> work for all in-kernel clients.
> >>
> >> TODO:
> >> - Add a patch that moves the function out of intel_fbdev.c since it's not
> >>   fbdev specific anymore.
> >>
> >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> >
> > So the reason we originally added this callback for i915 fast boot was
> > that there wasn't any atomic around yet. And it was all an experiment to
> > figure out how to best go about designing fastboot.
> >
> > But now we have fbdev, and fastboot design is also pretty clear:
> >
> > 1. driver loads
> > 2. driver reads out current hw state, reconstructs a full atomic state for
> > everything and stuffs it into connector/crtc/plane->state pointers.
> > 3. fbdev and any other client read out current state (with some caveats)
> > and just take it over.
> >
> > What non-fastboot drivers do:
> > 1. drivers load
> > 2. reset both hw and sw state to everything off.
> >
> > Now the intel_fb_initial_config is all generic code really, and it will
> > neatly fall back to the default config if everything is off. This means we
> > could:
> > 1. Move the intel_fb_initial_config into the fbdev helpers.
> > 2. Nuke the ->initial_config callback.
> >
> > And pronto! every driver which implements hw state readout will get fbdev
> > fastboot for free.
> >
>
> I'm back working on this now and there's one intel specific thing:
> num_pipes, in that function that I don't know how to handle when moving
> the code into the fbdev helper:

num_pipes == dev->mode_config.num_crtcs. Or should at least if we
managed to set up everything correctly. Not exactly sure why we've
used that intel-ism there, shouldn't have any effect when switching
over.
-Daniel

>
> static bool intel_fb_initial_config(...)
> {
> [...]
>         /*
>          * 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;
>         }
>
> Noralf.
>
> > And since you've already rewritting the intel code to use drm_client, it's
> > practically done already. Just need to s/intel_/drm_fbdev_helper_ or
> > something like that :-)
> > -Daniel
> >
> >> ---
> >>  drivers/gpu/drm/drm_fb_helper.c    |  19 +++++--
> >>  drivers/gpu/drm/i915/i915_drv.c    |   1 +
> >>  drivers/gpu/drm/i915/intel_drv.h   |  11 ++++
> >>  drivers/gpu/drm/i915/intel_fbdev.c | 113 ++++++++++++++++++-------------------
> >>  include/drm/drm_drv.h              |  21 +++++++
> >>  5 files changed, 104 insertions(+), 61 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> >> index b992f59dad30..5407bf6dc8c0 100644
> >> --- a/drivers/gpu/drm/drm_fb_helper.c
> >> +++ b/drivers/gpu/drm/drm_fb_helper.c
> >> @@ -2103,6 +2103,20 @@ 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);
> >>
> >> +    mutex_lock(&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");
> >> +
> >> +    if (dev->driver->initial_client_display) {
> >> +            display = dev->driver->initial_client_display(dev, width, height);
> >> +            if (display) {
> >> +                    drm_client_display_free(fb_helper->display);
> >> +                    fb_helper->display = display;
> >> +                    mutex_unlock(&dev->mode_config.mutex);
> >> +                    return;
> >> +            }
> >> +    }
> >> +
> >>      crtcs = kcalloc(fb_helper->connector_count,
> >>                      sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
> >>      modes = kcalloc(fb_helper->connector_count,
> >> @@ -2120,9 +2134,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
> >>      if (IS_ERR(display))
> >>              goto out;
> >>
> >> -    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");
> >>      drm_enable_connectors(fb_helper, enabled);
> >>
> >>      if (!(fb_helper->funcs->initial_config &&
> >> @@ -2144,7 +2155,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
> >>
> >>              drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
> >>      }
> >> -    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 */
> >> @@ -2182,6 +2192,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
> >>      drm_client_display_free(fb_helper->display);
> >>      fb_helper->display = display;
> >>  out:
> >> +    mutex_unlock(&dev->mode_config.mutex);
> >>      kfree(crtcs);
> >>      kfree(modes);
> >>      kfree(offsets);
> >> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> >> index 07c07d55398b..b746c0cbaa4b 100644
> >> --- a/drivers/gpu/drm/i915/i915_drv.c
> >> +++ b/drivers/gpu/drm/i915/i915_drv.c
> >> @@ -2857,6 +2857,7 @@ static struct drm_driver driver = {
> >>
> >>      .dumb_create = i915_gem_dumb_create,
> >>      .dumb_map_offset = i915_gem_mmap_gtt,
> >> +    .initial_client_display = i915_initial_client_display,
> >>      .ioctls = i915_ioctls,
> >>      .num_ioctls = ARRAY_SIZE(i915_ioctls),
> >>      .fops = &i915_driver_fops,
> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> >> index d4368589b355..f77f510617c5 100644
> >> --- a/drivers/gpu/drm/i915/intel_drv.h
> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> >> @@ -1720,6 +1720,9 @@ extern void intel_fbdev_fini(struct drm_i915_private *dev_priv);
> >>  extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
> >>  extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
> >>  extern void intel_fbdev_restore_mode(struct drm_device *dev);
> >> +struct drm_client_display *
> >> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
> >> +                        unsigned int height);
> >>  #else
> >>  static inline int intel_fbdev_init(struct drm_device *dev)
> >>  {
> >> @@ -1749,6 +1752,14 @@ static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
> >>  static inline void intel_fbdev_restore_mode(struct drm_device *dev)
> >>  {
> >>  }
> >> +
> >> +static inline struct drm_client_display *
> >> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
> >> +                        unsigned int height)
> >> +{
> >> +    return NULL;
> >> +}
> >> +
> >>  #endif
> >>
> >>  /* intel_fbc.c */
> >> diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
> >> index a4ab8575a72e..b7f44c9475a8 100644
> >> --- a/drivers/gpu/drm/i915/intel_fbdev.c
> >> +++ b/drivers/gpu/drm/i915/intel_fbdev.c
> >> @@ -38,6 +38,7 @@
> >>  #include <linux/vga_switcheroo.h>
> >>
> >>  #include <drm/drmP.h>
> >> +#include <drm/drm_client.h>
> >>  #include <drm/drm_crtc.h>
> >>  #include <drm/drm_fb_helper.h>
> >>  #include "intel_drv.h"
> >> @@ -287,18 +288,6 @@ 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.
> >> @@ -326,44 +315,48 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
> >>   * 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_client_display *
> >> +i915_initial_client_display(struct drm_device *dev, unsigned int width,
> >> +                        unsigned int height)
> >>  {
> >> -    struct drm_i915_private *dev_priv = to_i915(fb_helper->dev);
> >> +    struct drm_i915_private *dev_priv = to_i915(dev);
> >>      unsigned long conn_configured, conn_seq, mask;
> >> -    unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
> >> -    int i, j;
> >> -    bool *save_enabled;
> >> -    bool fallback = true, ret = true;
> >> +    bool fallback = true, *enabled = NULL;
> >> +    struct drm_client_display *display;
> >> +    struct drm_connector **connectors;
> >> +    int i, connector_count;
> >> +    unsigned int count;
> >>      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;
> >> +    display = drm_client_display_create(dev);
> >> +    if (IS_ERR(display))
> >> +            return NULL;
> >>
> >>      drm_modeset_acquire_init(&ctx, 0);
> >>
> >> -    while (drm_modeset_lock_all_ctx(fb_helper->dev, &ctx) != 0)
> >> +    while (drm_modeset_lock_all_ctx(dev, &ctx) != 0)
> >>              drm_modeset_backoff(&ctx);
> >>
> >> -    memcpy(save_enabled, enabled, count);
> >> +    connector_count = drm_connector_get_all(dev, &connectors);
> >> +    if (connector_count < 1)
> >> +            goto bail;
> >> +
> >> +    enabled = drm_connector_get_enabled_status(connectors, connector_count);
> >> +    if (!enabled)
> >> +            goto bail;
> >> +
> >> +    count = min(connector_count, BITS_PER_LONG);
> >>      mask = GENMASK(count - 1, 0);
> >>      conn_configured = 0;
> >>  retry:
> >>      conn_seq = conn_configured;
> >>      for (i = 0; i < count; i++) {
> >> -            struct drm_fb_helper_connector *fb_conn;
> >> -            struct drm_connector *connector;
> >> +            struct drm_connector *connector = connectors[i];
> >> +            struct drm_display_mode *mode;
> >> +            struct drm_mode_set *modeset;
> >>              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;
> >> @@ -402,16 +395,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
> >>
> >>              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_client_display_for_each_modeset(modeset, display) {
> >> +                    if (modeset->connectors[0] == connector) {
> >>                              DRM_DEBUG_KMS("fallback: cloned configuration\n");
> >>                              goto bail;
> >>                      }
> >> @@ -421,28 +411,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
> >>                            connector->name);
> >>
> >>              /* go for command line mode first */
> >> -            modes[i] = drm_connector_pick_cmdline_mode(connector);
> >> +            mode = drm_connector_pick_cmdline_mode(connector);
> >>
> >>              /* try for preferred next */
> >> -            if (!modes[i]) {
> >> +            if (!mode) {
> >>                      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);
> >> +                    mode = 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)) {
> >> +            if (!mode && !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);
> >> +                    mode = list_first_entry(&connector->modes,
> >> +                                            struct drm_display_mode, head);
> >>              }
> >>
> >>              /* last resort: use current mode */
> >> -            if (!modes[i]) {
> >> +            if (!mode) {
> >>                      /*
> >>                       * IMPORTANT: We want to use the adjusted mode (i.e.
> >>                       * after the panel fitter upscaling) as the initial
> >> @@ -458,16 +446,26 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
> >>                       */
> >>                      DRM_DEBUG_KMS("looking for current mode on connector %s\n",
> >>                                    connector->name);
> >> -                    modes[i] = &connector->state->crtc->mode;
> >> +                    mode = &connector->state->crtc->mode;
> >>              }
> >> -            crtcs[i] = new_crtc;
> >> +
> >> +            modeset = drm_client_display_find_modeset(display, connector->state->crtc);
> >> +            if (WARN_ON(!modeset))
> >> +                    goto bail;
> >> +
> >> +            modeset->mode = drm_mode_duplicate(dev, mode);
> >> +            drm_connector_get(connector);
> >> +            modeset->connectors[0] = connector;
> >> +            modeset->num_connectors = 1;
> >> +            modeset->x = 0;
> >> +            modeset->y = 0;
> >>
> >>              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" :"");
> >> +                          mode->hdisplay, mode->vdisplay,
> >> +                          mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "");
> >>
> >>              fallback = false;
> >>              conn_configured |= BIT(i);
> >> @@ -492,19 +490,20 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
> >>      if (fallback) {
> >>  bail:
> >>              DRM_DEBUG_KMS("Not using firmware configuration\n");
> >> -            memcpy(enabled, save_enabled, count);
> >> -            ret = false;
> >> +            drm_client_display_free(display);
> >> +            display = NULL;
> >>      }
> >>
> >>      drm_modeset_drop_locks(&ctx);
> >>      drm_modeset_acquire_fini(&ctx);
> >>
> >> -    kfree(save_enabled);
> >> -    return ret;
> >> +    drm_connector_put_all(connectors, connector_count);
> >> +    kfree(enabled);
> >> +
> >> +    return display;
> >>  }
> >>
> >>  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_drv.h b/include/drm/drm_drv.h
> >> index 7e545f5f94d3..13356e6fd40c 100644
> >> --- a/include/drm/drm_drv.h
> >> +++ b/include/drm/drm_drv.h
> >> @@ -32,6 +32,7 @@
> >>
> >>  #include <drm/drm_device.h>
> >>
> >> +struct drm_client_display;
> >>  struct drm_file;
> >>  struct drm_gem_object;
> >>  struct drm_master;
> >> @@ -553,6 +554,26 @@ struct drm_driver {
> >>                          struct drm_device *dev,
> >>                          uint32_t handle);
> >>
> >> +    /**
> >> +     * @initial_client_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.
> >> +     */
> >> +    struct drm_client_display *(*initial_client_display)(struct drm_device *dev,
> >> +                                    unsigned int width, unsigned int height);
> >> +
> >>      /**
> >>       * @gem_vm_ops: Driver private ops for this object
> >>       */
> >> --
> >> 2.15.1
> >>
> >> _______________________________________________
> >> Intel-gfx mailing list
> >> Intel-gfx@lists.freedesktop.org
> >> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> >



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - 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] 46+ messages in thread

* [RFC v4 18/25] drm/client: Make the display modes available to clients
  2018-04-13 16:53 Noralf Trønnes
@ 2018-04-13 16:53 ` Noralf Trønnes
  0 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-13 16:53 UTC (permalink / raw)
  To: dri-devel; +Cc: daniel.vetter, intel-gfx, laurent.pinchart, mstaudt

Give clients easy access to the display modes.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c | 159 +++++++++++++++++++++++++++++++++----------
 include/drm/drm_client.h     |  25 +++++++
 2 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 764c556630b8..bce1630a0db2 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,6 +8,7 @@
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
  */
 
+#include <linux/list.h>
 #include <linux/slab.h>
 
 #include <drm/drm_atomic.h>
@@ -54,6 +55,7 @@ struct drm_client_display *drm_client_display_create(struct drm_device *dev)
 	}
 
 	display->dev = dev;
+	INIT_LIST_HEAD(&display->modes);
 	display->modeset_count = num_crtc;
 
 	drm_for_each_crtc(crtc, dev)
@@ -84,12 +86,16 @@ EXPORT_SYMBOL(drm_client_display_create);
  */
 void drm_client_display_free(struct drm_client_display *display)
 {
+	struct drm_display_mode *mode, *tmp;
 	struct drm_mode_set *modeset;
 	unsigned int i;
 
 	if (!display)
 		return;
 
+	list_for_each_entry_safe(mode, tmp, &display->modes, head)
+		drm_mode_destroy(display->dev, mode);
+
 	drm_client_display_for_each_modeset(modeset, display) {
 		if (modeset->mode)
 			drm_mode_destroy(display->dev, modeset->mode);
@@ -670,22 +676,70 @@ static int drm_pick_crtcs(struct drm_client_display *display,
 	return best_score;
 }
 
-/**
- * drm_client_find_display() - Find display
- * @dev: DRM device
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function returns a display the client can use if available.
- *
- * Free resources by calling drm_client_display_free().
- *
- * Returns:
- * A &drm_client_display on success, NULL if no connectors are found
- * or error pointer on failure.
- */
-struct drm_client_display *
-drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+/* Give the client a static list of display modes */
+static int drm_client_display_copy_modes(struct drm_client_display *display)
+{
+	int hdisplay = 0, vdisplay = 0, vrefresh;
+	struct drm_device *dev = display->dev;
+	struct drm_display_mode *mode, *copy;
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	unsigned int count = 0;
+
+	drm_client_display_for_each_modeset(modeset, display) {
+		if (!modeset->num_connectors || !modeset->mode)
+			continue;
+
+		connector = modeset->connectors[0];
+		mode = modeset->mode;
+		count++;
+
+		if (modeset->num_connectors == 2) {
+			/* Cloned output */
+			copy = drm_mode_duplicate(dev, modeset->mode);
+			if (!copy)
+				return -ENOMEM;
+			list_add_tail(&copy->head, &display->modes);
+			display->mode = copy;
+
+			return 0;
+		}
+
+		if (!modeset->y)
+			hdisplay += modeset->mode->hdisplay;
+		if (!modeset->x)
+			vdisplay += modeset->mode->vdisplay;
+		vrefresh = modeset->mode->vrefresh;
+	}
+
+	if (!count)
+		return 0;
+
+	if (count == 1) {
+		struct drm_display_mode *iter;
+
+		list_for_each_entry(iter, &connector->modes, head) {
+			copy = drm_mode_duplicate(dev, iter);
+			if (!copy)
+				return -ENOMEM;
+			list_add_tail(&copy->head, &display->modes);
+			if (!display->mode && drm_mode_equal(iter, mode))
+				display->mode = copy;
+		}
+	} else {
+		/* Combined tile mode. Only the default one for now */
+		copy = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, false, false, false);
+		if (!copy)
+			return -ENOMEM;
+		list_add_tail(&copy->head, &display->modes);
+		display->mode = copy;
+	}
+
+	return 0;
+}
+
+static struct drm_client_display *
+drm_client_find_display_default(struct drm_device *dev, unsigned int width, unsigned int height)
 {
 	struct drm_client_display_offset *offsets;
 	struct drm_client_display *display;
@@ -695,25 +749,6 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 	int i, connector_count;
 	bool *enabled;
 
-	DRM_DEBUG_KMS("\n");
-
-	if (!width)
-		width = dev->mode_config.max_width;
-	if (!height)
-		height = dev->mode_config.max_height;
-
-	mutex_lock(&dev->mode_config.mutex);
-	if (!drm_client_probe_connector_modes(dev, width, height))
-		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-
-	if (dev->driver->initial_client_display) {
-		display = dev->driver->initial_client_display(dev, width, height);
-		if (display) {
-			mutex_unlock(&dev->mode_config.mutex);
-			return display;
-		}
-	}
-
 	connector_count = drm_connector_get_all(dev, &connectors);
 	if (connector_count < 1)
 		return NULL;
@@ -772,7 +807,6 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 		}
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
 	drm_connector_put_all(connectors, connector_count);
 	kfree(crtcs);
 	kfree(modes);
@@ -781,4 +815,57 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 
 	return display;
 }
+
+/**
+ * drm_client_find_display() - Find display
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function returns a display the client can use if one is found.
+ *
+ * Free resources by calling drm_client_display_free().
+ *
+ * Returns:
+ * A &drm_client_display on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_client_display *
+drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+{
+	struct drm_client_display *display = NULL;
+	int ret;
+
+	DRM_DEBUG_KMS("\n");
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	if (!drm_client_probe_connector_modes(dev, width, height))
+		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+
+	if (dev->driver->initial_client_display)
+		display = dev->driver->initial_client_display(dev, width, height);
+
+	if (!display)
+		display = drm_client_find_display_default(dev, width, height);
+
+	if (IS_ERR_OR_NULL(display))
+		goto out_unlock;
+
+	ret = drm_client_display_copy_modes(display);
+	if (ret) {
+		drm_client_display_free(display);
+		display = ERR_PTR(ret);
+	}
+
+out_unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return display;
+}
 EXPORT_SYMBOL(drm_client_find_display);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 3befd879a0b0..524f793d6e7b 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,9 +3,12 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+#include <linux/types.h>
+
 struct drm_connector;
 struct drm_crtc;
 struct drm_device;
+struct drm_display_mode;
 struct drm_mode_set;
 struct drm_plane;
 
@@ -33,6 +36,20 @@ struct drm_client_display {
 	 * Number of modesets
 	 */
 	unsigned int modeset_count;
+
+	/**
+	 * @modes:
+	 *
+	 * Display modes available on this display.
+	 */
+	struct list_head modes;
+
+	/**
+	 * @mode:
+	 *
+	 * The current display mode.
+	 */
+	struct drm_display_mode *mode;
 };
 
 struct drm_client_display *drm_client_display_create(struct drm_device *dev);
@@ -51,4 +68,12 @@ int drm_client_display_dpms(struct drm_client_display *display, int mode);
 struct drm_client_display *
 drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height);
 
+/**
+ * drm_client_display_for_each_mode - Iterate over the available display modes
+ * @mode: A @drm_display_mode loop cursor
+ * @display: Client display
+ */
+#define drm_client_display_for_each_mode(mode, display) \
+	list_for_each_entry(mode, &display->modes, head)
+
 #endif
-- 
2.15.1

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

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

* [RFC v4 18/25] drm/client: Make the display modes available to clients
  2018-04-12 16:12 [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
@ 2018-04-12 16:12 ` Noralf Trønnes
  0 siblings, 0 replies; 46+ messages in thread
From: Noralf Trønnes @ 2018-04-12 16:12 UTC (permalink / raw)
  To: dri-devel
  Cc: daniel.vetter, intel-gfx, Noralf Trønnes, laurent.pinchart,
	mstaudt, dh.herrmann

Give clients easy access to the display modes.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/gpu/drm/drm_client.c | 159 +++++++++++++++++++++++++++++++++----------
 include/drm/drm_client.h     |  25 +++++++
 2 files changed, 148 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 764c556630b8..bce1630a0db2 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -8,6 +8,7 @@
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
  */
 
+#include <linux/list.h>
 #include <linux/slab.h>
 
 #include <drm/drm_atomic.h>
@@ -54,6 +55,7 @@ struct drm_client_display *drm_client_display_create(struct drm_device *dev)
 	}
 
 	display->dev = dev;
+	INIT_LIST_HEAD(&display->modes);
 	display->modeset_count = num_crtc;
 
 	drm_for_each_crtc(crtc, dev)
@@ -84,12 +86,16 @@ EXPORT_SYMBOL(drm_client_display_create);
  */
 void drm_client_display_free(struct drm_client_display *display)
 {
+	struct drm_display_mode *mode, *tmp;
 	struct drm_mode_set *modeset;
 	unsigned int i;
 
 	if (!display)
 		return;
 
+	list_for_each_entry_safe(mode, tmp, &display->modes, head)
+		drm_mode_destroy(display->dev, mode);
+
 	drm_client_display_for_each_modeset(modeset, display) {
 		if (modeset->mode)
 			drm_mode_destroy(display->dev, modeset->mode);
@@ -670,22 +676,70 @@ static int drm_pick_crtcs(struct drm_client_display *display,
 	return best_score;
 }
 
-/**
- * drm_client_find_display() - Find display
- * @dev: DRM device
- * @width: Maximum display mode width (optional)
- * @height: Maximum display mode height (optional)
- *
- * This function returns a display the client can use if available.
- *
- * Free resources by calling drm_client_display_free().
- *
- * Returns:
- * A &drm_client_display on success, NULL if no connectors are found
- * or error pointer on failure.
- */
-struct drm_client_display *
-drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+/* Give the client a static list of display modes */
+static int drm_client_display_copy_modes(struct drm_client_display *display)
+{
+	int hdisplay = 0, vdisplay = 0, vrefresh;
+	struct drm_device *dev = display->dev;
+	struct drm_display_mode *mode, *copy;
+	struct drm_connector *connector;
+	struct drm_mode_set *modeset;
+	unsigned int count = 0;
+
+	drm_client_display_for_each_modeset(modeset, display) {
+		if (!modeset->num_connectors || !modeset->mode)
+			continue;
+
+		connector = modeset->connectors[0];
+		mode = modeset->mode;
+		count++;
+
+		if (modeset->num_connectors == 2) {
+			/* Cloned output */
+			copy = drm_mode_duplicate(dev, modeset->mode);
+			if (!copy)
+				return -ENOMEM;
+			list_add_tail(&copy->head, &display->modes);
+			display->mode = copy;
+
+			return 0;
+		}
+
+		if (!modeset->y)
+			hdisplay += modeset->mode->hdisplay;
+		if (!modeset->x)
+			vdisplay += modeset->mode->vdisplay;
+		vrefresh = modeset->mode->vrefresh;
+	}
+
+	if (!count)
+		return 0;
+
+	if (count == 1) {
+		struct drm_display_mode *iter;
+
+		list_for_each_entry(iter, &connector->modes, head) {
+			copy = drm_mode_duplicate(dev, iter);
+			if (!copy)
+				return -ENOMEM;
+			list_add_tail(&copy->head, &display->modes);
+			if (!display->mode && drm_mode_equal(iter, mode))
+				display->mode = copy;
+		}
+	} else {
+		/* Combined tile mode. Only the default one for now */
+		copy = drm_cvt_mode(dev, hdisplay, vdisplay, vrefresh, false, false, false);
+		if (!copy)
+			return -ENOMEM;
+		list_add_tail(&copy->head, &display->modes);
+		display->mode = copy;
+	}
+
+	return 0;
+}
+
+static struct drm_client_display *
+drm_client_find_display_default(struct drm_device *dev, unsigned int width, unsigned int height)
 {
 	struct drm_client_display_offset *offsets;
 	struct drm_client_display *display;
@@ -695,25 +749,6 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 	int i, connector_count;
 	bool *enabled;
 
-	DRM_DEBUG_KMS("\n");
-
-	if (!width)
-		width = dev->mode_config.max_width;
-	if (!height)
-		height = dev->mode_config.max_height;
-
-	mutex_lock(&dev->mode_config.mutex);
-	if (!drm_client_probe_connector_modes(dev, width, height))
-		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-
-	if (dev->driver->initial_client_display) {
-		display = dev->driver->initial_client_display(dev, width, height);
-		if (display) {
-			mutex_unlock(&dev->mode_config.mutex);
-			return display;
-		}
-	}
-
 	connector_count = drm_connector_get_all(dev, &connectors);
 	if (connector_count < 1)
 		return NULL;
@@ -772,7 +807,6 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 		}
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
 	drm_connector_put_all(connectors, connector_count);
 	kfree(crtcs);
 	kfree(modes);
@@ -781,4 +815,57 @@ drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int
 
 	return display;
 }
+
+/**
+ * drm_client_find_display() - Find display
+ * @dev: DRM device
+ * @width: Maximum display mode width (optional)
+ * @height: Maximum display mode height (optional)
+ *
+ * This function returns a display the client can use if one is found.
+ *
+ * Free resources by calling drm_client_display_free().
+ *
+ * Returns:
+ * A &drm_client_display on success, NULL if no connectors are found
+ * or error pointer on failure.
+ */
+struct drm_client_display *
+drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height)
+{
+	struct drm_client_display *display = NULL;
+	int ret;
+
+	DRM_DEBUG_KMS("\n");
+
+	if (!width)
+		width = dev->mode_config.max_width;
+	if (!height)
+		height = dev->mode_config.max_height;
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	if (!drm_client_probe_connector_modes(dev, width, height))
+		DRM_DEBUG_KMS("No connectors reported connected with modes\n");
+
+	if (dev->driver->initial_client_display)
+		display = dev->driver->initial_client_display(dev, width, height);
+
+	if (!display)
+		display = drm_client_find_display_default(dev, width, height);
+
+	if (IS_ERR_OR_NULL(display))
+		goto out_unlock;
+
+	ret = drm_client_display_copy_modes(display);
+	if (ret) {
+		drm_client_display_free(display);
+		display = ERR_PTR(ret);
+	}
+
+out_unlock:
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return display;
+}
 EXPORT_SYMBOL(drm_client_find_display);
diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 3befd879a0b0..524f793d6e7b 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -3,9 +3,12 @@
 #ifndef _DRM_CLIENT_H_
 #define _DRM_CLIENT_H_
 
+#include <linux/types.h>
+
 struct drm_connector;
 struct drm_crtc;
 struct drm_device;
+struct drm_display_mode;
 struct drm_mode_set;
 struct drm_plane;
 
@@ -33,6 +36,20 @@ struct drm_client_display {
 	 * Number of modesets
 	 */
 	unsigned int modeset_count;
+
+	/**
+	 * @modes:
+	 *
+	 * Display modes available on this display.
+	 */
+	struct list_head modes;
+
+	/**
+	 * @mode:
+	 *
+	 * The current display mode.
+	 */
+	struct drm_display_mode *mode;
 };
 
 struct drm_client_display *drm_client_display_create(struct drm_device *dev);
@@ -51,4 +68,12 @@ int drm_client_display_dpms(struct drm_client_display *display, int mode);
 struct drm_client_display *
 drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height);
 
+/**
+ * drm_client_display_for_each_mode - Iterate over the available display modes
+ * @mode: A @drm_display_mode loop cursor
+ * @display: Client display
+ */
+#define drm_client_display_for_each_mode(mode, display) \
+	list_for_each_entry(mode, &display->modes, head)
+
 #endif
-- 
2.15.1

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

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

end of thread, other threads:[~2019-03-01 11:51 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-14 11:52 [RFC v4 00/25] drm: Add generic fbdev emulation Noralf Trønnes
2018-04-14 11:52 ` [RFC v4 01/25] drm: provide management functions for drm_file Noralf Trønnes
2018-04-14 11:52 ` [RFC v4 02/25] drm/file: Don't set master on in-kernel clients Noralf Trønnes
2018-04-14 11:52 ` [RFC v4 03/25] drm/fb-helper: No need to cache rotation and sw_rotations Noralf Trønnes
2018-04-14 11:52 ` [RFC v4 04/25] drm/fb-helper: Remove drm_fb_helper_debug_enter/leave() Noralf Trønnes
2018-04-14 11:52 ` [RFC v4 05/25] drm/fb-helper: dpms_legacy(): Only set on connectors in use Noralf Trønnes
2018-04-14 11:52 ` [RFC v4 06/25] drm/atomic: Move __drm_atomic_helper_disable_plane/set_config() Noralf Trønnes
2018-04-16  8:30   ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 07/25] drm: Begin an API for in-kernel clients Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 08/25] drm/fb-helper: Use struct drm_client_display Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 09/25] drm/fb-helper: Move modeset commit code to drm_client Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 10/25] drm/connector: Add drm_connector_has_preferred_mode/pick_cmdline_mode() Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 11/25] drm/connector: Add connector array functions Noralf Trønnes
2018-04-16  8:33   ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
2018-04-16  8:38   ` Daniel Vetter
2019-03-01 11:46     ` [Intel-gfx] " Noralf Trønnes
2019-03-01 11:51       ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 13/25] drm/fb-helper: Remove struct drm_fb_helper_crtc Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 14/25] drm/fb-helper: Remove struct drm_fb_helper_connector Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 15/25] drm/fb-helper: Move modeset config code to drm_client Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 16/25] drm: Make ioctls available for in-kernel clients Noralf Trønnes
2018-04-16  9:04   ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 17/25] drm/client: Bail out if there's a DRM master Noralf Trønnes
2018-04-16  8:45   ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 18/25] drm/client: Make the display modes available to clients Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 19/25] drm/client: Finish the in-kernel client API Noralf Trønnes
2018-04-16  8:27   ` [Intel-gfx] " Daniel Vetter
2018-04-16 15:58     ` Noralf Trønnes
2018-04-17  8:08       ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 20/25] drm/prime: Don't pin module on export for in-kernel clients Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 21/25] drm/fb-helper: Add drm_fb_helper_fb_open/release() Noralf Trønnes
2018-04-16  8:46   ` Daniel Vetter
2018-04-16 16:10     ` Noralf Trønnes
2018-04-17  8:14       ` [Intel-gfx] " Daniel Vetter
2018-04-14 11:53 ` [RFC v4 22/25] drm/fb-helper: Add generic fbdev emulation Noralf Trønnes
2018-04-16  8:52   ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 23/25] drm: Add DRM device registered notifier Noralf Trønnes
2018-04-17 10:16   ` Daniel Vetter
2018-04-14 11:53 ` [RFC v4 24/25] drm/client: Hack: Add bootsplash Noralf Trønnes
2018-04-14 11:53 ` [RFC v4 25/25] drm/client: Hack: Add DRM VT console client Noralf Trønnes
2018-04-16  8:21 ` [RFC v4 00/25] drm: Add generic fbdev emulation Daniel Vetter
2018-04-16 18:49   ` Noralf Trønnes
2018-04-17  8:10     ` [Intel-gfx] " Daniel Vetter
  -- strict thread matches above, loose matches on Subject: below --
2018-04-13 16:53 Noralf Trønnes
2018-04-13 16:53 ` [RFC v4 18/25] drm/client: Make the display modes available to clients Noralf Trønnes
2018-04-12 16:12 [RFC v4 12/25] drm/i915: Add drm_driver->initial_client_display callback Noralf Trønnes
2018-04-12 16:12 ` [RFC v4 18/25] drm/client: Make the display modes available to clients Noralf Trønnes

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).