All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Noralf Trønnes" <noralf@tronnes.org>
To: dri-devel@lists.freedesktop.org
Cc: intel-gfx@lists.freedesktop.org,
	"Noralf Trønnes" <noralf@tronnes.org>,
	laurent.pinchart@ideasonboard.com
Subject: [PATCH v2 08/12] drm/client: Add client callbacks
Date: Mon, 18 Jun 2018 16:17:35 +0200	[thread overview]
Message-ID: <20180618141739.48151-9-noralf@tronnes.org> (raw)
In-Reply-To: <20180618141739.48151-1-noralf@tronnes.org>

Add client callbacks and hook them up.
Add a list of clients per drm_device.

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

Changes since version 1:
- Remove unused functions
- Change name drm_client_funcs.lastclose -> .restore
- Change name drm_client_funcs.remove -> .unregister
- Rework unregister code


 drivers/gpu/drm/drm_client.c        | 97 +++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/drm_drv.c           |  7 +++
 drivers/gpu/drm/drm_fb_cma_helper.c |  2 +-
 drivers/gpu/drm/drm_file.c          |  3 ++
 drivers/gpu/drm/drm_probe_helper.c  |  3 ++
 include/drm/drm_client.h            | 69 +++++++++++++++++++++++++-
 include/drm/drm_device.h            | 14 ++++++
 7 files changed, 190 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 98dda40f5416..f1dc04d641cc 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -74,6 +74,7 @@ EXPORT_SYMBOL(drm_client_close);
  * @dev: DRM device
  * @client: DRM client
  * @name: Client name
+ * @funcs: DRM client functions (optional)
  *
  * Use drm_client_put() to free the client.
  *
@@ -81,8 +82,9 @@ EXPORT_SYMBOL(drm_client_close);
  * Zero on success or negative error code on failure.
  */
 int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
-		   const char *name)
+		   const char *name, const struct drm_client_funcs *funcs)
 {
+	bool registered;
 	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET) ||
@@ -91,12 +93,23 @@ int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
 
 	client->dev = dev;
 	client->name = name;
+	client->funcs = funcs;
 	kref_init(&client->ref);
 
 	ret = drm_client_open(client);
 	if (ret)
 		return ret;
 
+	mutex_lock(&dev->clientlist_mutex);
+	registered = dev->registered;
+	if (registered)
+		list_add(&client->list, &dev->clientlist);
+	mutex_unlock(&dev->clientlist_mutex);
+	if (!registered) {
+		drm_client_close(client);
+		return -ENODEV;
+	}
+
 	drm_dev_get(dev);
 
 	return 0;
@@ -110,8 +123,17 @@ static void drm_client_release(struct kref *ref)
 
 	DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name);
 
-	drm_client_close(client);
-	kfree(client);
+	mutex_lock(&dev->clientlist_mutex);
+	if (!list_empty(&client->list))
+		list_del(&client->list);
+	mutex_unlock(&dev->clientlist_mutex);
+
+	if (client->funcs && client->funcs->release) {
+		client->funcs->release(client);
+	} else {
+		drm_client_close(client);
+		kfree(client);
+	}
 
 	drm_dev_put(dev);
 }
@@ -145,6 +167,75 @@ void drm_client_put(struct drm_client_dev *client)
 }
 EXPORT_SYMBOL(drm_client_put);
 
+void drm_client_dev_unregister(struct drm_device *dev)
+{
+	struct drm_client_dev *client, *iter;
+
+	if (!drm_core_check_feature(dev, DRIVER_MODESET))
+		return;
+
+	do {
+		client = NULL;
+		mutex_lock(&dev->clientlist_mutex);
+		list_for_each_entry(iter, &dev->clientlist, list) {
+			list_del_init(&iter->list);
+			if (iter->funcs && iter->funcs->unregister) {
+				/* Make sure a release has not begun */
+				if (kref_get_unless_zero(&iter->ref)) {
+					client = iter;
+					break;
+				}
+			}
+		}
+		mutex_unlock(&dev->clientlist_mutex);
+		if (client) {
+			client->funcs->unregister(client);
+			drm_client_put(client);
+		}
+	} while (client);
+}
+
+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 || !client->funcs->hotplug)
+			continue;
+
+		ret = client->funcs->hotplug(client);
+		DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret);
+	}
+	mutex_unlock(&dev->clientlist_mutex);
+}
+EXPORT_SYMBOL(drm_client_dev_hotplug);
+
+void drm_client_dev_restore(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 || !client->funcs->restore)
+			continue;
+
+		ret = client->funcs->restore(client);
+		DRM_DEV_DEBUG_KMS(dev->dev, "%s: ret=%d\n", client->name, ret);
+		if (!ret) /* The first one to return zero gets the privilege to restore */
+			break;
+	}
+	mutex_unlock(&dev->clientlist_mutex);
+}
+
 static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
 {
 	struct drm_device *dev;
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 67ac793a7108..00172a3da62c 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>
 
@@ -506,6 +507,7 @@ int drm_dev_init(struct drm_device *dev,
 
 	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);
@@ -515,6 +517,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);
 
@@ -570,6 +573,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;
@@ -604,6 +608,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);
@@ -859,6 +864,8 @@ void drm_dev_unregister(struct drm_device *dev)
 
 	dev->registered = false;
 
+	drm_client_dev_unregister(dev);
+
 	if (drm_core_check_feature(dev, DRIVER_MODESET))
 		drm_modeset_unregister_all(dev);
 
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index dbd1933160d1..31831a7a6a99 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -182,7 +182,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
 
 	fb_helper = &fbdev_cma->fb_helper;
 
-	ret = drm_client_new(dev, &fb_helper->client, "fbdev");
+	ret = drm_client_new(dev, &fb_helper->client, "fbdev", NULL);
 	if (ret)
 		goto err_free;
 
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index 55505378df47..06e409007495 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_restore(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/include/drm/drm_client.h b/include/drm/drm_client.h
index 12ac2615b17d..80fe21c86f69 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -6,11 +6,61 @@
 #include <linux/kref.h>
 #include <linux/types.h>
 
+struct drm_client_dev;
 struct drm_device;
 struct drm_framebuffer;
 struct drm_gem_object;
 struct drm_minor;
 
+/**
+ * struct drm_client_funcs - DRM client callbacks
+ */
+struct drm_client_funcs {
+	/**
+	 * @release:
+	 *
+	 * Called when the reference count is dropped to zero. Users of this
+	 * callback is responsible for calling drm_client_close() and freeing
+	 * the client structure.
+	 *
+	 * This callback is optional.
+	 */
+	void (*release)(struct drm_client_dev *client);
+
+	/**
+	 * @unregister:
+	 *
+	 * Called when &drm_device is unregistered. The client should respond by
+	 * releasing it's resources using drm_client_put(). If it can't do so
+	 * due to resoruces being tied up, like fbdev with open file handles,
+	 * it should release it's resources as soon as possible.
+	 *
+	 * This callback is optional.
+	 */
+	void (*unregister)(struct drm_client_dev *client);
+
+	/**
+	 * @restore:
+	 *
+	 * 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 not called after @unregister has been called.
+	 *
+	 * This callback is optional.
+	 */
+	int (*restore)(struct drm_client_dev *client);
+
+	/**
+	 * @hotplug:
+	 *
+	 * Called on drm_kms_helper_hotplug_event().
+	 * This callback is not called after @unregister has been called.
+	 *
+	 * This callback is optional.
+	 */
+	int (*hotplug)(struct drm_client_dev *client);
+};
+
 /**
  * struct drm_client_dev - DRM client instance
  */
@@ -33,6 +83,19 @@ struct drm_client_dev {
 	 */
 	struct kref ref;
 
+	/**
+	 * @list:
+	 *
+	 * List of all clients of a DRM device, linked into
+	 * &drm_device.clientlist. Protected by &drm_device.clientlist_mutex.
+	 */
+	struct list_head list;
+
+	/**
+	 * @funcs: DRM client functions (optional)
+	 */
+	const struct drm_client_funcs *funcs;
+
 	/**
 	 * @file: DRM file
 	 */
@@ -41,10 +104,14 @@ struct drm_client_dev {
 
 void drm_client_close(struct drm_client_dev *client);
 int drm_client_new(struct drm_device *dev, struct drm_client_dev *client,
-		   const char *name);
+		   const char *name, const struct drm_client_funcs *funcs);
 void drm_client_get(struct drm_client_dev *client);
 void drm_client_put(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_restore(struct drm_device *dev);
+
 /**
  * struct drm_client_buffer - DRM client buffer
  */
diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
index 9e29976d4e98..f9c6e0e3aec7 100644
--- a/include/drm/drm_device.h
+++ b/include/drm/drm_device.h
@@ -81,6 +81,20 @@ struct drm_device {
 	 */
 	struct list_head filelist_internal;
 
+	/**
+	 * @clientlist_mutex:
+	 *
+	 * Protects @clientlist access.
+	 */
+	struct mutex clientlist_mutex;
+
+	/**
+	 * @clientlist:
+	 *
+	 * List of in-kernel clients. Protected by @clientlist_mutex.
+	 */
+	struct list_head clientlist;
+
 	/** \name Memory management */
 	/*@{ */
 	struct list_head maplist;	/**< Linked list of regions */
-- 
2.15.1

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

  parent reply	other threads:[~2018-06-18 14:17 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-18 14:17 [PATCH v2 00/12] drm: Add generic fbdev emulation Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 01/12] drm: provide management functions for drm_file Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 02/12] drm/file: Don't set master on in-kernel clients Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 03/12] drm: Make ioctls available for " Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 04/12] drm: Begin an API " Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 05/12] drm/fb-helper: Add generic fbdev emulation .fb_probe function Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 06/12] drm/pl111: Set .gem_prime_vmap and .gem_prime_mmap Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 07/12] drm/cma-helper: Use the generic fbdev emulation Noralf Trønnes
2018-06-18 14:17 ` Noralf Trønnes [this message]
2018-06-18 14:17 ` [PATCH v2 09/12] drm/debugfs: Add internal client debugfs file Noralf Trønnes
2018-06-20  9:23   ` [Intel-gfx] " Daniel Vetter
2018-06-18 14:17 ` [PATCH v2 10/12] drm/fb-helper: Finish the generic fbdev emulation Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 11/12] drm/tinydrm: Use drm_fbdev_generic_setup() Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 12/12] drm/cma-helper: Remove drm_fb_cma_fbdev_init_with_funcs() Noralf Trønnes
2018-06-18 15:05 ` ✗ Fi.CI.CHECKPATCH: warning for drm: Add generic fbdev emulation Patchwork
2018-06-18 15:09 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-06-18 15:20 ` ✓ Fi.CI.BAT: success " Patchwork
2018-06-18 20:02 ` ✓ Fi.CI.IGT: " Patchwork
2018-06-20  9:34 ` [PATCH v2 00/12] " Daniel Vetter
2018-06-20 13:52   ` [Intel-gfx] " Noralf Trønnes
2018-06-20 15:28     ` Noralf Trønnes
2018-06-21  7:14       ` Daniel Vetter
2018-06-21 17:19         ` Noralf Trønnes
2018-06-26 13:41           ` [Intel-gfx] " Noralf Trønnes
2018-06-26 13:42             ` Daniel Vetter
2018-06-25 14:28 ` Noralf Trønnes

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20180618141739.48151-9-noralf@tronnes.org \
    --to=noralf@tronnes.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=laurent.pinchart@ideasonboard.com \
    /path/to/YOUR_REPLY

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

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