All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: linux-media@vger.kernel.org
Cc: sakari.ailus@maxwell.research.nokia.com
Subject: [RFC/PATCH v3 05/10] media: Reference count and power handling
Date: Thu, 29 Jul 2010 18:06:38 +0200	[thread overview]
Message-ID: <1280419616-7658-6-git-send-email-laurent.pinchart@ideasonboard.com> (raw)
In-Reply-To: <1280419616-7658-1-git-send-email-laurent.pinchart@ideasonboard.com>

From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>

Basically these are the interface functions:

media_entity_get() - acquire entity
media_entity_put() - release entity

	If the entity is of node type, the power change is distributed to
	all connected entities. For non-nodes it only affects that very
	node. A mutex is used to serialise access to the entity graph.

In the background there's a depth-first search algorithm that traverses the
active links in the graph. All these functions parse the graph to implement
whatever they're to do.

The module counters are increased/decreased in media_entity_get/put to
prevent module unloading when an entity is referenced.

Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
---
 Documentation/media-framework.txt |   37 +++++++++
 drivers/media/media-device.c      |    1 +
 drivers/media/media-entity.c      |  146 +++++++++++++++++++++++++++++++++++++
 include/media/media-device.h      |    3 +
 include/media/media-entity.h      |   15 ++++
 5 files changed, 202 insertions(+), 0 deletions(-)

diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 4fe3b32..6d680c6 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -236,3 +236,40 @@ When the graph traversal is complete the function will return NULL.
 Graph traversal can be interrupted at any moment. No cleanup function call is
 required and the graph structure can be freed normally.
 
+
+Reference counting and power handling
+-------------------------------------
+
+Before accessing type-specific entities operations (such as the V4L2
+sub-device operations), drivers must acquire a reference to the entity. This
+ensures that the entity will be powered on and ready to accept requests.
+Similarly, after being done with an entity, drivers must release the
+reference.
+
+	media_entity_get(struct media_entity *entity)
+
+The function will increase the entity reference count. If the entity is a node
+(MEDIA_ENTITY_TYPE_NODE type), the reference count of all entities it is
+connected to, both directly or indirectly, through active links is increased.
+This ensures that the whole media pipeline will be ready to process
+
+Acquiring a reference to an entity increases the media device module reference
+count to prevent module unloading when an entity is being used.
+
+media_entity_get will return a pointer to the entity if successful, or NULL
+otherwise.
+
+	media_entity_put(struct media_entity *entity)
+
+The function will decrease the entity reference count and, for node entities,
+like media_entity_get, the reference count of all connected entities. Calling
+media_entity_put with a NULL argument is valid and will return immediately.
+
+When the first reference to an entity is acquired, or the last reference
+released, the entity's set_power operation is called. Entity drivers must
+implement the operation if they need to perform any power management task,
+such as turning powers or clocks on or off. If no power management is
+required, drivers don't need to provide a set_power operation. The operation
+is allowed to fail when turning power on, in which case the media_entity_get
+function will return NULL.
+
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index ed64b4a..6fb2e26 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -51,6 +51,7 @@ int __must_check media_device_register(struct media_device *mdev)
 	mdev->entity_id = 1;
 	INIT_LIST_HEAD(&mdev->entities);
 	spin_lock_init(&mdev->lock);
+	mutex_init(&mdev->graph_mutex);
 
 	/* If dev == NULL, then name must be filled in by the caller */
 	if (mdev->dev == NULL && WARN_ON(!mdev->devnode.name[0]))
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 443c5c9..e091bc8 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <media/media-entity.h>
+#include <media/media-device.h>
 
 /**
  * media_entity_init - Initialize a media entity
@@ -193,6 +194,151 @@ media_entity_graph_walk_next(struct media_entity_graph *graph)
 EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
 
 /* -----------------------------------------------------------------------------
+ * Power state handling
+ */
+
+/* Apply use count to an entity. */
+static void media_entity_use_apply_one(struct media_entity *entity, int change)
+{
+	entity->use_count += change;
+	WARN_ON(entity->use_count < 0);
+}
+
+/*
+ * Apply use count change to an entity and change power state based on
+ * new use count.
+ */
+static int media_entity_power_apply_one(struct media_entity *entity, int change)
+{
+	int ret;
+
+	if (entity->use_count == 0 && change > 0 &&
+	    entity->ops && entity->ops->set_power) {
+		ret = entity->ops->set_power(entity, 1);
+		if (ret)
+			return ret;
+	}
+
+	media_entity_use_apply_one(entity, change);
+
+	if (entity->use_count == 0 && change < 0 &&
+	    entity->ops && entity->ops->set_power)
+		entity->ops->set_power(entity, 0);
+
+	return 0;
+}
+
+/*
+ * Apply power change to all connected entities. This ignores the
+ * nodes.
+ */
+static int media_entity_power_apply(struct media_entity *entity, int change)
+{
+	struct media_entity_graph graph;
+	struct media_entity *first = entity;
+	int ret = 0;
+
+	if (!change)
+		return 0;
+
+	media_entity_graph_walk_start(&graph, entity);
+
+	while (!ret && (entity = media_entity_graph_walk_next(&graph)))
+		if (media_entity_type(entity) != MEDIA_ENTITY_TYPE_NODE)
+			ret = media_entity_power_apply_one(entity, change);
+
+	if (!ret)
+		return 0;
+
+	media_entity_graph_walk_start(&graph, first);
+
+	while ((first = media_entity_graph_walk_next(&graph))
+	       && first != entity)
+		if (media_entity_type(first) != MEDIA_ENTITY_TYPE_NODE)
+			media_entity_power_apply_one(first, -change);
+
+	return ret;
+}
+
+/*
+ * Apply use count change to graph and change power state of entities
+ * accordingly.
+ */
+static int media_entity_node_power_change(struct media_entity *entity,
+					  int change)
+{
+	/* Apply use count to node. */
+	media_entity_use_apply_one(entity, change);
+
+	/* Apply power change to connected non-nodes. */
+	return media_entity_power_apply(entity, change);
+}
+
+/*
+ * Node entity use changes are reflected on power state of all
+ * connected (directly or indirectly) entities whereas non-node entity
+ * use count changes are limited to that very entity.
+ */
+static int media_entity_use_change(struct media_entity *entity, int change)
+{
+	if (media_entity_type(entity) == MEDIA_ENTITY_TYPE_NODE)
+		return media_entity_node_power_change(entity, change);
+	else
+		return media_entity_power_apply_one(entity, change);
+}
+
+static struct media_entity *__media_entity_get(struct media_entity *entity)
+{
+	if (media_entity_use_change(entity, 1))
+		return NULL;
+
+	return entity;
+}
+
+static void __media_entity_put(struct media_entity *entity)
+{
+	media_entity_use_change(entity, -1);
+}
+
+/* user open()s media entity */
+struct media_entity *media_entity_get(struct media_entity *entity)
+{
+	struct media_entity *e;
+
+	if (entity == NULL)
+		return NULL;
+
+	if (entity->parent->dev &&
+	    !try_module_get(entity->parent->dev->driver->owner))
+		return NULL;
+
+	mutex_lock(&entity->parent->graph_mutex);
+	e = __media_entity_get(entity);
+	mutex_unlock(&entity->parent->graph_mutex);
+
+	if (e == NULL && entity->parent->dev)
+		module_put(entity->parent->dev->driver->owner);
+
+	return e;
+}
+EXPORT_SYMBOL_GPL(media_entity_get);
+
+/* user release()s media entity */
+void media_entity_put(struct media_entity *entity)
+{
+	if (entity == NULL)
+		return;
+
+	mutex_lock(&entity->parent->graph_mutex);
+	__media_entity_put(entity);
+	mutex_unlock(&entity->parent->graph_mutex);
+
+	if (entity->parent->dev)
+		module_put(entity->parent->dev->driver->owner);
+}
+EXPORT_SYMBOL_GPL(media_entity_put);
+
+/* -----------------------------------------------------------------------------
  * Links management
  */
 
diff --git a/include/media/media-device.h b/include/media/media-device.h
index ac96847..39a437c 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -23,6 +23,7 @@
 
 #include <linux/device.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
 
 #include <media/media-devnode.h>
@@ -48,6 +49,8 @@ struct media_device {
 
 	/* Protects the entities list */
 	spinlock_t lock;
+	/* Serializes graph operations. */
+	struct mutex graph_mutex;
 };
 
 int __must_check media_device_register(struct media_device *mdev);
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 05c37a6..2205cbc 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -33,6 +33,10 @@ struct media_pad {
 	unsigned long flags;		/* Pad flags (MEDIA_PAD_FLAG_*) */
 };
 
+struct media_entity_operations {
+	int (*set_power)(struct media_entity *entity, int power);
+};
+
 struct media_entity {
 	struct list_head list;
 	struct media_device *parent;	/* Media device this entity belongs to*/
@@ -50,6 +54,10 @@ struct media_entity {
 	struct media_pad *pads;		/* Pads array (num_pads elements) */
 	struct media_link *links;	/* Links array (max_links elements)*/
 
+	const struct media_entity_operations *ops;	/* Entity operations */
+
+	int use_count;			/* Use count for the entity. */
+
 	union {
 		/* Node specifications */
 		struct {
@@ -92,9 +100,16 @@ void media_entity_cleanup(struct media_entity *entity);
 int media_entity_create_link(struct media_entity *source, u8 source_pad,
 		struct media_entity *sink, u8 sink_pad, u32 flags);
 
+struct media_entity *media_entity_get(struct media_entity *entity);
+void media_entity_put(struct media_entity *entity);
+
 void media_entity_graph_walk_start(struct media_entity_graph *graph,
 		struct media_entity *entity);
 struct media_entity *
 media_entity_graph_walk_next(struct media_entity_graph *graph);
 
+#define media_entity_call(entity, operation, args...)			\
+	(((entity)->ops && (entity)->ops->operation) ?			\
+	 (entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
+
 #endif
-- 
1.7.1


  parent reply	other threads:[~2010-07-29 16:07 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-07-29 16:06 [RFC/PATCH v3 00/10] Media controller (core and V4L2) Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 01/10] media: Media device node support Laurent Pinchart
2010-08-01 11:14   ` Hans Verkuil
2010-08-02 13:55     ` Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 02/10] media: Media device Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 03/10] media: Entities, pads and links Laurent Pinchart
2010-07-30 14:00   ` Sakari Ailus
2010-08-02 14:05     ` Laurent Pinchart
2010-08-01 11:32   ` Hans Verkuil
2010-08-02 14:19     ` Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 04/10] media: Entity graph traversal Laurent Pinchart
2010-07-29 16:06 ` Laurent Pinchart [this message]
2010-07-29 16:06 ` [RFC/PATCH v3 06/10] media: Entities, pads and links enumeration Laurent Pinchart
2010-08-01 11:58   ` Hans Verkuil
2010-08-02 14:35     ` Laurent Pinchart
2010-08-02 21:01       ` Hans Verkuil
2010-08-03  9:22         ` Laurent Pinchart
2010-08-04 19:28           ` Marko Ristola
2010-08-05  9:38             ` Laurent Pinchart
2010-08-05 19:45               ` Marko Ristola
2010-07-29 16:06 ` [RFC/PATCH v3 07/10] media: Links setup Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 08/10] v4l: Add a media_device pointer to the v4l2_device structure Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 09/10] v4l: Make video_device inherit from media_entity Laurent Pinchart
2010-07-29 16:06 ` [RFC/PATCH v3 10/10] v4l: Make v4l2_subdev " Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 00/12] V4L2 API additions and OMAP3 ISP driver Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 01/12] v4l: Move the media/v4l2-mediabus.h header to include/linux Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 02/12] v4l: Add 16 bit YUYV and SGRBG10 media bus format codes Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 03/12] v4l: Create v4l2 subdev file handle structure Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 04/12] v4l-subdev: Add pads operations Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 05/12] v4l: v4l2_subdev userspace format API Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 06/12] v4l: Add subdev userspace API to enumerate and configure frame interval Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 07/12] v4l: Add crop ioctl to V4L2 subdev API Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 08/12] v4l: subdev: Generic ioctl support Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 09/12] ARM: OMAP3: Update Camera ISP definitions for OMAP3630 Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 10/12] omap3: Export omap3isp platform device structure Laurent Pinchart
2010-07-29 16:06 ` [SAMPLE v3 11/12] omap34xxcam: Register the ISP platform device during omap34xxcam probe Laurent Pinchart
2010-08-19 19:09 ` [RFC/PATCH v3 00/10] Media controller (core and V4L2) Aguirre, Sergio
2010-08-19 19:12   ` Laurent Pinchart
2010-08-19 19:13     ` Aguirre, Sergio
2010-08-20 15:25     ` Laurent Pinchart
2010-08-20 15:26       ` Aguirre, Sergio
2010-08-20 15:31         ` Laurent Pinchart

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=1280419616-7658-6-git-send-email-laurent.pinchart@ideasonboard.com \
    --to=laurent.pinchart@ideasonboard.com \
    --cc=linux-media@vger.kernel.org \
    --cc=sakari.ailus@maxwell.research.nokia.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.