All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCv4 00/21] Request API
@ 2018-02-20  4:44 Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 01/21] media: add request API core and UAPI Alexandre Courbot
                   ` (21 more replies)
  0 siblings, 22 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Hi everyone,

And thanks for all the feedback on the previous version! I have tried to address as much as possible, which results in (another) almost rewrite. But I think the behavior and structure are converging to something satisfying and usable.

Besides the buffer queuing behavior that has been fixed, some of the big design changes undertaken are that the media controller framework is not a requirement anymore (although it can still be used in exactly the same way as before), and that ioctls related to requests are now performed directly on the request FD.

As discussed with Sakari, the fact that request entities were in fact media entities was a bit limiting, so I created a request_entity type that can be embedded into any structure we want to control with requests. This is what allows drivers to support requests without the media controller: simple V4L2 drivers can use the V4L2 implementation that allows to control a single video device (as opposed to the whole pipeline under a media controller). Media controllers can still, of course, use a more complex implementation and control their whole pipeline, but bringing that complexity to simple drivers seemed overreached to me.

Independently of the request implementation, request entities can store their own data, in a way that makes sense regarding their type (that would be v4l2_request_entity_data for V4L2 devices, but can be another data type for media controllers topology).

The entity data lookup is also performed on these request_entities, working effectively like the data store Sakari proposed, but retaining a base type for data lookup.

Patches are organized as follows:

Patch 1 provides the base request support, not tied to either media or v4l2.

Patches 2 to 8 are the control rework done by Hans, with an extra workaround for a bug discovered while working on vivid (see commit message for details).

Patch 9 adds request support to V4L2 in the form of entity data for v4l2 devices to be used in requests, and a request manager capable of producing simple requests for video devices. Maybe this should be split into different files, but since the code is not that big I have kept it under the same file.

Patches 10 to 13 add request support to vb2-core and vb2-v4l2.

Patches 14 and 15 add support for the request_fd field in G/S/TRY_EXT_CTRLS ioctls.

Patch 16 allows requests to be allocated from a supporting V4L2 video device node.

Patches 17 and 19 add request support to mem2mem and vim2m. Patch 18 documents usage of requests with V4L2 devices.

Patch 20 adds support to the vivid capture device.

Finally, 21 is a WIP patch implementing request support for media controller nodes. Requests allocated that way are of a different, broader nature than V4L2 requests, and will be able to control any device managed by the controller. To allow this, request_entity is embedded into media_entity, so that media entities can be upcasted as in the previous version.

Phew! That was quite long, sorry about that. As usual, simple programs demonstrating requests on vim2m and vivid are available:

https://gist.github.com/Gnurou/34c35f1f8e278dad454b51578d239a42
https://gist.github.com/Gnurou/5052e6ab41e7c55164b75d2970bc5a04

If things are starting to look ok, I would like to move on to the next step and implement support in v4l2-ctl. Maybe also start submitting an actual codec driver once the control work is completed. And of course, it may be good time to think about how pipeline configuration would work. The current design should make this question orthogonal to getting support in for simple V4L2 devices.

Looking forward to your feedback!

Changes since RFC v3:
* Buffer queuing is now performed as soon as the request is queued, allowing drivers to see them early.
* Request refcounting is done using the file * structure instead of a kref
* Requests can now be used independently of a media controller, to avoid having to pull it for simple codec drivers. For such drivers, the device node can allocate requests that are exclusive to this device only. Media controller nodes can still allocate requests that control their topology as well as the devices under them.
* Consequently, media_request is now its own module since it can be used independently of media.ko.
* SUBMIT/REINIT request ioctls are now performed on the request FD instead of the media device. This means that device/media controller node's business with requests is limited to allocating them.
* Got rid of request IDs.
* Only allow one buffer to be queued to each queue of request entities.
* The request FD that produced a CAPTURE buffer is not returned to user-space anymore.
* Added requests support for the Vivid video capture device.
* Let drivers decide individually whether their entities should be per file handle or global to the device, solving the question we had about this in previous RFCs. Vim2m provides an example of per-context entities, while vivid gives an example of a global request entity.
* Improved documentation.

Issues remaining with this version:
* Vivid support exposed what seems to be a limitation in the current controls cloning implementation. See patch 8 (which works the issue around) for details.
* Media controller implementation of requests is still incomplete. I plan to complete and exert it on an actual camera driver sometime soon.


Alexandre Courbot (14):
  media: add request API core and UAPI
  [WAR] v4l2-ctrls: do not clone non-standard controls
  v4l2: add request API support
  media: v4l2_fh: add request entity field
  media: videobuf2: add support for requests
  media: videobuf2-v4l2: support for requests
  videodev2.h: add request_fd field to v4l2_ext_controls
  v4l2-ctrls: support requests in EXT_CTRLS ioctls
  v4l2: video_device: support for creating requests
  media: mem2mem: support for requests
  Documentation: v4l: document request API
  media: vim2m: add request support
  media: vivid: add request support for the video capture device
  [WIP] media: media-device: support for creating requests

Hans Verkuil (7):
  v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev
  v4l2-ctrls: prepare internal structs for request API
  v4l2-ctrls: add core request API
  v4l2-ctrls: use ref in helper instead of ctrl
  v4l2-ctrls: support g/s_ext_ctrls for requests
  v4l2-ctrls: add v4l2_ctrl_request_setup
  videodev2.h: Add request_fd field to v4l2_buffer

 Documentation/ioctl/ioctl-number.txt          |   1 +
 Documentation/media/uapi/v4l/buffer.rst       |   9 +-
 Documentation/media/uapi/v4l/common.rst       |   1 +
 Documentation/media/uapi/v4l/request-api.rst  | 199 ++++++++++
 Documentation/media/uapi/v4l/user-func.rst    |   1 +
 .../media/uapi/v4l/vidioc-g-ext-ctrls.rst     |  16 +-
 .../media/uapi/v4l/vidioc-new-request.rst     |  64 ++++
 Documentation/media/uapi/v4l/vidioc-qbuf.rst  |   7 +
 drivers/media/Kconfig                         |   3 +
 drivers/media/Makefile                        |   6 +
 .../media/common/videobuf2/videobuf2-core.c   |   3 +
 .../media/common/videobuf2/videobuf2-v4l2.c   | 131 ++++++-
 drivers/media/dvb-frontends/rtl2832_sdr.c     |   5 +-
 drivers/media/media-device.c                  |  11 +
 drivers/media/media-request.c                 | 341 +++++++++++++++++
 drivers/media/pci/bt8xx/bttv-driver.c         |   2 +-
 drivers/media/pci/cx23885/cx23885-417.c       |   2 +-
 drivers/media/pci/cx88/cx88-blackbird.c       |   2 +-
 drivers/media/pci/cx88/cx88-video.c           |   2 +-
 drivers/media/pci/saa7134/saa7134-empress.c   |   4 +-
 drivers/media/pci/saa7134/saa7134-video.c     |   2 +-
 drivers/media/platform/Kconfig                |   1 +
 .../media/platform/exynos4-is/fimc-capture.c  |   2 +-
 drivers/media/platform/omap3isp/ispvideo.c    |   2 +-
 drivers/media/platform/rcar-vin/rcar-v4l2.c   |   3 +-
 drivers/media/platform/rcar_drif.c            |   2 +-
 .../media/platform/soc_camera/soc_camera.c    |   3 +-
 drivers/media/platform/vim2m.c                |  75 ++++
 drivers/media/platform/vivid/Kconfig          |   1 +
 drivers/media/platform/vivid/vivid-core.c     |  63 +++-
 drivers/media/platform/vivid/vivid-core.h     |   3 +
 drivers/media/platform/vivid/vivid-ctrls.c    |  46 +--
 .../media/platform/vivid/vivid-kthread-cap.c  |  17 +
 drivers/media/usb/cpia2/cpia2_v4l.c           |   2 +-
 drivers/media/usb/cx231xx/cx231xx-417.c       |   2 +-
 drivers/media/usb/cx231xx/cx231xx-video.c     |   4 +-
 drivers/media/usb/msi2500/msi2500.c           |   2 +-
 drivers/media/usb/tm6000/tm6000-video.c       |   2 +-
 drivers/media/v4l2-core/Makefile              |   1 +
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   9 +-
 drivers/media/v4l2-core/v4l2-ctrls.c          | 341 +++++++++++++++--
 drivers/media/v4l2-core/v4l2-dev.c            |   2 +
 drivers/media/v4l2-core/v4l2-device.c         |   3 +-
 drivers/media/v4l2-core/v4l2-ioctl.c          |  37 +-
 drivers/media/v4l2-core/v4l2-mem2mem.c        |   3 +-
 drivers/media/v4l2-core/v4l2-request.c        | 178 +++++++++
 drivers/media/v4l2-core/v4l2-subdev.c         |   2 +-
 drivers/staging/media/imx/imx-media-dev.c     |   2 +-
 drivers/staging/media/imx/imx-media-fim.c     |   2 +-
 include/media/mc-request.h                    |  33 ++
 include/media/media-device.h                  |   1 +
 include/media/media-entity.h                  |   5 +
 include/media/media-request.h                 | 349 ++++++++++++++++++
 include/media/v4l2-ctrls.h                    |  20 +-
 include/media/v4l2-dev.h                      |   2 +
 include/media/v4l2-fh.h                       |   3 +
 include/media/v4l2-request.h                  | 159 ++++++++
 include/media/videobuf2-core.h                |   4 +
 include/media/videobuf2-v4l2.h                |  59 +++
 include/uapi/linux/media-request.h            |  37 ++
 include/uapi/linux/media.h                    |   2 +
 include/uapi/linux/videodev2.h                |   9 +-
 62 files changed, 2217 insertions(+), 88 deletions(-)
 create mode 100644 Documentation/media/uapi/v4l/request-api.rst
 create mode 100644 Documentation/media/uapi/v4l/vidioc-new-request.rst
 create mode 100644 drivers/media/media-request.c
 create mode 100644 drivers/media/v4l2-core/v4l2-request.c
 create mode 100644 include/media/mc-request.h
 create mode 100644 include/media/media-request.h
 create mode 100644 include/media/v4l2-request.h
 create mode 100644 include/uapi/linux/media-request.h

-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 01/21] media: add request API core and UAPI
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20 10:36   ` Hans Verkuil
  2018-02-20  4:44 ` [RFCv4 02/21] v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev Alexandre Courbot
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

The request API provides a way to group buffers and device parameters
into units of work to be queued and executed. This patch introduces the
UAPI and core framework.

This patch is based on the previous work by Laurent Pinchart. The core
has changed considerably, but the UAPI is mostly untouched.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/Kconfig              |   3 +
 drivers/media/Makefile             |   6 +
 drivers/media/media-request.c      | 341 ++++++++++++++++++++++++++++
 include/media/media-request.h      | 349 +++++++++++++++++++++++++++++
 include/uapi/linux/media-request.h |  37 +++
 5 files changed, 736 insertions(+)
 create mode 100644 drivers/media/media-request.c
 create mode 100644 include/media/media-request.h
 create mode 100644 include/uapi/linux/media-request.h

diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 145e12bfb819..db30fc9547d2 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -130,6 +130,9 @@ config VIDEO_V4L2_SUBDEV_API
 
 	  This API is mostly used by camera interfaces in embedded platforms.
 
+config MEDIA_REQUEST_API
+	tristate
+
 source "drivers/media/v4l2-core/Kconfig"
 
 #
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 594b462ddf0e..03c0a39ad344 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -5,6 +5,12 @@
 
 media-objs	:= media-device.o media-devnode.o media-entity.o
 
+#
+# Request API support comes as its own module since it can be used by
+# both media and video devices
+#
+obj-$(CONFIG_MEDIA_REQUEST_API) += media-request.o
+
 #
 # I2C drivers should come before other drivers, otherwise they'll fail
 # when compiled as builtin drivers
diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
new file mode 100644
index 000000000000..b88362028561
--- /dev/null
+++ b/drivers/media/media-request.c
@@ -0,0 +1,341 @@
+/*
+ * Request base implementation
+ *
+ * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/media-request.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+
+#include <media/media-request.h>
+
+const struct file_operations request_fops;
+
+static const char * const media_request_states[] __maybe_unused = {
+	"IDLE",
+	"SUBMITTED",
+	"COMPLETED",
+	"INVALID",
+};
+
+struct media_request *media_request_get(struct media_request *req)
+{
+	get_file(req->file);
+	return req;
+}
+EXPORT_SYMBOL_GPL(media_request_get);
+
+struct media_request *media_request_get_from_fd(int fd)
+{
+	struct file *f;
+
+	f = fget(fd);
+	if (!f)
+		return NULL;
+
+	/* Not a request FD? */
+	if (f->f_op != &request_fops) {
+		fput(f);
+		return NULL;
+	}
+
+	return f->private_data;
+}
+EXPORT_SYMBOL_GPL(media_request_get_from_fd);
+
+void media_request_put(struct media_request *req)
+{
+	if (WARN_ON(req == NULL))
+		return;
+
+	fput(req->file);
+}
+EXPORT_SYMBOL_GPL(media_request_put);
+
+struct media_request_entity_data *
+media_request_get_entity_data(struct media_request *req,
+			      struct media_request_entity *entity)
+{
+	struct media_request_entity_data *data;
+
+	/* First check that this entity is valid for this request at all */
+	if (!req->mgr->ops->entity_valid(req, entity))
+		return ERR_PTR(-EINVAL);
+
+	mutex_lock(&req->lock);
+
+	/* Lookup whether we already have entity data */
+	list_for_each_entry(data, &req->data, list) {
+		if (data->entity == entity)
+			goto out;
+	}
+
+	/* No entity data found, let's create it */
+	data = entity->ops->data_alloc(req, entity);
+	if (IS_ERR(data))
+		goto out;
+
+	data->entity = entity;
+	list_add_tail(&data->list, &req->data);
+
+out:
+	mutex_unlock(&req->lock);
+
+	return data;
+}
+EXPORT_SYMBOL_GPL(media_request_get_entity_data);
+
+static unsigned int media_request_poll(struct file *file, poll_table *wait)
+{
+	struct media_request *req = file->private_data;
+
+	poll_wait(file, &req->complete_wait, wait);
+
+	if (req->state == MEDIA_REQUEST_STATE_COMPLETED)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int media_request_release(struct inode *inode, struct file *filp)
+{
+	struct media_request *req = filp->private_data;
+
+	if (req == NULL)
+		return 0;
+
+	req->mgr->ops->release(req);
+	return 0;
+}
+
+static long media_request_ioctl_submit(struct media_request *req)
+{
+	mutex_lock(&req->lock);
+
+	if (req->state != MEDIA_REQUEST_STATE_IDLE) {
+		dev_warn(req->mgr->dev, "cannot submit request in state %s\n",
+			 media_request_states[req->state]);
+		mutex_unlock(&req->lock);
+		return -EINVAL;
+	}
+
+	req->state = MEDIA_REQUEST_STATE_SUBMITTED;
+
+	/*
+	 * Nothing can change our state when we are submitted - no need to keep
+	 * holding that lock.
+	 */
+	mutex_unlock(&req->lock);
+
+	/* Keep a reference to the request until it is completed */
+	media_request_get(req);
+
+	return req->mgr->ops->submit(req);
+}
+
+static long media_request_ioctl_reinit(struct media_request *req)
+{
+	struct media_request_entity_data *data, *next;
+        LIST_HEAD(to_delete);
+
+	mutex_lock(&req->lock);
+
+	if (req->state == MEDIA_REQUEST_STATE_SUBMITTED) {
+		dev_warn(req->mgr->dev,
+			"%s: unable to reinit submitted request\n", __func__);
+		mutex_unlock(&req->lock);
+		return -EINVAL;
+	}
+
+	/* delete all entity data */
+	list_for_each_entry_safe(data, next, &req->data, list) {
+		list_del(&data->list);
+                list_add(&data->list, &to_delete);
+	}
+
+	/* reinitialize request to idle state */
+	req->state = MEDIA_REQUEST_STATE_IDLE;
+
+	mutex_unlock(&req->lock);
+
+        list_for_each_entry_safe(data, next, &to_delete, list)
+		data->entity->ops->data_free(data);
+
+	return 0;
+}
+
+#define MEDIA_REQUEST_IOC(__cmd, func)					\
+	[_IOC_NR(MEDIA_REQUEST_IOC_##__cmd) - 0x80] = {			\
+		.cmd = MEDIA_REQUEST_IOC_##__cmd,			\
+		.fn = func,						\
+	}
+
+struct media_request_ioctl_info {
+	unsigned int cmd;
+	long (*fn)(struct media_request *req);
+};
+
+static const struct media_request_ioctl_info ioctl_info[] = {
+	MEDIA_REQUEST_IOC(SUBMIT, media_request_ioctl_submit),
+	MEDIA_REQUEST_IOC(REINIT, media_request_ioctl_reinit),
+};
+
+static long media_request_ioctl(struct file *filp, unsigned int cmd,
+				unsigned long __arg)
+{
+	struct media_request *req = filp->private_data;
+	const struct media_request_ioctl_info *info;
+
+	if ((_IOC_NR(cmd) < 0x80) ||
+	     _IOC_NR(cmd) >= 0x80 + ARRAY_SIZE(ioctl_info) ||
+	     ioctl_info[_IOC_NR(cmd) - 0x80].cmd != cmd)
+		return -ENOIOCTLCMD;
+
+	info = &ioctl_info[_IOC_NR(cmd) - 0x80];
+
+	return info->fn(req);
+}
+
+const struct file_operations request_fops = {
+	.owner = THIS_MODULE,
+	.poll = media_request_poll,
+	.release = media_request_release,
+	.unlocked_ioctl = media_request_ioctl,
+};
+
+static void media_request_complete(struct media_request *req)
+{
+	struct device *dev = req->mgr->dev;
+
+	mutex_lock(&req->lock);
+
+	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_SUBMITTED)) {
+		dev_warn(dev, "can't complete request in state %s\n",
+			media_request_states[req->state]);
+		mutex_unlock(&req->lock);
+		return;
+	}
+
+	req->state = MEDIA_REQUEST_STATE_COMPLETED;
+
+	wake_up_interruptible(&req->complete_wait);
+
+	mutex_unlock(&req->lock);
+
+	/* Release the reference acquired when we submitted the request */
+	media_request_put(req);
+}
+
+void media_request_entity_complete(struct media_request *req,
+				   struct media_request_entity *completed)
+{
+	struct media_request_entity_data *data;
+	int cpt = 0;
+
+	list_for_each_entry(data, &req->data, list) {
+		if (data->entity == completed)
+			data->completed = true;
+		if (!data->completed)
+			++cpt;
+	}
+
+	if (cpt == 0)
+		media_request_complete(req);
+}
+EXPORT_SYMBOL_GPL(media_request_entity_complete);
+
+long media_request_ioctl_new(struct media_request_mgr *mgr,
+			     struct media_request_new *new)
+{
+	struct media_request *req;
+	int err;
+	int fd;
+
+	/* User only wants to check the availability of requests? */
+	if (new->flags & MEDIA_REQUEST_FLAG_TEST)
+		return 0;
+
+	fd = get_unused_fd_flags(O_CLOEXEC);
+	if (fd < 0)
+		return fd;
+
+	req = mgr->ops->alloc(mgr);
+	if (IS_ERR(req)) {
+		err = PTR_ERR(req);
+		goto out_fd;
+	}
+
+	req->file = anon_inode_getfile("request", &request_fops, req,
+				       O_CLOEXEC);
+	if (IS_ERR(req->file)) {
+		err = PTR_ERR(req->file);
+		mgr->ops->release(req);
+		goto out_fd;
+	}
+
+	fd_install(fd, req->file);
+	new->fd = fd;
+
+	return 0;
+
+out_fd:
+	put_unused_fd(fd);
+	return err;
+}
+EXPORT_SYMBOL_GPL(media_request_ioctl_new);
+
+void media_request_entity_init(struct media_request_entity *entity,
+			       enum media_request_entity_type type,
+			       const struct media_request_entity_ops *ops)
+{
+	entity->type = type;
+	entity->ops = ops;
+}
+EXPORT_SYMBOL_GPL(media_request_entity_init);
+
+void media_request_mgr_init(struct media_request_mgr *mgr, struct device *dev,
+			    const struct media_request_ops *ops)
+{
+	mgr->dev = dev;
+	mutex_init(&mgr->mutex);
+	INIT_LIST_HEAD(&mgr->requests);
+	mgr->ops = ops;
+}
+EXPORT_SYMBOL_GPL(media_request_mgr_init);
+
+void media_request_mgr_free(struct media_request_mgr *mgr)
+{
+	struct device *dev = mgr->dev;
+
+	/* Just a sanity check - we should have no remaining requests */
+	while (!list_empty(&mgr->requests)) {
+		struct media_request *req;
+
+		req = list_first_entry(&mgr->requests, typeof(*req), list);
+		dev_warn(dev,
+			"%s: request still referenced, deleting forcibly!\n",
+			__func__);
+		mgr->ops->release(req);
+	}
+}
+EXPORT_SYMBOL_GPL(media_request_mgr_free);
+
+MODULE_AUTHOR("Alexandre Courbot <acourbot@chromium.org>");
+MODULE_DESCRIPTION("Core support for media request API");
+MODULE_LICENSE("GPL");
diff --git a/include/media/media-request.h b/include/media/media-request.h
new file mode 100644
index 000000000000..110dcdc1099f
--- /dev/null
+++ b/include/media/media-request.h
@@ -0,0 +1,349 @@
+/*
+ * Media requests.
+ *
+ * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIA_REQUEST_H
+#define _MEDIA_REQUEST_H
+
+struct media_request;
+struct media_request_entity;
+struct media_request_entity_data;
+struct media_request_mgr;
+struct media_request_new;
+
+#include <linux/kconfig.h>
+
+enum media_request_state {
+	MEDIA_REQUEST_STATE_IDLE,
+	MEDIA_REQUEST_STATE_SUBMITTED,
+	MEDIA_REQUEST_STATE_COMPLETED,
+	MEDIA_REQUEST_STATE_INVALID,
+};
+
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/wait.h>
+
+/**
+ * struct media_request_entity_ops - request entity operations
+ *
+ * @data_alloc:	allocate memory to store that entity's relevant state
+ * @data_free:	free state previously allocated with data_alloc
+ * @submit:	perform all required actions to be ready to process that request
+ */
+struct media_request_entity_ops {
+	struct media_request_entity_data *
+		(*data_alloc)(struct media_request *req,
+			      struct media_request_entity *entity);
+	void (*data_free)(struct media_request_entity_data *data);
+	int (*submit)(struct media_request *req,
+		      struct media_request_entity_data *data);
+};
+
+/**
+ * enum media_request_entity_type - describe type of an entity
+ *
+ * This type lets us know the upper kind of a struct media_request_entity
+ * instance.
+ *
+ * @MEDIA_REQUEST_ENTITY_TYPE_V4L2:	instance can be upcasted to
+ * 					v4l2_request_entity
+ * @MEDIA_REQUEST_ENTITY_TYPE_MC:	instance can be updated to
+ * 					mc_request_entity
+ *
+ */
+enum media_request_entity_type {
+	MEDIA_REQUEST_ENTITY_TYPE_V4L2,
+	MEDIA_REQUEST_ENTITY_TYPE_MC,
+};
+
+/**
+ * struct media_request_entity - request entity base structure
+ *
+ * @type:	type of entity, indicating which upcast is safe to perform
+ * @ops:	operations that this entity can perform
+ *
+ * This structure is supposed to be embedded into a larger structure
+ * better representing the specifics of the instance (e.g. v4l2_request_entity
+ * for controlling V4L2 devices).
+ *
+ */
+struct media_request_entity {
+	enum media_request_entity_type type;
+	const struct media_request_entity_ops *ops;
+};
+
+/**
+ * media_request_entity_init() - initialize a request entity's base properties
+ *
+ * @entity:	entity to initialize
+ * @type:	type of this entity
+ * @ops:	operations that this entity will perform
+ */
+void media_request_entity_init(struct media_request_entity *entity,
+			       enum media_request_entity_type type,
+			       const struct media_request_entity_ops *ops);
+
+/**
+ * struct media_request_entity_data - per-entity request data
+ *
+ * @request:	request instance this data belongs to
+ * @entity:	entity that stores data here
+ * @list:	entry in media_request::data
+ * @completed:	whether this entity has completed its part of the request
+ *
+ * Base structure used to store request state data. To be extended by actual
+ * implementation.
+ *
+ */
+struct media_request_entity_data {
+	struct media_request *request;
+	struct media_request_entity *entity;
+	struct list_head list;
+	bool completed;
+};
+
+/**
+ * struct media_request - Media request base structure
+ *
+ * @mgr:	manager this request belongs to
+ * @file:	used to export FDs to user-space and reference count
+ * @list:	entry in the media_request_mgr::requests list
+ * @lock:	protects following members against concurrent accesses
+ * @state:	current state of the request
+ * @data:	per-entity data list
+ * @complete_wait:	wait queue that signals once the request has completed
+ */
+struct media_request {
+	struct media_request_mgr *mgr;
+	struct file *file;
+	struct list_head list;
+
+	struct mutex lock;
+	enum media_request_state state;
+	struct list_head data;
+	wait_queue_head_t complete_wait;
+};
+
+/**
+ * media_request_get() - increment the reference counter of a request
+ *
+ * The calling context must call media_request_put() once it does not need
+ * the reference to the request anymore.
+ *
+ * Returns the request that has been passed as argument.
+ *
+ * @req:	request to acquire a reference of
+ */
+struct media_request *media_request_get(struct media_request *req);
+
+/**
+ * media_request_get_from_fd() - lookup request by fd and acquire a reference.
+ *
+ * Look a request up from its fd, acquire a reference and return a pointer to
+ * the request. As for media_request_get(), media_request_put() must be called
+ * once the reference is not used anymore.
+ *
+ * @req:	request to lookup and acquire.
+ *
+ */
+struct media_request *media_request_get_from_fd(int fd);
+
+/**
+ * media_request_put() - decrement the reference counter of a request
+ *
+ * Mirror function of media_request_get() and media_request_get_from_fd(). Will
+ * free the request if this was the last valid reference.
+ *
+ * @req:	request to release.
+ */
+void media_request_put(struct media_request *req);
+
+/**
+ * media_request_lock() - prevent concurrent access to that request
+ *
+ * @req:	request to lock
+ */
+static inline void media_request_lock(struct media_request *req)
+{
+	mutex_lock(&req->lock);
+}
+
+/**
+ * media_request_unlock() - release previously acquired request lock
+ *
+ * @req:	request to release
+ */
+static inline void media_request_unlock(struct media_request *req)
+{
+	mutex_unlock(&req->lock);
+}
+
+/**
+ * media_request_get_state() - get the state of a request
+ *
+ * @req:	request which state we are interested in
+ *
+ * The request lock should always be acquired when confirming this value
+ * to avoid race conditions.
+ *
+ */
+static inline enum media_request_state
+media_request_get_state(struct media_request *req)
+{
+	return req->state;
+}
+
+/**
+ * media_request_get_entity_data() - get per-entity data for a request
+ * @req:	request to get entity data from
+ * @entity:	entity to get data of
+ *
+ * Search and return the entity data associated associated to the request. If no
+ * such data exists, it is allocated as per the entity operations.
+ *
+ * Returns the per-entity data, or an error code if a problem happened. -EINVAL
+ * means that data for the entity already existed, but has been allocated under
+ * a different cookie.
+ */
+struct media_request_entity_data *
+media_request_get_entity_data(struct media_request *req,
+			      struct media_request_entity *entity);
+
+/**
+ * media_request_entity_complete() - to be invoked when an entity completes its
+ *				     part of the request
+ *
+ * @req:	request which has completed
+ * @completed:	entity that has completed
+ */
+void media_request_entity_complete(struct media_request *req,
+				   struct media_request_entity *completed);
+
+/**
+ * media_request_ioctl_new() - process a NEW_REQUEST ioctl
+ *
+ * @mgr:	request manager from which to allocate the request
+ * @new:	media_request_new structure to be passed back to user-space
+ *
+ * This function is a helper to be called by actual handlers of *_NEW_REQUEST
+ * ioctls.
+ */
+long media_request_ioctl_new(struct media_request_mgr *mgr,
+			     struct media_request_new *new);
+
+/**
+ * struct media_request_ops - request operations
+ *
+ * @alloc:	allocate a request
+ * @release:	free a previously allocated request
+ * @entity_valid:	returns whether a given entity is valid for that request
+ * @submit:	allow the request to be processed
+ *
+ * This structure allows to specialize requests to a specific scope. For
+ * instance, requests obtained from a V4L2 device node should only be able to
+ * control that device. On the other hand, requests created from a media
+ * controller node will be able to control all the devices managed by this
+ * controller, and may want to implement some form of synchronization between
+ * them.
+ */
+struct media_request_ops {
+	struct media_request *(*alloc)(struct media_request_mgr *mgr);
+	void (*release)(struct media_request *req);
+	bool (*entity_valid)(const struct media_request *req,
+			     const struct media_request_entity *entity);
+	int (*submit)(struct media_request *req);
+};
+
+/**
+ * struct media_request_mgr - requests manager
+ *
+ * @dev:	device owning this manager
+ * @ops:	implementation of the manager
+ * @mutex:	protects the requests list_head
+ * @requests:	list of alive requests produced by this manager
+ *
+ * This structure is mainly responsible for allocating requests. Although it is
+ * not strictly required for that purpose, having it allows us to account for
+ * all requests created by a given device, and to make sure they are all
+ * discarded by the time the device is destroyed.
+ */
+struct media_request_mgr {
+	struct device *dev;
+	const struct media_request_ops *ops;
+
+	struct mutex mutex;
+	struct list_head requests;
+};
+
+/**
+ * media_request_mgr_init() - initialize a request manager.
+ *
+ * @mgr:	manager to initialize
+ */
+void media_request_mgr_init(struct media_request_mgr *mgr, struct device *dev,
+			    const struct media_request_ops *ops);
+
+/**
+ * media_request_mgr_free() - free a media manager
+ *
+ * This should only be called when all requests produced by this manager
+ * has been destroyed. Will warn if that is not the case.
+ */
+void media_request_mgr_free(struct media_request_mgr *mgr);
+
+#else /* CONFIG_MEDIA_REQUEST_API */
+
+static inline void media_request_entity_complete(struct media_request *req,
+					 struct media_request_entity *completed)
+{
+}
+
+static inline struct media_request_entity_data *
+media_request_get_entity_data(struct media_request *req,
+			      struct media_request_entity *entity)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+
+static inline long media_request_ioctl_new(struct media_request_mgr *mgr,
+					   struct media_request_new *new)
+{
+	return -ENOTTY;
+}
+
+static inline void media_request_put(struct media_request *req)
+{
+}
+
+static inline void media_request_lock(struct media_request *req)
+{
+}
+
+static inline void media_request_unlock(struct media_request *req)
+{
+}
+
+static inline enum media_request_state
+media_request_get_state(struct media_request *req)
+{
+	return MEDIA_REQUEST_STATE_INVALID;
+}
+
+#endif /* CONFIG_MEDIA_REQUEST_API */
+
+#endif
diff --git a/include/uapi/linux/media-request.h b/include/uapi/linux/media-request.h
new file mode 100644
index 000000000000..5d30f731a442
--- /dev/null
+++ b/include/uapi/linux/media-request.h
@@ -0,0 +1,37 @@
+/*
+ * Media requests UAPI
+ *
+ * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_MEDIA_REQUEST_H
+#define __LINUX_MEDIA_REQUEST_H
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+/* Only check that requests can be used, do not allocate */
+#define MEDIA_REQUEST_FLAG_TEST			0x00000001
+
+struct media_request_new {
+	__u32 flags;
+	__s32 fd;
+} __attribute__ ((packed));
+
+#define MEDIA_REQUEST_IOC_SUBMIT	  _IO('|',  128)
+#define MEDIA_REQUEST_IOC_REINIT	  _IO('|',  129)
+
+#endif
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 02/21] v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 01/21] media: add request API core and UAPI Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 03/21] v4l2-ctrls: prepare internal structs for request API Alexandre Courbot
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

Add a 'bool from_other_dev' argument: set to true if the two
handlers refer to different devices (e.g. it is true when
inheriting controls from a subdev into a main v4l2 bridge
driver).

This will be used later when implementing support for the
request API since we need to skip such controls.

TODO: check drivers/staging/media/imx/imx-media-fim.c change.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/dvb-frontends/rtl2832_sdr.c     |  5 +-
 drivers/media/pci/bt8xx/bttv-driver.c         |  2 +-
 drivers/media/pci/cx23885/cx23885-417.c       |  2 +-
 drivers/media/pci/cx88/cx88-blackbird.c       |  2 +-
 drivers/media/pci/cx88/cx88-video.c           |  2 +-
 drivers/media/pci/saa7134/saa7134-empress.c   |  4 +-
 drivers/media/pci/saa7134/saa7134-video.c     |  2 +-
 .../media/platform/exynos4-is/fimc-capture.c  |  2 +-
 drivers/media/platform/rcar-vin/rcar-v4l2.c   |  3 +-
 drivers/media/platform/rcar_drif.c            |  2 +-
 .../media/platform/soc_camera/soc_camera.c    |  3 +-
 drivers/media/platform/vivid/vivid-ctrls.c    | 46 +++++++++----------
 drivers/media/usb/cx231xx/cx231xx-417.c       |  2 +-
 drivers/media/usb/cx231xx/cx231xx-video.c     |  4 +-
 drivers/media/usb/msi2500/msi2500.c           |  2 +-
 drivers/media/usb/tm6000/tm6000-video.c       |  2 +-
 drivers/media/v4l2-core/v4l2-ctrls.c          | 11 +++--
 drivers/media/v4l2-core/v4l2-device.c         |  3 +-
 drivers/staging/media/imx/imx-media-dev.c     |  2 +-
 drivers/staging/media/imx/imx-media-fim.c     |  2 +-
 include/media/v4l2-ctrls.h                    |  4 +-
 21 files changed, 58 insertions(+), 49 deletions(-)

diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index c6e78d870ccd..6064d28224e8 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -1394,7 +1394,8 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
 	case RTL2832_SDR_TUNER_E4000:
 		v4l2_ctrl_handler_init(&dev->hdl, 9);
 		if (subdev)
-			v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, NULL);
+			v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler,
+					      NULL, true);
 		break;
 	case RTL2832_SDR_TUNER_R820T:
 	case RTL2832_SDR_TUNER_R828D:
@@ -1423,7 +1424,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
 		v4l2_ctrl_handler_init(&dev->hdl, 2);
 		if (subdev)
 			v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler,
-					      NULL);
+					      NULL, true);
 		break;
 	default:
 		v4l2_ctrl_handler_init(&dev->hdl, 0);
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index f697698fe38d..cdcb36d8c5c3 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -4211,7 +4211,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
 	/* register video4linux + input */
 	if (!bttv_tvcards[btv->c.type].no_video) {
 		v4l2_ctrl_add_handler(&btv->radio_ctrl_handler, hdl,
-				v4l2_ctrl_radio_filter);
+				v4l2_ctrl_radio_filter, false);
 		if (btv->radio_ctrl_handler.error) {
 			result = btv->radio_ctrl_handler.error;
 			goto fail2;
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index a71f3c7569ce..762823871c78 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1527,7 +1527,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
 	dev->cxhdl.priv = dev;
 	dev->cxhdl.func = cx23885_api_func;
 	cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
-	v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL);
+	v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL, false);
 
 	/* Allocate and initialize V4L video device */
 	dev->v4l_device = cx23885_video_dev_alloc(tsport,
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index 0e0952e60795..39f69d89a663 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -1183,7 +1183,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
 	err = cx2341x_handler_init(&dev->cxhdl, 36);
 	if (err)
 		goto fail_core;
-	v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl, NULL);
+	v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl, NULL, false);
 
 	/* blackbird stuff */
 	pr_info("cx23416 based mpeg encoder (blackbird reference design)\n");
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index 9be682cdb644..e35bfa03a1e2 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1378,7 +1378,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
 		if (vc->id == V4L2_CID_CHROMA_AGC)
 			core->chroma_agc = vc;
 	}
-	v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl, NULL);
+	v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl, NULL, false);
 
 	/* load and configure helper modules */
 
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 66acfd35ffc6..fc75ce00dbf8 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -265,9 +265,9 @@ static int empress_init(struct saa7134_dev *dev)
 		 "%s empress (%s)", dev->name,
 		 saa7134_boards[dev->board].name);
 	v4l2_ctrl_handler_init(hdl, 21);
-	v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter);
+	v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter, false);
 	if (dev->empress_sd)
-		v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL);
+		v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL, true);
 	if (hdl->error) {
 		video_device_release(dev->empress_dev);
 		return hdl->error;
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 1ca6a32ad10e..065af5df77b6 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -2136,7 +2136,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
 		hdl = &dev->radio_ctrl_handler;
 		v4l2_ctrl_handler_init(hdl, 2);
 		v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler,
-				v4l2_ctrl_radio_filter);
+				v4l2_ctrl_radio_filter, false);
 		if (hdl->error)
 			return hdl->error;
 	}
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index ed9302caa004..64f3ab3584d7 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -1421,7 +1421,7 @@ static int fimc_link_setup(struct media_entity *entity,
 		return 0;
 
 	return v4l2_ctrl_add_handler(&vc->ctx->ctrls.handler,
-				     sensor->ctrl_handler, NULL);
+				     sensor->ctrl_handler, NULL, true);
 }
 
 static const struct media_entity_operations fimc_sd_media_ops = {
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index b479b882da12..90246113fa03 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -900,7 +900,8 @@ int rvin_v4l2_probe(struct rvin_dev *vin)
 	if (ret < 0)
 		return ret;
 
-	ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, sd->ctrl_handler, NULL);
+	ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, sd->ctrl_handler,
+				    NULL, true);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index b2e080ef5391..70cef10c81a6 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -1167,7 +1167,7 @@ static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
 	}
 
 	ret = v4l2_ctrl_add_handler(&sdr->ctrl_hdl,
-				    sdr->ep.subdev->ctrl_handler, NULL);
+				    sdr->ep.subdev->ctrl_handler, NULL, true);
 	if (ret) {
 		rdrif_err(sdr, "failed: ctrl add hdlr ret %d\n", ret);
 		goto error;
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index c86dd2fdab84..33fac0cdfc5e 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -1180,7 +1180,8 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd)
 
 	v4l2_subdev_call(sd, video, g_tvnorms, &icd->vdev->tvnorms);
 
-	ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
+	ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler,
+				    NULL, true);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 4b6b5d715031..83e097de7d7d 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -1660,59 +1660,59 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
 		v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true);
 
 	if (dev->has_vid_cap) {
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL, false);
 		if (hdl_vid_cap->error)
 			return hdl_vid_cap->error;
 		dev->vid_cap_dev.ctrl_handler = hdl_vid_cap;
 	}
 	if (dev->has_vid_out) {
-		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL);
-		v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL, false);
 		if (hdl_vid_out->error)
 			return hdl_vid_out->error;
 		dev->vid_out_dev.ctrl_handler = hdl_vid_out;
 	}
 	if (dev->has_vbi_cap) {
-		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL);
-		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL);
-		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL);
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL, false);
 		if (hdl_vbi_cap->error)
 			return hdl_vbi_cap->error;
 		dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap;
 	}
 	if (dev->has_vbi_out) {
-		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL);
+		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL, false);
 		if (hdl_vbi_out->error)
 			return hdl_vbi_out->error;
 		dev->vbi_out_dev.ctrl_handler = hdl_vbi_out;
 	}
 	if (dev->has_radio_rx) {
-		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL);
+		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL, false);
 		if (hdl_radio_rx->error)
 			return hdl_radio_rx->error;
 		dev->radio_rx_dev.ctrl_handler = hdl_radio_rx;
 	}
 	if (dev->has_radio_tx) {
-		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL);
+		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL, false);
 		if (hdl_radio_tx->error)
 			return hdl_radio_tx->error;
 		dev->radio_tx_dev.ctrl_handler = hdl_radio_tx;
 	}
 	if (dev->has_sdr_cap) {
-		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL);
-		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL);
+		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL, false);
+		v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL, false);
 		if (hdl_sdr_cap->error)
 			return hdl_sdr_cap->error;
 		dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index b80e6857e2eb..fca16cf8b3bf 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1991,7 +1991,7 @@ int cx231xx_417_register(struct cx231xx *dev)
 	dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
 	if (dev->sd_cx25840)
 		v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
-				dev->sd_cx25840->ctrl_handler, NULL);
+				dev->sd_cx25840->ctrl_handler, NULL, false);
 	if (dev->mpeg_ctrl_handler.hdl.error) {
 		err = dev->mpeg_ctrl_handler.hdl.error;
 		dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 5b321b8ada3a..907cf095d54c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -2204,10 +2204,10 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
 
 	if (dev->sd_cx25840) {
 		v4l2_ctrl_add_handler(&dev->ctrl_handler,
-				dev->sd_cx25840->ctrl_handler, NULL);
+				dev->sd_cx25840->ctrl_handler, NULL, true);
 		v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
 				dev->sd_cx25840->ctrl_handler,
-				v4l2_ctrl_radio_filter);
+				v4l2_ctrl_radio_filter, true);
 	}
 
 	if (dev->ctrl_handler.error)
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index 65ef755adfdc..4aacd77a5d58 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -1278,7 +1278,7 @@ static int msi2500_probe(struct usb_interface *intf,
 	}
 
 	/* currently all controls are from subdev */
-	v4l2_ctrl_add_handler(&dev->hdl, sd->ctrl_handler, NULL);
+	v4l2_ctrl_add_handler(&dev->hdl, sd->ctrl_handler, NULL, true);
 
 	dev->v4l2_dev.ctrl_handler = &dev->hdl;
 	dev->vdev.v4l2_dev = &dev->v4l2_dev;
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 8314d3fa9241..1cfbbc47adfc 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1623,7 +1623,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
 	v4l2_ctrl_new_std(&dev->ctrl_handler, &tm6000_ctrl_ops,
 			V4L2_CID_HUE, -128, 127, 1, 0);
 	v4l2_ctrl_add_handler(&dev->ctrl_handler,
-			&dev->radio_ctrl_handler, NULL);
+			&dev->radio_ctrl_handler, NULL, false);
 
 	if (dev->radio_ctrl_handler.error)
 		ret = dev->radio_ctrl_handler.error;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index ce08b50b8290..5c705f5dde9b 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1876,7 +1876,8 @@ EXPORT_SYMBOL(v4l2_ctrl_find);
 
 /* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
 static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
-			   struct v4l2_ctrl *ctrl)
+			   struct v4l2_ctrl *ctrl,
+			   bool from_other_dev)
 {
 	struct v4l2_ctrl_ref *ref;
 	struct v4l2_ctrl_ref *new_ref;
@@ -1900,6 +1901,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 	if (!new_ref)
 		return handler_set_err(hdl, -ENOMEM);
 	new_ref->ctrl = ctrl;
+	new_ref->from_other_dev = from_other_dev;
 	if (ctrl->handler == hdl) {
 		/* By default each control starts in a cluster of its own.
 		   new_ref->ctrl is basically a cluster array with one
@@ -2080,7 +2082,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
 	}
 
-	if (handler_new_ref(hdl, ctrl)) {
+	if (handler_new_ref(hdl, ctrl, false)) {
 		kvfree(ctrl);
 		return NULL;
 	}
@@ -2249,7 +2251,8 @@ EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
 /* Add the controls from another handler to our own. */
 int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 			  struct v4l2_ctrl_handler *add,
-			  bool (*filter)(const struct v4l2_ctrl *ctrl))
+			  bool (*filter)(const struct v4l2_ctrl *ctrl),
+			  bool from_other_dev)
 {
 	struct v4l2_ctrl_ref *ref;
 	int ret = 0;
@@ -2272,7 +2275,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 		/* Filter any unwanted controls */
 		if (filter && !filter(ctrl))
 			continue;
-		ret = handler_new_ref(hdl, ctrl);
+		ret = handler_new_ref(hdl, ctrl, from_other_dev);
 		if (ret)
 			break;
 	}
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 937c6de85606..8391a7f0895b 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -178,7 +178,8 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 
 	sd->v4l2_dev = v4l2_dev;
 	/* This just returns 0 if either of the two args is NULL */
-	err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);
+	err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler,
+				    NULL, true);
 	if (err)
 		goto error_module;
 
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index 289d775c4820..08799beaea42 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -391,7 +391,7 @@ static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
 
 		ret = v4l2_ctrl_add_handler(vfd->ctrl_handler,
 					    sd->ctrl_handler,
-					    NULL);
+					    NULL, true);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/staging/media/imx/imx-media-fim.c b/drivers/staging/media/imx/imx-media-fim.c
index 6df189135db8..8cf773eef9da 100644
--- a/drivers/staging/media/imx/imx-media-fim.c
+++ b/drivers/staging/media/imx/imx-media-fim.c
@@ -463,7 +463,7 @@ int imx_media_fim_add_controls(struct imx_media_fim *fim)
 {
 	/* add the FIM controls to the calling subdev ctrl handler */
 	return v4l2_ctrl_add_handler(fim->sd->ctrl_handler,
-				     &fim->ctrl_handler, NULL);
+				     &fim->ctrl_handler, NULL, false);
 }
 EXPORT_SYMBOL_GPL(imx_media_fim_add_controls);
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 05ebb9ef9e73..96f5c63c12d0 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -257,6 +257,7 @@ struct v4l2_ctrl_ref {
 	struct v4l2_ctrl_ref *next;
 	struct v4l2_ctrl *ctrl;
 	struct v4l2_ctrl_helper *helper;
+	bool from_other_dev;
 };
 
 /**
@@ -642,7 +643,8 @@ typedef bool (*v4l2_ctrl_filter)(const struct v4l2_ctrl *ctrl);
  */
 int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 			  struct v4l2_ctrl_handler *add,
-			  v4l2_ctrl_filter filter);
+			  v4l2_ctrl_filter filter,
+			  bool from_other_dev);
 
 /**
  * v4l2_ctrl_radio_filter() - Standard filter for radio controls.
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 03/21] v4l2-ctrls: prepare internal structs for request API
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 01/21] media: add request API core and UAPI Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 02/21] v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 04/21] v4l2-ctrls: add core " Alexandre Courbot
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

Add a refcount and is_request bool to struct v4l2_ctrl_handler:
this is used to refcount a handler that represents a request.

Add a p_req field to struct v4l2_ctrl_ref that will store the
request value.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 1 +
 include/media/v4l2-ctrls.h           | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 5c705f5dde9b..eac70598635d 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1761,6 +1761,7 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
 				      sizeof(hdl->buckets[0]),
 				      GFP_KERNEL | __GFP_ZERO);
 	hdl->error = hdl->buckets ? 0 : -ENOMEM;
+	hdl->is_request = false;
 	return hdl->error;
 }
 EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 96f5c63c12d0..bcabbf8a44b5 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -18,6 +18,7 @@
 #define _V4L2_CTRLS_H
 
 #include <linux/list.h>
+#include <linux/kref.h>
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 
@@ -257,6 +258,7 @@ struct v4l2_ctrl_ref {
 	struct v4l2_ctrl_ref *next;
 	struct v4l2_ctrl *ctrl;
 	struct v4l2_ctrl_helper *helper;
+	union v4l2_ctrl_ptr p_req;
 	bool from_other_dev;
 };
 
@@ -292,7 +294,9 @@ struct v4l2_ctrl_handler {
 	v4l2_ctrl_notify_fnc notify;
 	void *notify_priv;
 	u16 nr_of_buckets;
+	bool is_request;
 	int error;
+	struct kref ref;
 };
 
 /**
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 04/21] v4l2-ctrls: add core request API
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (2 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 03/21] v4l2-ctrls: prepare internal structs for request API Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 05/21] v4l2-ctrls: use ref in helper instead of ctrl Alexandre Courbot
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

Add the four core request functions:

v4l2_ctrl_request_init() initializes a new (empty) request.
v4l2_ctrl_request_clone() resets a request based on another request
(or clears it if that request is NULL).
v4l2_ctrl_request_get(): increase refcount
v4l2_ctrl_request_put(): decrease refcount and delete if it reaches 0.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
[acourbot@chromium.org: turn v4l2_ctrl_request_alloc into init function]
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 106 ++++++++++++++++++++++++++-
 include/media/v4l2-ctrls.h           |   7 ++
 2 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index eac70598635d..784879816c24 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1878,6 +1878,7 @@ EXPORT_SYMBOL(v4l2_ctrl_find);
 /* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
 static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 			   struct v4l2_ctrl *ctrl,
+			   struct v4l2_ctrl_ref **ctrl_ref,
 			   bool from_other_dev)
 {
 	struct v4l2_ctrl_ref *ref;
@@ -1885,6 +1886,10 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 	u32 id = ctrl->id;
 	u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
 	int bucket = id % hdl->nr_of_buckets;	/* which bucket to use */
+	unsigned int sz_extra = 0;
+
+	if (ctrl_ref)
+		*ctrl_ref = NULL;
 
 	/*
 	 * Automatically add the control class if it is not yet present and
@@ -1898,11 +1903,16 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 	if (hdl->error)
 		return hdl->error;
 
-	new_ref = kzalloc(sizeof(*new_ref), GFP_KERNEL);
+	if (hdl->is_request)
+		sz_extra = ctrl->elems * ctrl->elem_size;
+	new_ref = kzalloc(sizeof(*new_ref) + sz_extra, GFP_KERNEL);
 	if (!new_ref)
 		return handler_set_err(hdl, -ENOMEM);
 	new_ref->ctrl = ctrl;
 	new_ref->from_other_dev = from_other_dev;
+	if (sz_extra)
+		new_ref->p_req.p = &new_ref[1];
+
 	if (ctrl->handler == hdl) {
 		/* By default each control starts in a cluster of its own.
 		   new_ref->ctrl is basically a cluster array with one
@@ -1942,6 +1952,8 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
 	/* Insert the control node in the hash */
 	new_ref->next = hdl->buckets[bucket];
 	hdl->buckets[bucket] = new_ref;
+	if (ctrl_ref)
+		*ctrl_ref = new_ref;
 
 unlock:
 	mutex_unlock(hdl->lock);
@@ -2083,7 +2095,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 		ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
 	}
 
-	if (handler_new_ref(hdl, ctrl, false)) {
+	if (handler_new_ref(hdl, ctrl, NULL, false)) {
 		kvfree(ctrl);
 		return NULL;
 	}
@@ -2276,7 +2288,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
 		/* Filter any unwanted controls */
 		if (filter && !filter(ctrl))
 			continue;
-		ret = handler_new_ref(hdl, ctrl, from_other_dev);
+		ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev);
 		if (ret)
 			break;
 	}
@@ -2685,6 +2697,94 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
 }
 EXPORT_SYMBOL(v4l2_querymenu);
 
+int v4l2_ctrl_request_init(struct v4l2_ctrl_handler *hdl)
+{
+	int err;
+
+	err = v4l2_ctrl_handler_init(hdl, 0);
+	if (err)
+		return err;
+	hdl->is_request = true;
+	kref_init(&hdl->ref);
+
+	return 0;
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_init);
+
+int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
+			    const struct v4l2_ctrl_handler *from,
+			    bool (*filter)(const struct v4l2_ctrl *ctrl))
+{
+	struct v4l2_ctrl_ref *ref;
+	int err;
+
+	if (WARN_ON(!hdl || hdl == from))
+		return -EINVAL;
+
+	if (hdl->error)
+		return hdl->error;
+
+	WARN_ON(hdl->lock != &hdl->_lock);
+	v4l2_ctrl_handler_free(hdl);
+	err = v4l2_ctrl_handler_init(hdl, (from->nr_of_buckets - 1) * 8);
+	hdl->is_request = true;
+	if (err)
+		return err;
+	if (!from)
+		return 0;
+
+	mutex_lock(from->lock);
+	list_for_each_entry(ref, &from->ctrl_refs, node) {
+		struct v4l2_ctrl *ctrl = ref->ctrl;
+		struct v4l2_ctrl_ref *new_ref;
+
+		/* Skip refs inherited from other devices */
+		if (ref->from_other_dev)
+			continue;
+		/* And buttons and control classes */
+		if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+		    ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+			continue;
+		/* Filter any unwanted controls */
+		if (filter && !filter(ctrl))
+			continue;
+		err = handler_new_ref(hdl, ctrl, &new_ref, false);
+		if (err)
+			break;
+		if (from->is_request)
+			ptr_to_ptr(ctrl, ref->p_req, new_ref->p_req);
+		else
+			ptr_to_ptr(ctrl, ctrl->p_cur, new_ref->p_req);
+	}
+	mutex_unlock(from->lock);
+	return err;
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_clone);
+
+void v4l2_ctrl_request_get(struct v4l2_ctrl_handler *hdl)
+{
+	if (WARN_ON(!hdl->is_request))
+		return;
+	kref_get(&hdl->ref);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_get);
+
+static void v4l2_ctrl_request_release(struct kref *kref)
+{
+	struct v4l2_ctrl_handler *hdl =
+		container_of(kref, struct v4l2_ctrl_handler, ref);
+
+	v4l2_ctrl_handler_free(hdl);
+	kfree(hdl);
+}
+
+void v4l2_ctrl_request_put(struct v4l2_ctrl_handler *hdl)
+{
+	if (WARN_ON(!hdl->is_request))
+		return;
+	kref_put(&hdl->ref, v4l2_ctrl_request_release);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_put);
 
 /* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index bcabbf8a44b5..c51e1cacc09d 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -1052,6 +1052,13 @@ int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
  */
 __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait);
 
+int v4l2_ctrl_request_init(struct v4l2_ctrl_handler *hdl);
+int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
+			    const struct v4l2_ctrl_handler *from,
+			    bool (*filter)(const struct v4l2_ctrl *ctrl));
+void v4l2_ctrl_request_get(struct v4l2_ctrl_handler *hdl);
+void v4l2_ctrl_request_put(struct v4l2_ctrl_handler *hdl);
+
 /* Helpers for ioctl_ops */
 
 /**
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 05/21] v4l2-ctrls: use ref in helper instead of ctrl
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (3 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 04/21] v4l2-ctrls: add core " Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 06/21] v4l2-ctrls: support g/s_ext_ctrls for requests Alexandre Courbot
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

The next patch needs the reference to a control instead of the
control itself, so change struct v4l2_ctrl_helper accordingly.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 784879816c24..b3be022b219f 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -37,8 +37,8 @@
 struct v4l2_ctrl_helper {
 	/* Pointer to the control reference of the master control */
 	struct v4l2_ctrl_ref *mref;
-	/* The control corresponding to the v4l2_ext_control ID field. */
-	struct v4l2_ctrl *ctrl;
+	/* The control ref corresponding to the v4l2_ext_control ID field. */
+	struct v4l2_ctrl_ref *ref;
 	/* v4l2_ext_control index of the next control belonging to the
 	   same cluster, or 0 if there isn't any. */
 	u32 next;
@@ -2856,6 +2856,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 		ref = find_ref_lock(hdl, id);
 		if (ref == NULL)
 			return -EINVAL;
+		h->ref = ref;
 		ctrl = ref->ctrl;
 		if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
 			return -EINVAL;
@@ -2878,7 +2879,6 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
 		}
 		/* Store the ref to the master control of the cluster */
 		h->mref = ref;
-		h->ctrl = ctrl;
 		/* Initially set next to 0, meaning that there is no other
 		   control in this helper array belonging to the same
 		   cluster */
@@ -2963,7 +2963,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 	cs->error_idx = cs->count;
 
 	for (i = 0; !ret && i < cs->count; i++)
-		if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+		if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
 			ret = -EACCES;
 
 	for (i = 0; !ret && i < cs->count; i++) {
@@ -2998,7 +2998,7 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 
 			do {
 				ret = ctrl_to_user(cs->controls + idx,
-						   helpers[idx].ctrl);
+						   helpers[idx].ref->ctrl);
 				idx = helpers[idx].next;
 			} while (!ret && idx);
 		}
@@ -3137,7 +3137,7 @@ static int validate_ctrls(struct v4l2_ext_controls *cs,
 
 	cs->error_idx = cs->count;
 	for (i = 0; i < cs->count; i++) {
-		struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+		struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
 		union v4l2_ctrl_ptr p_new;
 
 		cs->error_idx = i;
@@ -3249,7 +3249,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 			do {
 				/* Check if the auto control is part of the
 				   list, and remember the new value. */
-				if (helpers[tmp_idx].ctrl == master)
+				if (helpers[tmp_idx].ref->ctrl == master)
 					new_auto_val = cs->controls[tmp_idx].value;
 				tmp_idx = helpers[tmp_idx].next;
 			} while (tmp_idx);
@@ -3262,7 +3262,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 		/* Copy the new caller-supplied control values.
 		   user_to_new() sets 'is_new' to 1. */
 		do {
-			struct v4l2_ctrl *ctrl = helpers[idx].ctrl;
+			struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
 
 			ret = user_to_new(cs->controls + idx, ctrl);
 			if (!ret && ctrl->is_ptr)
@@ -3278,7 +3278,7 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 			idx = i;
 			do {
 				ret = new_to_user(cs->controls + idx,
-						helpers[idx].ctrl);
+						helpers[idx].ref->ctrl);
 				idx = helpers[idx].next;
 			} while (!ret && idx);
 		}
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 06/21] v4l2-ctrls: support g/s_ext_ctrls for requests
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (4 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 05/21] v4l2-ctrls: use ref in helper instead of ctrl Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 07/21] v4l2-ctrls: add v4l2_ctrl_request_setup Alexandre Courbot
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

The v4l2_g/s_ext_ctrls functions now support control handlers that
represent requests.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 37 +++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b3be022b219f..00c4488ca1da 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1528,6 +1528,13 @@ static int new_to_user(struct v4l2_ext_control *c,
 	return ptr_to_user(c, ctrl, ctrl->p_new);
 }
 
+/* Helper function: copy the request value back to the caller */
+static int req_to_user(struct v4l2_ext_control *c,
+		       struct v4l2_ctrl_ref *ref)
+{
+	return ptr_to_user(c, ref->ctrl, ref->p_req);
+}
+
 /* Helper function: copy the initial control value back to the caller */
 static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
 {
@@ -1647,6 +1654,14 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
 	ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
 }
 
+/* Copy the new value to the request value */
+static void new_to_req(struct v4l2_ctrl_ref *ref)
+{
+	if (!ref)
+		return;
+	ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
+}
+
 /* Return non-zero if one or more of the controls in the cluster has a new
    value that differs from the current value. */
 static int cluster_changed(struct v4l2_ctrl *master)
@@ -2971,7 +2986,8 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 				    struct v4l2_ctrl *ctrl);
 		struct v4l2_ctrl *master;
 
-		ctrl_to_user = def_value ? def_to_user : cur_to_user;
+		ctrl_to_user = def_value ? def_to_user :
+			       (hdl->is_request ? NULL : cur_to_user);
 
 		if (helpers[i].mref == NULL)
 			continue;
@@ -2997,8 +3013,12 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 			u32 idx = i;
 
 			do {
-				ret = ctrl_to_user(cs->controls + idx,
-						   helpers[idx].ref->ctrl);
+				if (ctrl_to_user)
+					ret = ctrl_to_user(cs->controls + idx,
+						helpers[idx].ref->ctrl);
+				else
+					ret = req_to_user(cs->controls + idx,
+						helpers[idx].ref);
 				idx = helpers[idx].next;
 			} while (!ret && idx);
 		}
@@ -3271,7 +3291,16 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 		} while (!ret && idx);
 
 		if (!ret)
-			ret = try_or_set_cluster(fh, master, set, 0);
+			ret = try_or_set_cluster(fh, master,
+						 !hdl->is_request && set, 0);
+		if (!ret && hdl->is_request && set) {
+			for (j = 0; j < master->ncontrols; j++) {
+				struct v4l2_ctrl_ref *ref =
+					find_ref(hdl, master->cluster[j]->id);
+
+				new_to_req(ref);
+			}
+		}
 
 		/* Copy the new values back to userspace. */
 		if (!ret) {
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 07/21] v4l2-ctrls: add v4l2_ctrl_request_setup
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (5 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 06/21] v4l2-ctrls: support g/s_ext_ctrls for requests Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 08/21] [WAR] v4l2-ctrls: do not clone non-standard controls Alexandre Courbot
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

Add a helper function that can set controls from a request.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 71 ++++++++++++++++++++++++++++
 include/media/v4l2-ctrls.h           |  2 +
 2 files changed, 73 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 00c4488ca1da..166647817efb 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1662,6 +1662,14 @@ static void new_to_req(struct v4l2_ctrl_ref *ref)
 	ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
 }
 
+/* Copy the request value to the new value */
+static void req_to_new(struct v4l2_ctrl_ref *ref)
+{
+	if (!ref)
+		return;
+	ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
+}
+
 /* Return non-zero if one or more of the controls in the cluster has a new
    value that differs from the current value. */
 static int cluster_changed(struct v4l2_ctrl *master)
@@ -3427,6 +3435,69 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
 }
 EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
 
+void v4l2_ctrl_request_setup(struct v4l2_ctrl_handler *hdl)
+{
+	struct v4l2_ctrl_ref *ref;
+
+	if (!hdl)
+		return;
+
+	mutex_lock(hdl->lock);
+
+	list_for_each_entry(ref, &hdl->ctrl_refs, node)
+		ref->done = false;
+
+	list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+		struct v4l2_ctrl *ctrl = ref->ctrl;
+		struct v4l2_ctrl *master = ctrl->cluster[0];
+		int i;
+
+		/* Skip if this control was already handled by a cluster. */
+		/* Skip button controls and read-only controls. */
+		if (ref->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+		    (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+			continue;
+
+		v4l2_ctrl_lock(master);
+		for (i = 0; i < master->ncontrols; i++) {
+			if (master->cluster[i]) {
+				struct v4l2_ctrl_ref *r =
+					find_ref(hdl, master->cluster[i]->id);
+
+				req_to_new(r);
+				master->cluster[i]->is_new = 1;
+				r->done = true;
+			}
+		}
+		/*
+		 * For volatile autoclusters that are currently in auto mode
+		 * we need to discover if it will be set to manual mode.
+		 * If so, then we have to copy the current volatile values
+		 * first since those will become the new manual values (which
+		 * may be overwritten by explicit new values from this set
+		 * of controls).
+		 */
+		if (master->is_auto && master->has_volatiles &&
+		    !is_cur_manual(master)) {
+			s32 new_auto_val = *master->p_new.p_s32;
+
+			/*
+			 * If the new value == the manual value, then copy
+			 * the current volatile values.
+			 */
+			if (new_auto_val == master->manual_mode_value)
+				update_from_auto_cluster(master);
+		}
+
+		try_or_set_cluster(NULL, master, true, 0);
+
+		v4l2_ctrl_unlock(master);
+	}
+
+	mutex_unlock(hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_request_setup);
+
 void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
 {
 	if (ctrl == NULL)
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index c51e1cacc09d..3a10fb3419e3 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -259,6 +259,7 @@ struct v4l2_ctrl_ref {
 	struct v4l2_ctrl *ctrl;
 	struct v4l2_ctrl_helper *helper;
 	union v4l2_ctrl_ptr p_req;
+	bool done;
 	bool from_other_dev;
 };
 
@@ -1056,6 +1057,7 @@ int v4l2_ctrl_request_init(struct v4l2_ctrl_handler *hdl);
 int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
 			    const struct v4l2_ctrl_handler *from,
 			    bool (*filter)(const struct v4l2_ctrl *ctrl));
+void v4l2_ctrl_request_setup(struct v4l2_ctrl_handler *hdl);
 void v4l2_ctrl_request_get(struct v4l2_ctrl_handler *hdl);
 void v4l2_ctrl_request_put(struct v4l2_ctrl_handler *hdl);
 
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 08/21] [WAR] v4l2-ctrls: do not clone non-standard controls
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (6 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 07/21] v4l2-ctrls: add v4l2_ctrl_request_setup Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20 13:05   ` Hans Verkuil
  2018-02-20  4:44 ` [RFCv4 09/21] v4l2: add request API support Alexandre Courbot
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Only standard controls can be successfully cloned: handler_new_ref, used
by v4l2_ctrl_request_clone(), forcibly calls v4l2_ctrl_new_std() which
fails to find custom controls names, and we eventually hit the condition
that name == NULL in v4l2_ctrl_new().

This prevents us from using non-standard controls with requests, but
that is enough for testing purposes.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 166647817efb..7a81aa5959c3 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2772,6 +2772,11 @@ int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
 		if (filter && !filter(ctrl))
 			continue;
 		err = handler_new_ref(hdl, ctrl, &new_ref, false);
+		if (err) {
+			printk("%s: handler_new_ref on control %x (%s) returned %d\n", __func__, ctrl->id, ctrl->name, err);
+			err = 0;
+			continue;
+		}
 		if (err)
 			break;
 		if (from->is_request)
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 09/21] v4l2: add request API support
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (7 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 08/21] [WAR] v4l2-ctrls: do not clone non-standard controls Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  7:36   ` Philippe Ombredanne
  2018-02-20 13:25   ` Hans Verkuil
  2018-02-20  4:44 ` [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer Alexandre Courbot
                   ` (12 subsequent siblings)
  21 siblings, 2 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Add a v4l2 request entity data structure that takes care of storing the
request-related state of a V4L2 device ; in this case, its controls.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/Makefile       |   1 +
 drivers/media/v4l2-core/v4l2-request.c | 178 +++++++++++++++++++++++++
 include/media/v4l2-request.h           | 159 ++++++++++++++++++++++
 3 files changed, 338 insertions(+)
 create mode 100644 drivers/media/v4l2-core/v4l2-request.c
 create mode 100644 include/media/v4l2-request.h

diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index 80de2cb9c476..13d0477535bd 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -16,6 +16,7 @@ ifeq ($(CONFIG_TRACEPOINTS),y)
   videodev-objs += vb2-trace.o v4l2-trace.o
 endif
 videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
+videodev-$(CONFIG_MEDIA_REQUEST_API) += v4l2-request.o
 
 obj-$(CONFIG_VIDEO_V4L2) += videodev.o
 obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
diff --git a/drivers/media/v4l2-core/v4l2-request.c b/drivers/media/v4l2-core/v4l2-request.c
new file mode 100644
index 000000000000..e8ad10e2f525
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-request.c
@@ -0,0 +1,178 @@
+/*
+ * Media requests support for V4L2
+ *
+ * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-request.h>
+#include <media/videobuf2-v4l2.h>
+
+void v4l2_request_entity_init(struct v4l2_request_entity *entity,
+			      const struct media_request_entity_ops *ops,
+			      struct video_device *vdev)
+{
+	media_request_entity_init(&entity->base, MEDIA_REQUEST_ENTITY_TYPE_V4L2, ops);
+	entity->vdev = vdev;
+}
+EXPORT_SYMBOL_GPL(v4l2_request_entity_init);
+
+struct media_request_entity_data *
+v4l2_request_entity_data_alloc(struct media_request *req,
+			       struct v4l2_ctrl_handler *hdl)
+{
+	struct v4l2_request_entity_data *data;
+	int ret;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	ret = v4l2_ctrl_request_init(&data->ctrls);
+	if (ret) {
+		kfree(data);
+		return ERR_PTR(ret);
+	}
+	ret = v4l2_ctrl_request_clone(&data->ctrls, hdl, NULL);
+	if (ret) {
+		kfree(data);
+		return ERR_PTR(ret);
+	}
+
+	INIT_LIST_HEAD(&data->queued_buffers);
+
+	return &data->base;
+}
+EXPORT_SYMBOL_GPL(v4l2_request_entity_data_alloc);
+
+void v4l2_request_entity_data_free(struct media_request_entity_data *_data)
+{
+	struct v4l2_request_entity_data *data;
+	struct v4l2_vb2_request_buffer *qb, *n;
+
+	data = to_v4l2_entity_data(_data);
+
+	list_for_each_entry_safe(qb, n, &data->queued_buffers, node) {
+		struct vb2_buffer *buf;
+		dev_warn(_data->request->mgr->dev,
+			 "entity data freed while buffer still queued!\n");
+
+		/* give buffer back to user-space */
+		buf = qb->queue->bufs[qb->v4l2_buf.index];
+		buf->state = qb->pre_req_state;
+		buf->request = NULL;
+
+		kfree(qb);
+	}
+
+	v4l2_ctrl_handler_free(&data->ctrls);
+	kfree(data);
+}
+EXPORT_SYMBOL_GPL(v4l2_request_entity_data_free);
+
+
+
+
+
+static struct media_request *v4l2_request_alloc(struct media_request_mgr *mgr)
+{
+	struct media_request *req;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+
+	req->mgr = mgr;
+	req->state = MEDIA_REQUEST_STATE_IDLE;
+	INIT_LIST_HEAD(&req->data);
+	init_waitqueue_head(&req->complete_wait);
+	mutex_init(&req->lock);
+
+	mutex_lock(&mgr->mutex);
+	list_add_tail(&req->list, &mgr->requests);
+	mutex_unlock(&mgr->mutex);
+
+	return req;
+}
+
+static void v4l2_request_free(struct media_request *req)
+{
+	struct media_request_mgr *mgr = req->mgr;
+	struct media_request_entity_data *data, *next;
+
+	mutex_lock(&mgr->mutex);
+	list_del(&req->list);
+	mutex_unlock(&mgr->mutex);
+
+	list_for_each_entry_safe(data, next, &req->data, list) {
+		list_del(&data->list);
+		data->entity->ops->data_free(data);
+	}
+
+	kfree(req);
+}
+
+static bool v4l2_entity_valid(const struct media_request *req,
+			      const struct media_request_entity *_entity)
+{
+	const struct v4l2_request_mgr *mgr;
+	const struct v4l2_request_entity *entity;
+
+	if (_entity->type != MEDIA_REQUEST_ENTITY_TYPE_V4L2)
+		return false;
+
+	entity = container_of(_entity, struct v4l2_request_entity, base);
+	mgr = container_of(req->mgr, struct v4l2_request_mgr, base);
+
+	/* Entity is valid if it is the video device that created the manager */
+	return entity->vdev == mgr->vdev;
+}
+
+static int v4l2_request_submit(struct media_request *req)
+{
+	struct media_request_entity_data *data;
+
+        /* Submit for each entity */
+	list_for_each_entry(data, &req->data, list) {
+		int ret = data->entity->ops->submit(req, data);
+		/* TODO proper error handling, abort on other entities? */
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+const struct media_request_ops v4l2_request_ops = {
+	.alloc = v4l2_request_alloc,
+	.release = v4l2_request_free,
+	.entity_valid = v4l2_entity_valid,
+	.submit = v4l2_request_submit,
+};
+EXPORT_SYMBOL_GPL(v4l2_request_ops);
+
+void v4l2_request_mgr_init(struct v4l2_request_mgr *mgr,
+			  struct video_device *vdev,
+			  const struct media_request_ops *ops)
+{
+	media_request_mgr_init(&mgr->base, &vdev->dev, ops);
+	mgr->vdev = vdev;
+}
+EXPORT_SYMBOL_GPL(v4l2_request_mgr_init);
+
+void v4l2_request_mgr_free(struct v4l2_request_mgr* mgr)
+{
+	media_request_mgr_free(&mgr->base);
+}
+EXPORT_SYMBOL_GPL(v4l2_request_mgr_free);
diff --git a/include/media/v4l2-request.h b/include/media/v4l2-request.h
new file mode 100644
index 000000000000..8a87ca455b74
--- /dev/null
+++ b/include/media/v4l2-request.h
@@ -0,0 +1,159 @@
+/*
+ * Media requests support for V4L2
+ *
+ * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIA_V4L2_REQUEST_H
+#define _MEDIA_V4L2_REQUEST_H
+
+#include <linux/kconfig.h>
+#include <media/media-request.h>
+
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+
+#include <linux/list.h>
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+
+/**
+ * struct v4l2_request_entity - entity used with V4L2 instances
+ *
+ * @base:	base media_request_entity struct
+ * @vdev:	video device that this entity represents
+ *
+ * This structure is used by V4L2 devices that support being controlled
+ * by requests. If should be added to the device-specific structure that the
+ * driver wishes to control using requests.
+ *
+ * V4L2 request entities are able to receive queued buffers using vb2 queues,
+ * and control settings using the control framework.
+ *
+ */
+struct v4l2_request_entity {
+	struct media_request_entity base;
+	struct video_device *vdev;
+};
+#define to_v4l2_entity(e) container_of(e, struct v4l2_request_entity, base)
+
+/**
+ * v4l2_request_entity_init() - initialize a struct v4l2_request_entity
+ *
+ * @entity:	entity to initialize
+ * @ops:	entity ops to use
+ * @vdev:	video device represented by this entity
+ */
+void v4l2_request_entity_init(struct v4l2_request_entity *entity,
+			      const struct media_request_entity_ops *ops,
+			      struct video_device *vdev);
+
+/**
+ * struct v4l2_vb2_request_buffer - record buffer queue on behalf of a request
+ *
+ * @queue:		vb2 queue
+ * @pre_req_state:	keep track of the pre-QBUF state of the buffer
+ * @v4l2_buf:		user-space buffer queue ioctl data
+ * @node:		entry into v4l2_request_entity_data::queued_buffers
+ */
+struct v4l2_vb2_request_buffer {
+	struct vb2_queue *queue;
+	enum vb2_buffer_state pre_req_state;
+	struct v4l2_buffer v4l2_buf;
+	struct list_head node;
+};
+
+/**
+ * struct v4l2_request_entity_data - per-request data for V4L2 entities
+ *
+ * @base:		base entity data structure
+ * @ctrls:		record of controls set for this request
+ * @queued_buffers:	record of buffers queued for this request
+ */
+struct v4l2_request_entity_data {
+	struct media_request_entity_data base;
+	struct v4l2_ctrl_handler ctrls;
+	struct list_head queued_buffers;
+};
+static inline struct v4l2_request_entity_data *
+to_v4l2_entity_data(struct media_request_entity_data *data)
+{
+	if (IS_ERR(data))
+		return (struct v4l2_request_entity_data *)data;
+
+	return container_of(data, struct v4l2_request_entity_data, base);
+}
+
+/**
+ * v4l2_request_entity_data_alloc() - allocate data for a V4L2 entity
+ *
+ * @req:	request to allocate for
+ * @hdl:	control handler of the device we will be controlling
+ *
+ * Helper function to be used from the media_request_entity_ops::data_alloc
+ * hook.
+ */
+struct media_request_entity_data *
+v4l2_request_entity_data_alloc(struct media_request *req,
+			       struct v4l2_ctrl_handler *hdl);
+
+/**
+ * v4l2_request_entity_data_free() - free per-request data of an entity
+ *
+ * @data:	entity data to free
+ *
+ * Helper function to be usedfrom the media_request_entity_ops::data_free
+ * hook.
+ */
+void
+v4l2_request_entity_data_free(struct media_request_entity_data *_data);
+
+
+
+
+
+/**
+ * struct v4l2_request_mgr - request manager producing requests suitable
+ *			     for managing single v4l2 devices.
+ *
+ * @base:	base manager structure
+ * @vdev:	device that our requests can control
+ */
+struct v4l2_request_mgr {
+	struct media_request_mgr base;
+	struct video_device *vdev;
+};
+
+/**
+ * v4l2_request_mgr_init() - initialize a v4l2_request_mgr
+ *
+ * @mgr:	manager to initialize
+ * @vdev:	video device that our instances will control
+ * @ops:	used to override ops if needed. &v4l2_request_ops is a good
+ *		default
+ */
+void v4l2_request_mgr_init(struct v4l2_request_mgr *mgr,
+			  struct video_device *vdev,
+			  const struct media_request_ops *ops);
+
+/**
+ * v4l2_request_mgr_free() - free a v4l2 request manager
+ *
+ * @mgr:	manager to free
+ */
+void v4l2_request_mgr_free(struct v4l2_request_mgr *mgr);
+
+extern const struct media_request_ops v4l2_request_ops;
+
+#endif /* CONFIG_MEDIA_REQUEST_API */
+
+#endif
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (8 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 09/21] v4l2: add request API support Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20 15:20   ` Hans Verkuil
  2018-02-20  4:44 ` [RFCv4 11/21] media: v4l2_fh: add request entity field Alexandre Courbot
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil,
	Alexandre Courbot

From: Hans Verkuil <hans.verkuil@cisco.com>

When queuing buffers allow for passing the request that should
be associated with this buffer.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
[acourbot@chromium.org: make request ID 32-bit]
Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 +-
 drivers/media/usb/cpia2/cpia2_v4l.c             | 2 +-
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c   | 9 ++++++---
 drivers/media/v4l2-core/v4l2-ioctl.c            | 4 ++--
 include/uapi/linux/videodev2.h                  | 3 ++-
 5 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 886a2d8d5c6c..6d4d184aa68e 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -203,7 +203,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
 	b->timestamp = ns_to_timeval(vb->timestamp);
 	b->timecode = vbuf->timecode;
 	b->sequence = vbuf->sequence;
-	b->reserved2 = 0;
+	b->request_fd = 0;
 	b->reserved = 0;
 
 	if (q->is_multiplanar) {
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index 99f106b13280..af42ce3ceb48 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -948,7 +948,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 	buf->sequence = cam->buffers[buf->index].seq;
 	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
 	buf->length = cam->frame_size;
-	buf->reserved2 = 0;
+	buf->request_fd = 0;
 	buf->reserved = 0;
 	memset(&buf->timecode, 0, sizeof(buf->timecode));
 
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 5198c9eeb348..32bf47489a2e 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -386,7 +386,7 @@ struct v4l2_buffer32 {
 		__s32		fd;
 	} m;
 	__u32			length;
-	__u32			reserved2;
+	__s32			request_fd;
 	__u32			reserved;
 };
 
@@ -486,6 +486,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
 {
 	u32 type;
 	u32 length;
+	s32 request_fd;
 	enum v4l2_memory memory;
 	struct v4l2_plane32 __user *uplane32;
 	struct v4l2_plane __user *uplane;
@@ -500,7 +501,9 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
 	    get_user(memory, &up->memory) ||
 	    put_user(memory, &kp->memory) ||
 	    get_user(length, &up->length) ||
-	    put_user(length, &kp->length))
+	    put_user(length, &kp->length) ||
+	    get_user(request_fd, &up->request_fd) ||
+	    put_user(request_fd, &kp->request_fd))
 		return -EFAULT;
 
 	if (V4L2_TYPE_IS_OUTPUT(type))
@@ -604,7 +607,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
 	    assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
 	    copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
 	    assign_in_user(&up->sequence, &kp->sequence) ||
-	    assign_in_user(&up->reserved2, &kp->reserved2) ||
+	    assign_in_user(&up->request_fd, &kp->request_fd) ||
 	    assign_in_user(&up->reserved, &kp->reserved) ||
 	    get_user(length, &kp->length) ||
 	    put_user(length, &up->length))
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 260288ca4f55..7bfeaf233d5a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -437,13 +437,13 @@ static void v4l_print_buffer(const void *arg, bool write_only)
 	const struct v4l2_plane *plane;
 	int i;
 
-	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s",
+	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request_fd=%u, flags=0x%08x, field=%s, sequence=%d, memory=%s",
 			p->timestamp.tv_sec / 3600,
 			(int)(p->timestamp.tv_sec / 60) % 60,
 			(int)(p->timestamp.tv_sec % 60),
 			(long)p->timestamp.tv_usec,
 			p->index,
-			prt_names(p->type, v4l2_type_names),
+			prt_names(p->type, v4l2_type_names), p->request_fd,
 			p->flags, prt_names(p->field, v4l2_field_names),
 			p->sequence, prt_names(p->memory, v4l2_memory_names));
 
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 982718965180..4fd46ae8fad5 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -909,6 +909,7 @@ struct v4l2_plane {
  * @length:	size in bytes of the buffer (NOT its payload) for single-plane
  *		buffers (when type != *_MPLANE); number of elements in the
  *		planes array for multi-plane buffers
+ * @request_fd: fd of the request that this buffer should use
  *
  * Contains data exchanged by application and driver using one of the Streaming
  * I/O methods.
@@ -932,7 +933,7 @@ struct v4l2_buffer {
 		__s32		fd;
 	} m;
 	__u32			length;
-	__u32			reserved2;
+	__s32			request_fd;
 	__u32			reserved;
 };
 
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 11/21] media: v4l2_fh: add request entity field
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (9 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20 15:24   ` Hans Verkuil
  2018-02-20  4:44 ` [RFCv4 12/21] media: videobuf2: add support for requests Alexandre Courbot
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Allow drivers to assign a request entity to v4l2_fh. This will be useful
for request-aware ioctls to find out which request entity to use.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 include/media/v4l2-fh.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
index ea73fef8bdc0..f54cb319dd64 100644
--- a/include/media/v4l2-fh.h
+++ b/include/media/v4l2-fh.h
@@ -28,6 +28,7 @@
 
 struct video_device;
 struct v4l2_ctrl_handler;
+struct media_request_entity;
 
 /**
  * struct v4l2_fh - Describes a V4L2 file handler
@@ -43,6 +44,7 @@ struct v4l2_ctrl_handler;
  * @navailable: number of available events at @available list
  * @sequence: event sequence number
  * @m2m_ctx: pointer to &struct v4l2_m2m_ctx
+ * @entity: the request entity this fh operates on behalf of
  */
 struct v4l2_fh {
 	struct list_head	list;
@@ -60,6 +62,7 @@ struct v4l2_fh {
 #if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
 	struct v4l2_m2m_ctx	*m2m_ctx;
 #endif
+	struct media_request_entity *entity;
 };
 
 /**
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 12/21] media: videobuf2: add support for requests
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (10 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 11/21] media: v4l2_fh: add request entity field Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 13/21] media: videobuf2-v4l2: " Alexandre Courbot
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Make vb2 core aware of requests. Drivers can specify whether a given
queue accepts requests or not.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/common/videobuf2/videobuf2-core.c | 3 +++
 include/media/videobuf2-core.h                  | 4 ++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index debe35fc66b4..355fe7dc99d7 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -930,6 +930,9 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
 		vb->state = state;
 	}
 	atomic_dec(&q->owned_by_drv_count);
+
+	vb->request = NULL;
+
 	spin_unlock_irqrestore(&q->done_lock, flags);
 
 	trace_vb2_buf_done(q, vb);
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 5b6c541e4e1b..6e9e814886e7 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -238,6 +238,7 @@ struct vb2_queue;
  * @num_planes:		number of planes in the buffer
  *			on an internal driver queue.
  * @timestamp:		frame timestamp in ns.
+ * @request:		request the buffer belongs to, if any.
  */
 struct vb2_buffer {
 	struct vb2_queue	*vb2_queue;
@@ -246,6 +247,7 @@ struct vb2_buffer {
 	unsigned int		memory;
 	unsigned int		num_planes;
 	u64			timestamp;
+	struct media_request	*request;
 
 	/* private: internal use only
 	 *
@@ -446,6 +448,7 @@ struct vb2_buf_ops {
  * @quirk_poll_must_check_waiting_for_buffers: Return %EPOLLERR at poll when QBUF
  *              has not been called. This is a vb1 idiom that has been adopted
  *              also by vb2.
+ * @allow_requests:	whether requests are supported on this queue.
  * @lock:	pointer to a mutex that protects the &struct vb2_queue. The
  *		driver can set this to a mutex to let the v4l2 core serialize
  *		the queuing ioctls. If the driver wants to handle locking
@@ -513,6 +516,7 @@ struct vb2_queue {
 	unsigned			fileio_write_immediately:1;
 	unsigned			allow_zero_bytesused:1;
 	unsigned		   quirk_poll_must_check_waiting_for_buffers:1;
+	unsigned			allow_requests:1;
 
 	struct mutex			*lock;
 	void				*owner;
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (11 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 12/21] media: videobuf2: add support for requests Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20 16:18   ` Hans Verkuil
  2018-03-07 16:50   ` [RFCv4,13/21] " Paul Kocialkowski
  2018-02-20  4:44 ` [RFCv4 14/21] videodev2.h: add request_fd field to v4l2_ext_controls Alexandre Courbot
                   ` (8 subsequent siblings)
  21 siblings, 2 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
that request-aware drivers can call to queue a buffer into a request
instead of directly into the vb2 queue if relevent.

This function expects that drivers invoking it are using instances of
v4l2_request_entity and v4l2_request_entity_data to describe their
entity and entity data respectively.

Also add the vb2_request_submit() helper function which drivers can
invoke in order to queue all the buffers previously queued into a
request into the regular vb2 queue.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
 include/media/videobuf2-v4l2.h                |  59 ++++++++
 2 files changed, 187 insertions(+), 1 deletion(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 6d4d184aa68e..0627c3339572 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -28,8 +28,11 @@
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-request.h>
 
 #include <media/videobuf2-v4l2.h>
+#include <media/media-request.h>
 
 static int debug;
 module_param(debug, int, 0644);
@@ -569,11 +572,131 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 		return -EBUSY;
 	}
 
+	/* drivers supporting requests must call vb2_qbuf_request instead */
+	if (b->request_fd > 0) {
+		dprintk(1, "invalid call to vb2_qbuf with request_fd set\n");
+		return -EINVAL;
+	}
+
 	ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
 	return ret ? ret : vb2_core_qbuf(q, b->index, b);
 }
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
+		     struct media_request_entity *entity)
+{
+	struct v4l2_request_entity_data *data;
+	struct v4l2_vb2_request_buffer *qb;
+	struct media_request *req;
+	struct vb2_buffer *vb;
+	int ret = 0;
+
+	if (b->request_fd <= 0)
+		return vb2_qbuf(q, b);
+
+	if (!q->allow_requests)
+		return -EINVAL;
+
+	req = media_request_get_from_fd(b->request_fd);
+	if (!req)
+		return -EINVAL;
+
+	data = to_v4l2_entity_data(media_request_get_entity_data(req, entity));
+	if (IS_ERR(data)) {
+		ret = PTR_ERR(data);
+		goto out;
+	}
+
+	mutex_lock(&req->lock);
+
+	if (req->state != MEDIA_REQUEST_STATE_IDLE) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
+	if (ret)
+		goto out;
+
+	vb = q->bufs[b->index];
+	switch (vb->state) {
+	case VB2_BUF_STATE_DEQUEUED:
+		break;
+	case VB2_BUF_STATE_PREPARED:
+		break;
+	case VB2_BUF_STATE_PREPARING:
+		dprintk(1, "buffer still being prepared\n");
+		ret = -EINVAL;
+		goto out;
+	default:
+		dprintk(1, "invalid buffer state %d\n", vb->state);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* do we already have a buffer for this request in the queue? */
+	list_for_each_entry(qb, &data->queued_buffers, node) {
+		if (qb->queue == q) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	qb = kzalloc(sizeof(*qb), GFP_KERNEL);
+	if (!qb) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * TODO should be prepare the buffer here if needed, to report errors
+	 * early?
+	 */
+	qb->pre_req_state = vb->state;
+	qb->queue = q;
+	memcpy(&qb->v4l2_buf, b, sizeof(*b));
+	vb->request = req;
+	vb->state = VB2_BUF_STATE_QUEUED;
+	list_add_tail(&qb->node, &data->queued_buffers);
+
+out:
+	mutex_unlock(&req->lock);
+	media_request_put(req);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_qbuf_request);
+
+int vb2_request_submit(struct v4l2_request_entity_data *data)
+{
+	struct v4l2_vb2_request_buffer *qb, *n;
+
+	/* v4l2 requests require at least one buffer to reach the device */
+	if (list_empty(&data->queued_buffers)) {
+		return -EINVAL;
+	}
+
+	list_for_each_entry_safe(qb, n, &data->queued_buffers, node) {
+		struct vb2_queue *q = qb->queue;
+		struct vb2_buffer *vb = q->bufs[qb->v4l2_buf.index];
+		int ret;
+
+		list_del(&qb->node);
+		vb->state = qb->pre_req_state;
+		ret = vb2_core_qbuf(q, vb->index, &qb->v4l2_buf);
+		kfree(qb);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_request_submit);
+
+#endif /* CONFIG_MEDIA_REQUEST_API */
+
 int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 {
 	int ret;
@@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
 int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
 	struct video_device *vdev = video_devdata(file);
+	struct v4l2_fh *fh = NULL;
+
+	if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+		fh = file->private_data;
 
 	if (vb2_queue_is_busy(vdev, file))
 		return -EBUSY;
-	return vb2_qbuf(vdev->queue, p);
+	return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
 }
 EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
 
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 3d5e2d739f05..d4dfa266a0da 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -23,6 +23,12 @@
 #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
 #endif
 
+struct media_entity;
+struct v4l2_fh;
+struct media_request;
+struct media_request_entity;
+struct v4l2_request_entity_data;
+
 /**
  * struct vb2_v4l2_buffer - video buffer information for v4l2.
  *
@@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
  */
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
 
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+
+/**
+ * vb2_qbuf_request() - Queue a buffer, with request support
+ * @q:		pointer to &struct vb2_queue with videobuf2 queue.
+ * @b:		buffer structure passed from userspace to
+ *		&v4l2_ioctl_ops->vidioc_qbuf handler in driver
+ * @entity:	request entity to queue for if requests are used.
+ *
+ * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
+ *
+ * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
+ *
+ * If the request_fd member of b is set, then the buffer represented by b is
+ * queued in the request instead of the vb2 queue. The buffer will be passed
+ * to the vb2 queue when the request is submitted.
+ *
+ * The return values from this function are intended to be directly returned
+ * from &v4l2_ioctl_ops->vidioc_qbuf handler in driver.
+ */
+int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
+		     struct media_request_entity *entity);
+
+/**
+ * vb2_request_submit() - Queue all the buffers in a v4l2 request.
+ * @data:	request entity data to queue buffers of
+ *
+ * This function should be called from the media_request_entity_ops::submit
+ * hook for instances of media_request_v4l2_entity_data. It will immediately
+ * queue all the request-bound buffers to their respective vb2 queues.
+ *
+ * Errors from vb2_core_qbuf() are returned if something happened. Also, since
+ * v4l2 request entities require at least one buffer for the request to trigger,
+ * this function will return -EINVAL if no buffer have been bound at all for
+ * this entity.
+ */
+int vb2_request_submit(struct v4l2_request_entity_data *data);
+
+#else /* CONFIG_MEDIA_REQUEST_API */
+
+static inline int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
+				   struct media_request_entity *entity)
+{
+	return vb2_qbuf(q, b);
+}
+
+static inline int vb2_request_submit(struct v4l2_request_entity_data *data)
+{
+	return -ENOTSUPP;
+}
+
+#endif /* CONFIG_MEDIA_REQUEST_API */
+
 /**
  * vb2_expbuf() - Export a buffer as a file descriptor
  * @q:		pointer to &struct vb2_queue with videobuf2 queue.
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 14/21] videodev2.h: add request_fd field to v4l2_ext_controls
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (12 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 13/21] media: videobuf2-v4l2: " Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 15/21] v4l2-ctrls: support requests in EXT_CTRLS ioctls Alexandre Courbot
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Allow to specify a request to be used with the S_EXT_CTRLS and
G_EXT_CTRLS operations.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 2 +-
 include/uapi/linux/videodev2.h       | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 7bfeaf233d5a..2f40ac0cdf6e 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -870,7 +870,7 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
 	__u32 i;
 
 	/* zero the reserved fields */
-	c->reserved[0] = c->reserved[1] = 0;
+	c->reserved[0] = 0;
 	for (i = 0; i < c->count; i++)
 		c->controls[i].reserved2[0] = 0;
 
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 4fd46ae8fad5..91cfe0cbd5c5 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1592,7 +1592,8 @@ struct v4l2_ext_controls {
 	};
 	__u32 count;
 	__u32 error_idx;
-	__u32 reserved[2];
+	__s32 request_fd;
+	__u32 reserved[1];
 	struct v4l2_ext_control *controls;
 };
 
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 15/21] v4l2-ctrls: support requests in EXT_CTRLS ioctls
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (13 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 14/21] videodev2.h: add request_fd field to v4l2_ext_controls Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 16/21] v4l2: video_device: support for creating requests Alexandre Courbot
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Read and use the request_fd field of struct v4l2_ext_controls to apply
VIDIOC_G_EXT_CTRLS or VIDIOC_S_EXT_CTRLS to a request when asked by
userspace.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/platform/omap3isp/ispvideo.c |  2 +-
 drivers/media/v4l2-core/v4l2-ctrls.c       | 98 +++++++++++++++++++++-
 drivers/media/v4l2-core/v4l2-ioctl.c       |  6 +-
 drivers/media/v4l2-core/v4l2-subdev.c      |  2 +-
 include/media/v4l2-ctrls.h                 |  3 +-
 5 files changed, 102 insertions(+), 9 deletions(-)

diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index a751c89a3ea8..3976cd9ac2f2 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -1028,7 +1028,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
 	ctrls.count = 1;
 	ctrls.controls = &ctrl;
 
-	ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
+	ret = v4l2_g_ext_ctrls(NULL, pipe->external->ctrl_handler, &ctrls);
 	if (ret < 0) {
 		dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
 			 pipe->external->name);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 7a81aa5959c3..d7b1aeb32470 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -27,6 +27,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-request.h>
 
 #define has_op(master, op) \
 	(master->ops && master->ops->op)
@@ -2959,9 +2960,44 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
 }
 
 
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+static struct media_request *
+get_handler_for_request(struct v4l2_fh *fh, struct v4l2_ext_controls *cs,
+			struct v4l2_ctrl_handler **hdl)
+{
+	struct media_request *req;
+	struct v4l2_request_entity_data *data;
+
+	if (!fh || !fh->entity)
+		return ERR_PTR(-EINVAL);
+
+	req = media_request_get_from_fd(cs->request_fd);
+	if (!req)
+		return ERR_PTR(-EINVAL);
+
+	data = to_v4l2_entity_data(media_request_get_entity_data(req,
+								 fh->entity));
+	if (IS_ERR(data)) {
+		media_request_put(req);
+		return (void *)data;
+	}
+
+	*hdl = &data->ctrls;
+
+	return req;
+}
+#else
+static struct media_request *
+get_handler_for_request(struct v4l2_fh *fh, struct v4l2_ext_controls *cs,
+			struct v4l2_ctrl_handler **hdl)
+{
+	return ERR_PTR(-ENOTSUPP);
+}
+#endif
 
 /* Get extended controls. Allocates the helpers array if needed. */
-int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+int __v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+		       struct v4l2_ext_controls *cs)
 {
 	struct v4l2_ctrl_helper helper[4];
 	struct v4l2_ctrl_helper *helpers = helper;
@@ -3042,6 +3078,30 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
 		kvfree(helpers);
 	return ret;
 }
+
+int v4l2_g_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+		     struct v4l2_ext_controls *cs)
+{
+	struct media_request *req = NULL;
+	int ret;
+
+	if (cs->request_fd > 0) {
+		req = get_handler_for_request(fh, cs, &hdl);
+		if (IS_ERR(req))
+			return PTR_ERR(req);
+
+		 media_request_lock(req);
+	}
+
+	ret = __v4l2_g_ext_ctrls(hdl, cs);
+
+	if (req) {
+		media_request_unlock(req);
+		media_request_put(req);
+	}
+
+	return ret;
+}
 EXPORT_SYMBOL(v4l2_g_ext_ctrls);
 
 /* Helper function to get a single control */
@@ -3217,9 +3277,9 @@ static void update_from_auto_cluster(struct v4l2_ctrl *master)
 }
 
 /* Try or try-and-set controls */
-static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
-			     struct v4l2_ext_controls *cs,
-			     bool set)
+static int __try_set_ext_ctrls(struct v4l2_fh *fh,
+			       struct v4l2_ctrl_handler *hdl,
+			       struct v4l2_ext_controls *cs, bool set)
 {
 	struct v4l2_ctrl_helper helper[4];
 	struct v4l2_ctrl_helper *helpers = helper;
@@ -3332,6 +3392,36 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 	return ret;
 }
 
+static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
+			     struct v4l2_ext_controls *cs, bool set)
+{
+	struct media_request *req = NULL;
+	int ret;
+
+	if (cs->request_fd > 0) {
+		req = get_handler_for_request(fh, cs, &hdl);
+		if (IS_ERR(req))
+			return PTR_ERR(req);
+
+		media_request_lock(req);
+
+		if (media_request_get_state(req) != MEDIA_REQUEST_STATE_IDLE) {
+			ret = -EBUSY;
+			goto out;
+		}
+	}
+
+	ret = __try_set_ext_ctrls(fh, hdl, cs, set);
+
+out:
+	if (req) {
+		media_request_unlock(req);
+		media_request_put(req);
+	}
+
+	return ret;
+}
+
 int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
 {
 	return try_set_ext_ctrls(NULL, hdl, cs, false);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 2f40ac0cdf6e..ab4968ea443f 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -2077,10 +2077,11 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 		test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
 
 	p->error_idx = p->count;
+
 	if (vfh && vfh->ctrl_handler)
-		return v4l2_g_ext_ctrls(vfh->ctrl_handler, p);
+		return v4l2_g_ext_ctrls(vfh, vfh->ctrl_handler, p);
 	if (vfd->ctrl_handler)
-		return v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
+		return v4l2_g_ext_ctrls(NULL, vfd->ctrl_handler, p);
 	if (ops->vidioc_g_ext_ctrls == NULL)
 		return -ENOTTY;
 	return check_ext_ctrls(p, 0) ? ops->vidioc_g_ext_ctrls(file, fh, p) :
@@ -2096,6 +2097,7 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops,
 		test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
 
 	p->error_idx = p->count;
+
 	if (vfh && vfh->ctrl_handler)
 		return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
 	if (vfd->ctrl_handler)
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index c5639817db34..c547788026c6 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -202,7 +202,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 		return v4l2_s_ctrl(vfh, vfh->ctrl_handler, arg);
 
 	case VIDIOC_G_EXT_CTRLS:
-		return v4l2_g_ext_ctrls(vfh->ctrl_handler, arg);
+		return v4l2_g_ext_ctrls(vfh, vfh->ctrl_handler, arg);
 
 	case VIDIOC_S_EXT_CTRLS:
 		return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, arg);
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 3a10fb3419e3..7c6a76479099 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -1126,12 +1126,13 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
  * v4l2_g_ext_ctrls - Helper function to implement
  *	:ref:`VIDIOC_G_EXT_CTRLS <vidioc_g_ext_ctrls>` ioctl
  *
+ * @fh: pointer to &struct v4l2_fh
  * @hdl: pointer to &struct v4l2_ctrl_handler
  * @c: pointer to &struct v4l2_ext_controls
  *
  * If hdl == NULL then they will all return -EINVAL.
  */
-int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+int v4l2_g_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
 		     struct v4l2_ext_controls *c);
 
 /**
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 16/21] v4l2: video_device: support for creating requests
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (14 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 15/21] v4l2-ctrls: support requests in EXT_CTRLS ioctls Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20 16:35   ` Hans Verkuil
  2018-02-20  4:44 ` [RFCv4 17/21] media: mem2mem: support for requests Alexandre Courbot
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Add a new VIDIOC_NEW_REQUEST ioctl, which allows to instanciate requests
on devices that support the request API. Requests created that way can
only control the device they originate from, making them suitable for
simple devices, but not complex pipelines.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 Documentation/ioctl/ioctl-number.txt |  1 +
 drivers/media/v4l2-core/v4l2-dev.c   |  2 ++
 drivers/media/v4l2-core/v4l2-ioctl.c | 25 +++++++++++++++++++++++++
 include/media/v4l2-dev.h             |  2 ++
 include/uapi/linux/videodev2.h       |  3 +++
 5 files changed, 33 insertions(+)

diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 6501389d55b9..afdc9ed255b0 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -286,6 +286,7 @@ Code  Seq#(hex)	Include File		Comments
 					<mailto:oe@port.de>
 'z'	10-4F	drivers/s390/crypto/zcrypt_api.h	conflict!
 '|'	00-7F	linux/media.h
+'|'	80-9F	linux/media-request.h
 0x80	00-1F	linux/fb.h
 0x89	00-06	arch/x86/include/asm/sockios.h
 0x89	0B-DF	linux/sockios.h
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 0301fe426a43..062ebee5bffc 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -559,6 +559,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 		set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
 	if (vdev->ctrl_handler || ops->vidioc_querymenu)
 		set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
+	if (vdev->req_mgr)
+		set_bit(_IOC_NR(VIDIOC_NEW_REQUEST), valid_ioctls);
 	SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
 	SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
 	SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index ab4968ea443f..a45fe078f8ae 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -21,6 +21,7 @@
 
 #include <linux/videodev2.h>
 
+#include <media/media-request.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
@@ -842,6 +843,13 @@ static void v4l_print_freq_band(const void *arg, bool write_only)
 			p->rangehigh, p->modulation);
 }
 
+static void vidioc_print_new_request(const void *arg, bool write_only)
+{
+	const struct media_request_new *new = arg;
+
+	pr_cont("fd=0x%x\n", new->fd);
+}
+
 static void v4l_print_edid(const void *arg, bool write_only)
 {
 	const struct v4l2_edid *p = arg;
@@ -2486,6 +2494,22 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
 	return -ENOTTY;
 }
 
+static int vidioc_new_request(const struct v4l2_ioctl_ops *ops,
+			      struct file *file, void *fh, void *arg)
+{
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+	struct media_request_new *new = arg;
+	struct video_device *vfd = video_devdata(file);
+
+	if (!vfd->req_mgr)
+		return -ENOTTY;
+
+	return media_request_ioctl_new(vfd->req_mgr, new);
+#else
+	return -ENOTTY;
+#endif
+}
+
 struct v4l2_ioctl_info {
 	unsigned int ioctl;
 	u32 flags;
@@ -2617,6 +2641,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
 	IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
 	IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
 	IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
+	IOCTL_INFO_FNC(VIDIOC_NEW_REQUEST, vidioc_new_request, vidioc_print_new_request, 0),
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 53f32022fabe..e6c4e10889bc 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -209,6 +209,7 @@ struct v4l2_file_operations {
  * @entity: &struct media_entity
  * @intf_devnode: pointer to &struct media_intf_devnode
  * @pipe: &struct media_pipeline
+ * @req_mgr: request manager to use if this device supports creating requests
  * @fops: pointer to &struct v4l2_file_operations for the video device
  * @device_caps: device capabilities as used in v4l2_capabilities
  * @dev: &struct device for the video device
@@ -251,6 +252,7 @@ struct video_device
 	struct media_intf_devnode *intf_devnode;
 	struct media_pipeline pipe;
 #endif
+	struct media_request_mgr *req_mgr;
 	const struct v4l2_file_operations *fops;
 
 	u32 device_caps;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 91cfe0cbd5c5..35706204e81d 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -63,6 +63,7 @@
 #include <linux/compiler.h>
 #include <linux/ioctl.h>
 #include <linux/types.h>
+#include <linux/media-request.h>
 #include <linux/v4l2-common.h>
 #include <linux/v4l2-controls.h>
 
@@ -2407,6 +2408,8 @@ struct v4l2_create_buffers {
 
 #define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
 
+#define VIDIOC_NEW_REQUEST	_IOWR('V', 104, struct media_request_new)
+
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
 
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 17/21] media: mem2mem: support for requests
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (15 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 16/21] v4l2: video_device: support for creating requests Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 18/21] Documentation: v4l: document request API Alexandre Courbot
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Add generic support for requests to the mem2mem framework. This just
requires calling vb2_qbuf_request() instead of vb2_qbuf() in
v4l2_m2m_qbuf().

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/v4l2-core/v4l2-mem2mem.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index c4f963d96a79..d9ae428651c4 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -388,11 +388,12 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
 int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 		  struct v4l2_buffer *buf)
 {
+	struct v4l2_fh *fh = file->private_data;
 	struct vb2_queue *vq;
 	int ret;
 
 	vq = v4l2_m2m_get_vq(m2m_ctx, buf->type);
-	ret = vb2_qbuf(vq, buf);
+	ret = vb2_qbuf_request(vq, buf, fh->entity);
 	if (!ret)
 		v4l2_m2m_try_schedule(m2m_ctx);
 
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 18/21] Documentation: v4l: document request API
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (16 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 17/21] media: mem2mem: support for requests Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 19/21] media: vim2m: add request support Alexandre Courbot
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Document the request API for V4L2 devices, and amend the documentation
of system calls influenced by it.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 Documentation/media/uapi/v4l/buffer.rst       |   9 +-
 Documentation/media/uapi/v4l/common.rst       |   1 +
 Documentation/media/uapi/v4l/request-api.rst  | 199 ++++++++++++++++++
 Documentation/media/uapi/v4l/user-func.rst    |   1 +
 .../media/uapi/v4l/vidioc-g-ext-ctrls.rst     |  16 +-
 .../media/uapi/v4l/vidioc-new-request.rst     |  64 ++++++
 Documentation/media/uapi/v4l/vidioc-qbuf.rst  |   7 +
 7 files changed, 293 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/media/uapi/v4l/request-api.rst
 create mode 100644 Documentation/media/uapi/v4l/vidioc-new-request.rst

diff --git a/Documentation/media/uapi/v4l/buffer.rst b/Documentation/media/uapi/v4l/buffer.rst
index ae6ee73f151c..62caa8c9120d 100644
--- a/Documentation/media/uapi/v4l/buffer.rst
+++ b/Documentation/media/uapi/v4l/buffer.rst
@@ -301,10 +301,13 @@ struct v4l2_buffer
 	elements in the ``planes`` array. The driver will fill in the
 	actual number of valid elements in that array.
     * - __u32
-      - ``reserved2``
+      - ``request_fd``
       -
-      - A place holder for future extensions. Drivers and applications
-	must set this to 0.
+      - The file descriptor of the request to queue the buffer to. If specified,
+	the buffer will be queued to that request. If zero, the buffer will
+	be directly queued to the queue designated by the ``type`` field. This
+	is set by the user when calling :ref:`VIDIOC_QBUF` and ignored by other
+	ioctls.
     * - __u32
       - ``reserved``
       -
diff --git a/Documentation/media/uapi/v4l/common.rst b/Documentation/media/uapi/v4l/common.rst
index 13f2ed3fc5a6..a4aa0059d45a 100644
--- a/Documentation/media/uapi/v4l/common.rst
+++ b/Documentation/media/uapi/v4l/common.rst
@@ -44,3 +44,4 @@ applicable to all devices.
     crop
     selection-api
     streaming-par
+    request-api
diff --git a/Documentation/media/uapi/v4l/request-api.rst b/Documentation/media/uapi/v4l/request-api.rst
new file mode 100644
index 000000000000..0c1f2896e197
--- /dev/null
+++ b/Documentation/media/uapi/v4l/request-api.rst
@@ -0,0 +1,199 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _media-request-api:
+
+Request API
+===========
+
+The Request API has been designed to allow V4L2 to deal with requirements of
+modern devices (stateless codecs, MIPI cameras, ...) and APIs (Android Codec
+v2). One such requirement is the ability for devices belonging to the same
+pipeline to reconfigure and collaborate closely on a per-frame basis. Another is
+efficient support of stateless codecs, which need per-frame controls to be set
+asynchronously in order to be efficiently used.
+
+Supporting these features without the Request API is possible but terribly
+inefficient: user-space would have to flush all activity on the media pipeline,
+reconfigure it for the next frame, queue the buffers to be processed with that
+configuration, and wait until they are all available for dequeing before
+considering the next frame. This defeats the purpose of having buffer queues
+since in practice only one buffer would be queued at a time.
+
+The Request API allows a specific configuration of the pipeline (media
+controller topology + controls for each device) to be associated with specific
+buffers. The parameters are applied by each participating device as buffers
+associated to a request flow in. This allows user-space to schedule several
+tasks ("requests") with different parameters in advance, knowing that the
+parameters will be applied when needed to get the expected result. Controls
+values at the time of request completion are also available for reading.
+
+Usage
+=====
+
+The Request API is used on top of standard media controller and V4L2 calls,
+which are augmented with an extra ``request_fd`` parameter. Request themselves
+are allocated from either a supporting V4L2 device node, or a supporting media
+controller node. The origin of requests determine their scope: requests
+allocated from a V4L2 device node can only act on that device, whereas requests
+allocated from a media controller node can control the whole pipeline of the
+controller.
+
+Request Allocation
+------------------
+
+User-space allocates requests using the ``VIDIOC_NEW_REQUEST`` (for V4L2 device
+requests) or ``MEDIA_IOC_NEW_REQUEST`` (for media controller requests) on an
+opened device or media node. This returns a file descriptor representing the
+request. Typically, several such requests will be allocated.
+
+Request Preparation
+-------------------
+
+Standard V4L2 ioctls can then receive a request file descriptor to express the
+fact that the ioctl is part of said request, and is not to be applied
+immediately. V4L2 ioctls supporting this are :c:func:`VIDIOC_S_EXT_CTRLS` and
+:c:func:`VIDIOC_QBUF`. Controls set with a request parameter are stored instead
+of being immediately applied, and queued buffers not enter the regular buffer
+queue until the request is submitted. Only one buffer can be queued to a given
+queue for a given request.
+
+Request Submission
+------------------
+
+Once the parameters and buffers of the request are specified, it can be
+submitted by calling the ``MEDIA_REQUEST_IOC_SUBMIT`` ioctl on the request FD.
+This will make the buffers associated to the request available to their driver,
+which can then apply the saved controls as buffers are processed. A submitted
+request cannot be modified anymore.
+
+If several devices are part of the request, individual drivers may synchronize
+so the requested pipeline's topology is applied before the buffers are
+processed. This is at the discretion of media controller drivers and is not a
+requirement.
+
+Buffers queued without an associated request after a request-bound buffer will
+be processed using the state of the hardware at the time of the request
+completion. All the same, controls set without a request are applied
+immediately, regardless of whether a request is in use or not.
+
+User-space can ``poll()`` a request FD in order to wait until the request
+completes. A request is considered complete once all its associated buffers are
+available for dequeing. Note that user-space does not need to wait for the
+request to complete to dequeue its buffers: buffers that are available halfway
+through a request can be dequeued independently of the request's state.
+
+A completed request includes the state of all devices that had queued buffers
+associated with it at the time of the request completion. User-space can query
+that state by calling :c:func:`VIDIOC_G_EXT_CTRLS` with the request FD.
+
+Recycling and Destruction
+-------------------------
+
+Finally, completed request can either be discarded or be reused. Calling
+``close()`` on a request FD will make that FD unusable, freeing the request if
+it is not referenced elsewhere. The ``MEDIA_REQUEST_IOC_SUBMIT`` ioctl will
+clear a request's state and make it available again. No state is retained by
+this operation: the request is as if it had just been allocated.
+
+Example for a M2M Device
+------------------------
+
+M2M devices are single-node V4L2 devices providing one OUTPUT queue (for
+user-space
+to provide input buffers) and one CAPTURE queue (to retrieve processed data).
+They are perfectly symetric, i.e. one buffer of input will produce one buffer of
+output. These devices are commonly used for frame processors or stateless
+codecs.
+
+In this use-case, the request API can be used to associate specific controls to
+be applied by the driver before processing an OUTPUT buffer, allowing user-space
+to queue many such buffers in advance. It can also take advantage of requests'
+ability to capture the state of controls when the request completes to read back
+information that may be subject to change.
+
+Put into code, after obtaining a request, user-space can assign controls and one
+OUTPUT buffer to it:
+
+	struct v4l2_buf buf;
+	struct v4l2_ext_controls ctrls;
+	struct media_request_new new = { 0 };
+	int req_fd;
+	...
+	ioctl(media_fd, VIDIOC_NEW_REQUEST, &new);
+	req_fd = new.fd;
+	...
+	ctrls.request_fd = req_fd;
+	ioctl(codec_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
+	...
+	buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	buf.request_fd = req_fd;
+	ioctl(codec_fd, VIDIOC_QBUF, &buf);
+
+Note that request_fd does not need to be specified for CAPTURE buffers: since
+there is symetry between the OUTPUT and CAPTURE queues, and requests are
+processed in order of submission, we can know which CAPTURE buffer corresponds
+to which request.
+
+Once the request is fully prepared, it can be submitted to the driver:
+
+	ioctl(request_fd, MEDIA_REQUEST_IOC_SUBMIT, NULL);
+
+User-space can then either wait for the request to complete by calling poll() on
+its file descriptor, or start dequeuing CAPTURE buffers. Most likely, it will
+want to get CAPTURE buffers as soon as possible and this can be done using a
+regular DQBUF:
+
+	struct v4l2_buf buf;
+
+	memset(&buf, 0, sizeof(buf));
+	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ioctl(codec_fd, VIDIOC_DQBUF, &buf);
+
+We can then, after ensuring that the request is completed via polling the
+request FD, query control values at the time of its completion via an
+annotated call to G_EXT_CTRLS. This is particularly useful for volatile controls
+for which we want to query values as soon as the capture buffer is produced.
+
+	struct pollfd pfd = { .events = POLLIN, .fd = request_fd };
+	poll(&pfd, 1, -1);
+	...
+	ctrls.request_fd = req_fd;
+	ioctl(codec_fd, VIDIOC_G_EXT_CTRLS, &ctrls);
+
+Once we don't need the request anymore, we can either recycle it for reuse with
+MEDIA_REQUEST_IOC_REINIT...
+
+	ioctl(request, MEDIA_REQUEST_IOC_REINIT, NULL);
+
+... or close its file descriptor to completely dispose of it.
+
+	close(request_fd);
+
+Example for a Simple Capture Device
+-----------------------------------
+
+With a simple capture device, requests can be used to specify controls to apply
+to a given CAPTURE buffer. The driver will apply these controls before producing
+the marked CAPTURE buffer.
+
+	struct v4l2_buf buf;
+	struct v4l2_ext_controls ctrls;
+	struct media_request_new new = { 0 };
+	int req_fd;
+	...
+	ioctl(camera_fd, VIDIOC_NEW_REQUEST, &new);
+	req_fd = new.fd;
+	...
+	ctrls.request_fd = req_fd;
+	ioctl(camera_fd, VIDIOC_S_EXT_CTRLS, &ctrls);
+	...
+	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	buf.request_fd = req_fd;
+	ioctl(camera_fd, VIDIOC_QBUF, &buf);
+
+Once the request is fully prepared, it can be submitted to the driver:
+
+	ioctl(req_fd, MEDIA_REQUEST_IOC_SUBMIT, &cmd);
+
+User-space can then dequeue buffers, wait for the request completion, query
+controls and recycle the request as in the M2M example above.
diff --git a/Documentation/media/uapi/v4l/user-func.rst b/Documentation/media/uapi/v4l/user-func.rst
index 3e0413b83a33..2c8238a2b188 100644
--- a/Documentation/media/uapi/v4l/user-func.rst
+++ b/Documentation/media/uapi/v4l/user-func.rst
@@ -53,6 +53,7 @@ Function Reference
     vidioc-g-std
     vidioc-g-tuner
     vidioc-log-status
+    vidioc-new-request
     vidioc-overlay
     vidioc-prepare-buf
     vidioc-qbuf
diff --git a/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst b/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst
index 2011c2b2ee67..3b0dacec9962 100644
--- a/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst
+++ b/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst
@@ -95,6 +95,17 @@ appropriate. In the first case the new value is set in struct
 is inappropriate (e.g. the given menu index is not supported by the menu
 control), then this will also result in an ``EINVAL`` error code error.
 
+If ``request_fd`` is set to a not-submitted request file descriptor, then the
+controls are not applied immediately when calling
+:ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_S_EXT_CTRLS>`, but instead are applied right
+before the driver starts processing a buffer associated to the same request.
+
+If ``request_fd`` is specified during a call to
+:ref:`VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>`, then the returned values will
+be the values currently set for the request (or the hardware value if none is
+set) if the request has not yet completed, or the values of the controls at the
+time of request completion if it has already completed.
+
 The driver will only set/get these controls if all control values are
 correct. This prevents the situation where only some of the controls
 were set/get. Only low-level errors (e. g. a failed i2c command) can
@@ -272,8 +283,11 @@ still cause this situation.
 	then you can call :ref:`VIDIOC_TRY_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` to try to discover the
 	actual control that failed the validation step. Unfortunately,
 	there is no ``TRY`` equivalent for :ref:`VIDIOC_G_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>`.
+    * - __s32
+      - ``request_fd``
+	File descriptor of the request to be used by this operation (0 if none).
     * - __u32
-      - ``reserved``\ [2]
+      - ``reserved``\ [1]
       - Reserved for future extensions.
 
 	Drivers and applications must set the array to zero.
diff --git a/Documentation/media/uapi/v4l/vidioc-new-request.rst b/Documentation/media/uapi/v4l/vidioc-new-request.rst
new file mode 100644
index 000000000000..0038287f7d16
--- /dev/null
+++ b/Documentation/media/uapi/v4l/vidioc-new-request.rst
@@ -0,0 +1,64 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _VIDIOC_NEW_REQUEST:
+
+************************
+ioctl VIDIOC_NEW_REQUEST
+************************
+
+Name
+====
+
+VIDIOC_NEW_REQUEST - Allocate a request for given video device.
+
+
+Synopsis
+========
+
+.. c:function:: int ioctl( int fd, VIDIOC_NEW_REQUEST, struct media_request_new *argp )
+    :name: VIDIOC_NEW_REQUEST
+
+Arguments
+=========
+
+``fd``
+    File descriptor returned by :ref:`open() <func-open>`.
+
+``argp``
+    Pointer to struct :c:type:`media_request_new`.
+
+
+Description
+===========
+
+Applications call the ``VIDIOC_NEW_REQUEST`` ioctl to allocate a new request for a given V4L2 video device. The request will only be valid in the scope of the device that allocated it and cannot be used to coordinate multiple devices.
+
+Applications can also check whether requests are supported by a given device by calling this ioctl with the MEDIA_REQUEST_FLAG_TEST bit of :c:type:`media_request_new`'s ``flags`` set. Doing so will not allocate a new request, but will return 0 is request allocation is supported by the device, or -1 and set ``errno`` to ENOTTY if they are not.
+
+.. c:type:: media_request_new
+
+.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
+
+.. flat-table:: struct media_request_new
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u32
+      - ``flags``
+      - Flags for this request creation. If ``MEDIA_REQUEST_FLAG_TEST`` is set, then no request is created and the call only checks for request availability. Written by the application.
+    * - __s32
+      - ``fd``
+      - File descriptor referencing the created request. Written by the kernel.
+
+Return Value
+============
+
+On success 0 is returned, and the ``fd`` field of ``argp`` is set to a file descriptor referencing the request. User-space can use this file descriptor to mention the request in other system calls, perform ``MEDIA_REQUEST_IOC_SUBMIT`` and ``MEDIA_REQUEST_IOC_REINIT`` ioctls on it, and close it to discard the request.
+
+On error -1 is returned and the ``errno`` variable is set appropriately.  The
+generic error codes are described in the :ref:`Generic Error Codes <gen-errors>`
+chapter.
+
+ENOTTY
+    The device does not support the use of requests or request support is not built into the kernel.
diff --git a/Documentation/media/uapi/v4l/vidioc-qbuf.rst b/Documentation/media/uapi/v4l/vidioc-qbuf.rst
index 9e448a4aa3aa..12d2e2fd699b 100644
--- a/Documentation/media/uapi/v4l/vidioc-qbuf.rst
+++ b/Documentation/media/uapi/v4l/vidioc-qbuf.rst
@@ -98,6 +98,13 @@ dequeued, until the :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` or
 :ref:`VIDIOC_REQBUFS` ioctl is called, or until the
 device is closed.
 
+The ``request_fd`` field can be used when queuing to specify the file
+descriptor of a request, if requests are in use. Setting it means that the
+buffer will not be passed to the driver until the request itself is submitted.
+Also, the driver will apply any setting associated with the request before
+processing the buffer. Only one buffer per queue can be assigned that way to
+a request.
+
 Applications call the ``VIDIOC_DQBUF`` ioctl to dequeue a filled
 (capturing) or displayed (output) buffer from the driver's outgoing
 queue. They just set the ``type``, ``memory`` and ``reserved`` fields of
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 19/21] media: vim2m: add request support
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (17 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 18/21] Documentation: v4l: document request API Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-03-07 16:37   ` [RFCv4,19/21] " Paul Kocialkowski
  2018-02-20  4:44 ` [RFCv4 20/21] media: vivid: add request support for the video capture device Alexandre Courbot
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Set the necessary ops for supporting requests in vim2m.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/platform/Kconfig |  1 +
 drivers/media/platform/vim2m.c | 75 ++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 614fbef08ddc..09be0b5f9afe 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -534,6 +534,7 @@ source "drivers/media/platform/vivid/Kconfig"
 config VIDEO_VIM2M
 	tristate "Virtual Memory-to-Memory Driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
+	select MEDIA_REQUEST_API
 	select VIDEOBUF2_VMALLOC
 	select V4L2_MEM2MEM_DEV
 	default n
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index 065483e62db4..02793dd9a330 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -30,6 +30,8 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
 #include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-request.h>
+#include <media/videobuf2-v4l2.h>
 
 MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
 MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
@@ -148,6 +150,8 @@ struct vim2m_dev {
 	struct timer_list	timer;
 
 	struct v4l2_m2m_dev	*m2m_dev;
+
+	struct v4l2_request_mgr req_mgr;
 };
 
 struct vim2m_ctx {
@@ -155,6 +159,7 @@ struct vim2m_ctx {
 	struct vim2m_dev	*dev;
 
 	struct v4l2_ctrl_handler hdl;
+	struct v4l2_request_entity req_entity;
 
 	/* Processed buffers in this transaction */
 	u8			num_processed;
@@ -367,6 +372,24 @@ static void job_abort(void *priv)
 	ctx->aborting = 1;
 }
 
+static int apply_request_params(struct media_request *req,
+				struct vim2m_ctx *ctx)
+{
+	struct v4l2_request_entity_data *data;
+
+	if (!req)
+		return -EINVAL;
+
+	data = to_v4l2_entity_data(media_request_get_entity_data(req,
+							&ctx->req_entity.base));
+	if (WARN_ON(IS_ERR(data)))
+		return PTR_ERR(data);
+
+	v4l2_ctrl_request_setup(&data->ctrls);
+
+	return 0;
+}
+
 /* device_run() - prepares and starts the device
  *
  * This simulates all the immediate preparations required before starting
@@ -382,6 +405,19 @@ static void device_run(void *priv)
 	src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
+	WARN_ON(dst_buf->vb2_buf.request != NULL &&
+		dst_buf->vb2_buf.request != src_buf->vb2_buf.request);
+
+	/* Apply request if needed */
+	if (src_buf->vb2_buf.request) {
+		int ret = apply_request_params(src_buf->vb2_buf.request, ctx);
+		if (ret) {
+			dprintk(dev, "error applying request parameters: %d\n",
+				ret);
+			return;
+		}
+	}
+
 	device_process(ctx, src_buf, dst_buf);
 
 	/* Run a timer, which simulates a hardware irq  */
@@ -393,6 +429,7 @@ static void device_isr(struct timer_list *t)
 	struct vim2m_dev *vim2m_dev = from_timer(vim2m_dev, t, timer);
 	struct vim2m_ctx *curr_ctx;
 	struct vb2_v4l2_buffer *src_vb, *dst_vb;
+	struct media_request *req;
 	unsigned long flags;
 
 	curr_ctx = v4l2_m2m_get_curr_priv(vim2m_dev->m2m_dev);
@@ -404,6 +441,7 @@ static void device_isr(struct timer_list *t)
 
 	src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
 	dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+	req = src_vb->vb2_buf.request;
 
 	curr_ctx->num_processed++;
 
@@ -411,6 +449,8 @@ static void device_isr(struct timer_list *t)
 	v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
 	v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
 	spin_unlock_irqrestore(&vim2m_dev->irqlock, flags);
+	if (req)
+		media_request_entity_complete(req, &curr_ctx->req_entity.base);
 
 	if (curr_ctx->num_processed == curr_ctx->translen
 	    || curr_ctx->aborting) {
@@ -838,6 +878,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
 	src_vq->mem_ops = &vb2_vmalloc_memops;
 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	src_vq->lock = &ctx->dev->dev_mutex;
+	src_vq->allow_requests = true;
 
 	ret = vb2_queue_init(src_vq);
 	if (ret)
@@ -851,6 +892,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
 	dst_vq->mem_ops = &vb2_vmalloc_memops;
 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
 	dst_vq->lock = &ctx->dev->dev_mutex;
+	dst_vq->allow_requests = true;
 
 	return vb2_queue_init(dst_vq);
 }
@@ -877,6 +919,31 @@ static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = {
 	.step = 1,
 };
 
+struct media_request_entity_data *
+vim2m_entity_data_alloc(struct media_request *req,
+			struct media_request_entity *entity)
+{
+	struct vim2m_ctx *ctx;
+
+	ctx = container_of(entity, struct vim2m_ctx, req_entity.base);
+	return v4l2_request_entity_data_alloc(req, &ctx->hdl);
+}
+
+static int vim2m_request_submit(struct media_request *req,
+				struct media_request_entity_data *_data)
+{
+	struct v4l2_request_entity_data *data;
+
+	data = to_v4l2_entity_data(_data);
+	return vb2_request_submit(data);
+}
+
+static const struct media_request_entity_ops vim2m_request_entity_ops = {
+	.data_alloc	= vim2m_entity_data_alloc,
+	.data_free	= v4l2_request_entity_data_free,
+	.submit		= vim2m_request_submit,
+};
+
 /*
  * File operations
  */
@@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
 	ctx->dev = dev;
 	hdl = &ctx->hdl;
 	v4l2_ctrl_handler_init(hdl, 4);
+	v4l2_request_entity_init(&ctx->req_entity, &vim2m_request_entity_ops,
+				 &ctx->dev->vfd);
+	ctx->fh.entity = &ctx->req_entity.base;
 	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
 	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
 	v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
@@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device *pdev)
 	if (!dev)
 		return -ENOMEM;
 
+	v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
+			      &v4l2_request_ops);
+
 	spin_lock_init(&dev->irqlock);
 
 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
@@ -1012,6 +1085,7 @@ static int vim2m_probe(struct platform_device *pdev)
 	vfd = &dev->vfd;
 	vfd->lock = &dev->dev_mutex;
 	vfd->v4l2_dev = &dev->v4l2_dev;
+	vfd->req_mgr = &dev->req_mgr.base;
 
 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
 	if (ret) {
@@ -1054,6 +1128,7 @@ static int vim2m_remove(struct platform_device *pdev)
 	del_timer_sync(&dev->timer);
 	video_unregister_device(&dev->vfd);
 	v4l2_device_unregister(&dev->v4l2_dev);
+	v4l2_request_mgr_free(&dev->req_mgr);
 
 	return 0;
 }
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 20/21] media: vivid: add request support for the video capture device
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (18 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 19/21] media: vim2m: add request support Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:44 ` [RFCv4 21/21] [WIP] media: media-device: support for creating requests Alexandre Courbot
  2018-02-20  4:54 ` [RFCv4 00/21] Request API Alexandre Courbot
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Allow to use requests with the video capture device.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/platform/vivid/Kconfig          |  1 +
 drivers/media/platform/vivid/vivid-core.c     | 63 ++++++++++++++++++-
 drivers/media/platform/vivid/vivid-core.h     |  3 +
 .../media/platform/vivid/vivid-kthread-cap.c  | 17 +++++
 4 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig
index 154de92dd809..a6494dabae95 100644
--- a/drivers/media/platform/vivid/Kconfig
+++ b/drivers/media/platform/vivid/Kconfig
@@ -7,6 +7,7 @@ config VIDEO_VIVID
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
+	select MEDIA_REQUEST_API
 	select VIDEOBUF2_VMALLOC
 	select VIDEOBUF2_DMA_CONTIG
 	select VIDEO_V4L2_TPG
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 82ec216f2ad8..c1cf8e7ca2c9 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -23,6 +23,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-request.h>
 
 #include "vivid-core.h"
 #include "vivid-vid-common.h"
@@ -486,6 +487,33 @@ static const struct v4l2_file_operations vivid_fops = {
 	.mmap           = vb2_fop_mmap,
 };
 
+static int vivid_cap_open(struct file *filp)
+{
+	struct vivid_dev *dev;
+	struct v4l2_fh *fh;
+	int ret;
+
+	ret = v4l2_fh_open(filp);
+	if (ret)
+		return ret;
+
+	dev = container_of(video_devdata(filp), struct vivid_dev, vid_cap_dev);
+	fh = filp->private_data;
+	fh->entity = &dev->vid_cap_req_entity.base;
+
+	return ret;
+}
+
+static const struct v4l2_file_operations vivid_cap_fops = {
+	.owner		= THIS_MODULE,
+	.open           = vivid_cap_open,
+	.release        = vivid_fop_release,
+	.read           = vb2_fop_read,
+	.write          = vb2_fop_write,
+	.poll		= vb2_fop_poll,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap           = vb2_fop_mmap,
+};
 static const struct v4l2_file_operations vivid_radio_fops = {
 	.owner		= THIS_MODULE,
 	.open           = v4l2_fh_open,
@@ -607,6 +635,31 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
 };
 
+struct media_request_entity_data *
+vid_cap_entity_data_alloc(struct media_request *req,
+			struct media_request_entity *entity)
+{
+	struct vivid_dev *dev;
+
+	dev = container_of(entity, struct vivid_dev, vid_cap_req_entity.base);
+	return v4l2_request_entity_data_alloc(req, &dev->ctrl_hdl_vid_cap);
+}
+
+static int vid_cap_request_submit(struct media_request *req,
+				struct media_request_entity_data *_data)
+{
+	struct v4l2_request_entity_data *data;
+
+	data = to_v4l2_entity_data(_data);
+	return vb2_request_submit(data);
+}
+
+static const struct media_request_entity_ops vivid_request_entity_ops = {
+	.data_alloc	= vid_cap_entity_data_alloc,
+	.data_free	= v4l2_request_entity_data_free,
+	.submit		= vid_cap_request_submit,
+};
+
 /* -----------------------------------------------------------------
 	Initialization and module stuff
    ------------------------------------------------------------------*/
@@ -1057,6 +1110,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
 		q->mem_ops = vivid_mem_ops[allocator];
 		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
 		q->min_buffers_needed = 2;
+		q->allow_requests = true;
 		q->lock = &dev->mutex;
 		q->dev = dev->v4l2_dev.dev;
 
@@ -1158,13 +1212,19 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
 		vfd = &dev->vid_cap_dev;
 		snprintf(vfd->name, sizeof(vfd->name),
 			 "vivid-%03d-vid-cap", inst);
-		vfd->fops = &vivid_fops;
+		vfd->fops = &vivid_cap_fops;
 		vfd->ioctl_ops = &vivid_ioctl_ops;
 		vfd->device_caps = dev->vid_cap_caps;
 		vfd->release = video_device_release_empty;
 		vfd->v4l2_dev = &dev->v4l2_dev;
 		vfd->queue = &dev->vb_vid_cap_q;
 		vfd->tvnorms = tvnorms_cap;
+		vfd->req_mgr = &dev->vid_cap_req_mgr.base;
+		v4l2_request_mgr_init(&dev->vid_cap_req_mgr, vfd,
+				      &v4l2_request_ops);
+		v4l2_request_entity_init(&dev->vid_cap_req_entity,
+					 &vivid_request_entity_ops,
+					 vfd);
 
 		/*
 		 * Provide a mutex to v4l2 core. It will be used to protect
@@ -1448,6 +1508,7 @@ static int vivid_remove(struct platform_device *pdev)
 			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
 				video_device_node_name(&dev->vid_cap_dev));
 			video_unregister_device(&dev->vid_cap_dev);
+			v4l2_request_mgr_free(&dev->vid_cap_req_mgr);
 		}
 		if (dev->has_vid_out) {
 			v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 477c80a4d44c..c8adcbb1c1d1 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -11,6 +11,7 @@
 #include <linux/fb.h>
 #include <linux/workqueue.h>
 #include <media/cec.h>
+#include <media/v4l2-request.h>
 #include <media/videobuf2-v4l2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-dev.h>
@@ -145,6 +146,8 @@ struct vivid_dev {
 	struct v4l2_ctrl_handler	ctrl_hdl_fb;
 	struct video_device		vid_cap_dev;
 	struct v4l2_ctrl_handler	ctrl_hdl_vid_cap;
+	struct v4l2_request_mgr		vid_cap_req_mgr;
+	struct v4l2_request_entity	vid_cap_req_entity;
 	struct video_device		vid_out_dev;
 	struct v4l2_ctrl_handler	ctrl_hdl_vid_out;
 	struct video_device		vbi_cap_dev;
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 3fdb280c36ca..0d0866dc11b3 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -19,6 +19,7 @@
 #include <linux/random.h>
 #include <linux/v4l2-dv-timings.h>
 #include <asm/div64.h>
+#include <media/media-request.h>
 #include <media/videobuf2-vmalloc.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-ioctl.h>
@@ -703,6 +704,17 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
 		goto update_mv;
 
 	if (vid_cap_buf) {
+		struct media_request *req = vid_cap_buf->vb.vb2_buf.request;
+
+		/* Using request? Apply its controls */
+		if (req) {
+			struct v4l2_request_entity_data *data;
+			data = to_v4l2_entity_data(
+				media_request_get_entity_data(req,
+						&dev->vid_cap_req_entity.base));
+			if (!WARN_ON(IS_ERR(data)))
+				v4l2_ctrl_request_setup(&data->ctrls);
+		}
 		/* Fill buffer */
 		vivid_fillbuff(dev, vid_cap_buf);
 		dprintk(dev, 1, "filled buffer %d\n",
@@ -717,6 +729,11 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
 				VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
 		dprintk(dev, 2, "vid_cap buffer %d done\n",
 				vid_cap_buf->vb.vb2_buf.index);
+		if (req)
+			media_request_entity_complete(req,
+						 &dev->vid_cap_req_entity.base);
+		dprintk(dev, 2, "vid_cap buffer %d request completed\n",
+				vid_cap_buf->vb.vb2_buf.index);
 	}
 
 	if (vbi_cap_buf) {
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 21/21] [WIP] media: media-device: support for creating requests
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (19 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 20/21] media: vivid: add request support for the video capture device Alexandre Courbot
@ 2018-02-20  4:44 ` Alexandre Courbot
  2018-02-20  4:54 ` [RFCv4 00/21] Request API Alexandre Courbot
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:44 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

Add a new MEDIA_IOC_NEW_REQUEST ioctl, which can be used to instantiate
a request suitable to control the media device topology as well as the
parameters and buffer flow of its entities.

This is still very early work, and mainly here to demonstrate that it is
still possible to bind requests to media entities.

Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
---
 drivers/media/media-device.c | 11 +++++++++++
 include/media/mc-request.h   | 33 +++++++++++++++++++++++++++++++++
 include/media/media-device.h |  1 +
 include/media/media-entity.h |  5 +++++
 include/uapi/linux/media.h   |  2 ++
 5 files changed, 52 insertions(+)
 create mode 100644 include/media/mc-request.h

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index e79f72b8b858..2fb8b9c5ec85 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -32,6 +32,7 @@
 #include <media/media-device.h>
 #include <media/media-devnode.h>
 #include <media/media-entity.h>
+#include <media/media-request.h>
 
 #ifdef CONFIG_MEDIA_CONTROLLER
 
@@ -359,6 +360,15 @@ static long media_device_get_topology(struct media_device *mdev,
 	return ret;
 }
 
+static long media_device_new_request(struct media_device *mdev,
+				     struct media_request_new *new)
+{
+	if (!mdev->req_mgr)
+		return -ENOTTY;
+
+	return media_request_ioctl_new(mdev->req_mgr, new);
+}
+
 static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
 {
 	/* All media IOCTLs are _IOWR() */
@@ -407,6 +417,7 @@ static const struct media_ioctl_info ioctl_info[] = {
 	MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
 	MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
 	MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
+	MEDIA_IOC(NEW_REQUEST, media_device_new_request, 0),
 };
 
 static long media_device_ioctl(struct file *filp, unsigned int cmd,
diff --git a/include/media/mc-request.h b/include/media/mc-request.h
new file mode 100644
index 000000000000..c14d38a93019
--- /dev/null
+++ b/include/media/mc-request.h
@@ -0,0 +1,33 @@
+/*
+ * Media requests support for media controller
+ *
+ * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIA_MC_REQUEST_H
+#define _MEDIA_MC_REQUEST_H
+
+#include <linux/kconfig.h>
+#include <media/media-request.h>
+
+#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
+
+struct mc_request_entity {
+	struct media_request_entity base;
+	struct media_entity *entity;
+};
+
+#else  /* CONFIG_MEDIA_REQUEST_API */
+
+#endif  /* CONFIG_MEDIA_REQUEST_API */
+
+#endif
diff --git a/include/media/media-device.h b/include/media/media-device.h
index bcc6ec434f1f..e931e8b9f60e 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -127,6 +127,7 @@ struct media_device {
 	/* dev->driver_data points to this struct. */
 	struct device *dev;
 	struct media_devnode *devnode;
+	struct media_request_mgr *req_mgr;
 
 	char model[32];
 	char driver_name[32];
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index a732af1dbba0..e3525d1ec386 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -26,6 +26,8 @@
 #include <linux/list.h>
 #include <linux/media.h>
 
+struct mc_request_entity;
+
 /* Enums used internally at the media controller to represent graphs */
 
 /**
@@ -243,6 +245,7 @@ enum media_entity_type {
  *		re-used if entities are unregistered or registered again.
  * @pads:	Pads array with the size defined by @num_pads.
  * @links:	List of data links.
+ * @req_entity:	Pointer to the request entity representing this entity, if any
  * @ops:	Entity operations.
  * @stream_count: Stream count for the entity.
  * @use_count:	Use count for the entity.
@@ -279,6 +282,8 @@ struct media_entity {
 	struct media_pad *pads;
 	struct list_head links;
 
+	struct mc_request_entity *req_entity;
+
 	const struct media_entity_operations *ops;
 
 	int stream_count;
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index b9b9446095e9..eb0014c4eb40 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -30,6 +30,7 @@
 #include <linux/ioctl.h>
 #include <linux/types.h>
 #include <linux/version.h>
+#include <linux/media-request.h>
 
 struct media_device_info {
 	char driver[16];
@@ -413,5 +414,6 @@ struct media_v2_topology {
 #define MEDIA_IOC_ENUM_LINKS		_IOWR('|', 0x02, struct media_links_enum)
 #define MEDIA_IOC_SETUP_LINK		_IOWR('|', 0x03, struct media_link_desc)
 #define MEDIA_IOC_G_TOPOLOGY		_IOWR('|', 0x04, struct media_v2_topology)
+#define MEDIA_IOC_NEW_REQUEST		_IOR('|', 0x05, struct media_request_new)
 
 #endif /* __LINUX_MEDIA_H */
-- 
2.16.1.291.g4437f3f132-goog

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

* [RFCv4 00/21] Request API
  2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
                   ` (20 preceding siblings ...)
  2018-02-20  4:44 ` [RFCv4 21/21] [WIP] media: media-device: support for creating requests Alexandre Courbot
@ 2018-02-20  4:54 ` Alexandre Courbot
  21 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  4:54 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Alexandre Courbot

(resending with correct word-wrap - sorry for the inconvenience)

Hi everyone,

And thanks for all the feedback on the previous version! I have tried to address
as much as possible, which results in (another) almost rewrite. But I think the
behavior and structure are converging to something satisfying and usable.

Besides the buffer queuing behavior that has been fixed, some of the big design
changes undertaken are that the media controller framework is not a requirement
anymore (although it can still be used in exactly the same way as before), and
that ioctls related to requests are now performed directly on the request FD.

As discussed with Sakari, the fact that request entities were in fact media
entities was a bit limiting, so I created a request_entity type that can be
embedded into any structure we want to control with requests. This is what
allows drivers to support requests without the media controller: simple V4L2
drivers can use the V4L2 implementation that allows to control a single video
device (as opposed to the whole pipeline under a media controller). Media
controllers can still, of course, use a more complex implementation and control
their whole pipeline, but bringing that complexity to simple drivers seemed
overreached to me.

Independently of the request implementation, request entities can store their
own data, in a way that makes sense regarding their type (that would be
v4l2_request_entity_data for V4L2 devices, but can be another data type for
media controllers topology).

The entity data lookup is also performed on these request_entities, working
effectively like the data store Sakari proposed, but retaining a base type for
data lookup.

Patches are organized as follows:

Patch 1 provides the base request support, not tied to either media or v4l2.

Patches 2 to 8 are the control rework done by Hans, with an extra workaround for
a bug discovered while working on vivid (see commit message for details).

Patch 9 adds request support to V4L2 in the form of entity data for v4l2 devices
to be used in requests, and a request manager capable of producing simple
requests for video devices. Maybe this should be split into different files, but
since the code is not that big I have kept it under the same file.

Patches 10 to 13 add request support to vb2-core and vb2-v4l2.

Patches 14 and 15 add support for the request_fd field in G/S/TRY_EXT_CTRLS
ioctls.

Patch 16 allows requests to be allocated from a supporting V4L2 video device
node.

Patches 17 and 19 add request support to mem2mem and vim2m. Patch 18 documents
usage of requests with V4L2 devices.

Patch 20 adds support to the vivid capture device.

Finally, 21 is a WIP patch implementing request support for media controller
nodes. Requests allocated that way are of a different, broader nature than V4L2
requests, and will be able to control any device managed by the controller. To
allow this, request_entity is embedded into media_entity, so that media entities
can be upcasted as in the previous version.

Phew! That was quite long, sorry about that. As usual, simple programs
demonstrating requests on vim2m and vivid are available:

https://gist.github.com/Gnurou/34c35f1f8e278dad454b51578d239a42
https://gist.github.com/Gnurou/5052e6ab41e7c55164b75d2970bc5a04

If things are starting to look ok, I would like to move on to the next step and
implement support in v4l2-ctl. Maybe also start submitting an actual codec
driver once the control work is completed. And of course, it may be good time to
think about how pipeline configuration would work. The current design should
make this question orthogonal to getting support in for simple V4L2 devices.

Looking forward to your feedback!

Changes since RFC v3:
* Buffer queuing is now performed as soon as the request is queued, allowing
drivers to see them early.
* Request refcounting is done using the file * structure instead of a kref
* Requests can now be used independently of a media controller, to avoid having
to pull it for simple codec drivers. For such drivers, the device node can
allocate requests that are exclusive to this device only. Media controller nodes
can still allocate requests that control their topology as well as the devices
under them.
* Consequently, media_request is now its own module since it can be used
independently of media.ko.
* SUBMIT/REINIT request ioctls are now performed on the request FD instead of
the media device. This means that device/media controller node's business with
requests is limited to allocating them.
* Got rid of request IDs.
* Only allow one buffer to be queued to each queue of request entities.
* The request FD that produced a CAPTURE buffer is not returned to user-space
anymore.
* Added requests support for the Vivid video capture device.
* Let drivers decide individually whether their entities should be per file
handle or global to the device, solving the question we had about this in
previous RFCs. Vim2m provides an example of per-context entities, while vivid
gives an example of a global request entity.
* Improved documentation.

Issues remaining with this version:
* Vivid support exposed what seems to be a limitation in the current controls
cloning implementation. See patch 8 (which works the issue around) for details.
* Media controller implementation of requests is still incomplete. I plan to
complete and exert it on an actual camera driver sometime soon.


Alexandre Courbot (14):
  media: add request API core and UAPI
  [WAR] v4l2-ctrls: do not clone non-standard controls
  v4l2: add request API support
  media: v4l2_fh: add request entity field
  media: videobuf2: add support for requests
  media: videobuf2-v4l2: support for requests
  videodev2.h: add request_fd field to v4l2_ext_controls
  v4l2-ctrls: support requests in EXT_CTRLS ioctls
  v4l2: video_device: support for creating requests
  media: mem2mem: support for requests
  Documentation: v4l: document request API
  media: vim2m: add request support
  media: vivid: add request support for the video capture device
  [WIP] media: media-device: support for creating requests

Hans Verkuil (7):
  v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev
  v4l2-ctrls: prepare internal structs for request API
  v4l2-ctrls: add core request API
  v4l2-ctrls: use ref in helper instead of ctrl
  v4l2-ctrls: support g/s_ext_ctrls for requests
  v4l2-ctrls: add v4l2_ctrl_request_setup
  videodev2.h: Add request_fd field to v4l2_buffer

 Documentation/ioctl/ioctl-number.txt          |   1 +
 Documentation/media/uapi/v4l/buffer.rst       |   9 +-
 Documentation/media/uapi/v4l/common.rst       |   1 +
 Documentation/media/uapi/v4l/request-api.rst  | 199 ++++++++++
 Documentation/media/uapi/v4l/user-func.rst    |   1 +
 .../media/uapi/v4l/vidioc-g-ext-ctrls.rst     |  16 +-
 .../media/uapi/v4l/vidioc-new-request.rst     |  64 ++++
 Documentation/media/uapi/v4l/vidioc-qbuf.rst  |   7 +
 drivers/media/Kconfig                         |   3 +
 drivers/media/Makefile                        |   6 +
 .../media/common/videobuf2/videobuf2-core.c   |   3 +
 .../media/common/videobuf2/videobuf2-v4l2.c   | 131 ++++++-
 drivers/media/dvb-frontends/rtl2832_sdr.c     |   5 +-
 drivers/media/media-device.c                  |  11 +
 drivers/media/media-request.c                 | 341 +++++++++++++++++
 drivers/media/pci/bt8xx/bttv-driver.c         |   2 +-
 drivers/media/pci/cx23885/cx23885-417.c       |   2 +-
 drivers/media/pci/cx88/cx88-blackbird.c       |   2 +-
 drivers/media/pci/cx88/cx88-video.c           |   2 +-
 drivers/media/pci/saa7134/saa7134-empress.c   |   4 +-
 drivers/media/pci/saa7134/saa7134-video.c     |   2 +-
 drivers/media/platform/Kconfig                |   1 +
 .../media/platform/exynos4-is/fimc-capture.c  |   2 +-
 drivers/media/platform/omap3isp/ispvideo.c    |   2 +-
 drivers/media/platform/rcar-vin/rcar-v4l2.c   |   3 +-
 drivers/media/platform/rcar_drif.c            |   2 +-
 .../media/platform/soc_camera/soc_camera.c    |   3 +-
 drivers/media/platform/vim2m.c                |  75 ++++
 drivers/media/platform/vivid/Kconfig          |   1 +
 drivers/media/platform/vivid/vivid-core.c     |  63 +++-
 drivers/media/platform/vivid/vivid-core.h     |   3 +
 drivers/media/platform/vivid/vivid-ctrls.c    |  46 +--
 .../media/platform/vivid/vivid-kthread-cap.c  |  17 +
 drivers/media/usb/cpia2/cpia2_v4l.c           |   2 +-
 drivers/media/usb/cx231xx/cx231xx-417.c       |   2 +-
 drivers/media/usb/cx231xx/cx231xx-video.c     |   4 +-
 drivers/media/usb/msi2500/msi2500.c           |   2 +-
 drivers/media/usb/tm6000/tm6000-video.c       |   2 +-
 drivers/media/v4l2-core/Makefile              |   1 +
 drivers/media/v4l2-core/v4l2-compat-ioctl32.c |   9 +-
 drivers/media/v4l2-core/v4l2-ctrls.c          | 341 +++++++++++++++--
 drivers/media/v4l2-core/v4l2-dev.c            |   2 +
 drivers/media/v4l2-core/v4l2-device.c         |   3 +-
 drivers/media/v4l2-core/v4l2-ioctl.c          |  37 +-
 drivers/media/v4l2-core/v4l2-mem2mem.c        |   3 +-
 drivers/media/v4l2-core/v4l2-request.c        | 178 +++++++++
 drivers/media/v4l2-core/v4l2-subdev.c         |   2 +-
 drivers/staging/media/imx/imx-media-dev.c     |   2 +-
 drivers/staging/media/imx/imx-media-fim.c     |   2 +-
 include/media/mc-request.h                    |  33 ++
 include/media/media-device.h                  |   1 +
 include/media/media-entity.h                  |   5 +
 include/media/media-request.h                 | 349 ++++++++++++++++++
 include/media/v4l2-ctrls.h                    |  20 +-
 include/media/v4l2-dev.h                      |   2 +
 include/media/v4l2-fh.h                       |   3 +
 include/media/v4l2-request.h                  | 159 ++++++++
 include/media/videobuf2-core.h                |   4 +
 include/media/videobuf2-v4l2.h                |  59 +++
 include/uapi/linux/media-request.h            |  37 ++
 include/uapi/linux/media.h                    |   2 +
 include/uapi/linux/videodev2.h                |   9 +-
 62 files changed, 2217 insertions(+), 88 deletions(-)
 create mode 100644 Documentation/media/uapi/v4l/request-api.rst
 create mode 100644 Documentation/media/uapi/v4l/vidioc-new-request.rst
 create mode 100644 drivers/media/media-request.c
 create mode 100644 drivers/media/v4l2-core/v4l2-request.c
 create mode 100644 include/media/mc-request.h
 create mode 100644 include/media/media-request.h
 create mode 100644 include/media/v4l2-request.h
 create mode 100644 include/uapi/linux/media-request.h

-- 
2.16.1.291.g4437f3f132-goog

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

* Re: [RFCv4 09/21] v4l2: add request API support
  2018-02-20  4:44 ` [RFCv4 09/21] v4l2: add request API support Alexandre Courbot
@ 2018-02-20  7:36   ` Philippe Ombredanne
  2018-02-20  8:03     ` Alexandre Courbot
  2018-02-20 13:25   ` Hans Verkuil
  1 sibling, 1 reply; 63+ messages in thread
From: Philippe Ombredanne @ 2018-02-20  7:36 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML

On Tue, Feb 20, 2018 at 5:44 AM, Alexandre Courbot
<acourbot@chromium.org> wrote:
> Add a v4l2 request entity data structure that takes care of storing the
> request-related state of a V4L2 device ; in this case, its controls.
>
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>

<snip>

> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-request.c
> @@ -0,0 +1,178 @@
> +/*
> + * Media requests support for V4L2
> + *
> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */

Do you mind using SPDX tags per [1] rather that this fine but long
legalese. (Here and in the whole patch series)

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/license-rules.rst
-- 
Cordially
Philippe Ombredanne

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

* Re: [RFCv4 09/21] v4l2: add request API support
  2018-02-20  7:36   ` Philippe Ombredanne
@ 2018-02-20  8:03     ` Alexandre Courbot
  0 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-20  8:03 UTC (permalink / raw)
  To: Philippe Ombredanne
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML

Hi Philippe,

On Tue, Feb 20, 2018 at 4:36 PM, Philippe Ombredanne
<pombredanne@nexb.com> wrote:
> On Tue, Feb 20, 2018 at 5:44 AM, Alexandre Courbot
> <acourbot@chromium.org> wrote:
>> Add a v4l2 request entity data structure that takes care of storing the
>> request-related state of a V4L2 device ; in this case, its controls.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>
> <snip>
>
>> --- /dev/null
>> +++ b/drivers/media/v4l2-core/v4l2-request.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Media requests support for V4L2
>> + *
>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>
> Do you mind using SPDX tags per [1] rather that this fine but long
> legalese. (Here and in the whole patch series)
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/license-rules.rst

I need to check what is the stance of Chromium OS regarding these, but
will gladly comply if possible.

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

* Re: [RFCv4 01/21] media: add request API core and UAPI
  2018-02-20  4:44 ` [RFCv4 01/21] media: add request API core and UAPI Alexandre Courbot
@ 2018-02-20 10:36   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 10:36 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel

On 02/20/18 05:44, Alexandre Courbot wrote:
> The request API provides a way to group buffers and device parameters
> into units of work to be queued and executed. This patch introduces the
> UAPI and core framework.
> 
> This patch is based on the previous work by Laurent Pinchart. The core
> has changed considerably, but the UAPI is mostly untouched.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  drivers/media/Kconfig              |   3 +
>  drivers/media/Makefile             |   6 +
>  drivers/media/media-request.c      | 341 ++++++++++++++++++++++++++++
>  include/media/media-request.h      | 349 +++++++++++++++++++++++++++++
>  include/uapi/linux/media-request.h |  37 +++
>  5 files changed, 736 insertions(+)
>  create mode 100644 drivers/media/media-request.c
>  create mode 100644 include/media/media-request.h
>  create mode 100644 include/uapi/linux/media-request.h
> 
> diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
> index 145e12bfb819..db30fc9547d2 100644
> --- a/drivers/media/Kconfig
> +++ b/drivers/media/Kconfig
> @@ -130,6 +130,9 @@ config VIDEO_V4L2_SUBDEV_API
>  
>  	  This API is mostly used by camera interfaces in embedded platforms.
>  
> +config MEDIA_REQUEST_API
> +	tristate
> +
>  source "drivers/media/v4l2-core/Kconfig"
>  
>  #
> diff --git a/drivers/media/Makefile b/drivers/media/Makefile
> index 594b462ddf0e..03c0a39ad344 100644
> --- a/drivers/media/Makefile
> +++ b/drivers/media/Makefile
> @@ -5,6 +5,12 @@
>  
>  media-objs	:= media-device.o media-devnode.o media-entity.o
>  
> +#
> +# Request API support comes as its own module since it can be used by
> +# both media and video devices
> +#
> +obj-$(CONFIG_MEDIA_REQUEST_API) += media-request.o
> +
>  #
>  # I2C drivers should come before other drivers, otherwise they'll fail
>  # when compiled as builtin drivers
> diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
> new file mode 100644
> index 000000000000..b88362028561
> --- /dev/null
> +++ b/drivers/media/media-request.c
> @@ -0,0 +1,341 @@
> +/*
> + * Request base implementation
> + *
> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/anon_inodes.h>
> +#include <linux/fs.h>
> +#include <linux/file.h>
> +#include <linux/list.h>
> +#include <linux/device.h>
> +#include <linux/media-request.h>
> +#include <linux/module.h>
> +#include <linux/poll.h>
> +#include <linux/slab.h>
> +
> +#include <media/media-request.h>
> +
> +const struct file_operations request_fops;
> +
> +static const char * const media_request_states[] __maybe_unused = {

Why 'maybe_unused'?

> +	"IDLE",
> +	"SUBMITTED",
> +	"COMPLETED",
> +	"INVALID",

I don't like to yell. I prefer "Idle", "Submitted", etc.

> +};
> +
> +struct media_request *media_request_get(struct media_request *req)
> +{
> +	get_file(req->file);
> +	return req;
> +}
> +EXPORT_SYMBOL_GPL(media_request_get);
> +
> +struct media_request *media_request_get_from_fd(int fd)
> +{
> +	struct file *f;
> +
> +	f = fget(fd);
> +	if (!f)
> +		return NULL;
> +
> +	/* Not a request FD? */
> +	if (f->f_op != &request_fops) {
> +		fput(f);
> +		return NULL;
> +	}
> +
> +	return f->private_data;
> +}
> +EXPORT_SYMBOL_GPL(media_request_get_from_fd);
> +
> +void media_request_put(struct media_request *req)
> +{
> +	if (WARN_ON(req == NULL))
> +		return;
> +
> +	fput(req->file);
> +}
> +EXPORT_SYMBOL_GPL(media_request_put);
> +
> +struct media_request_entity_data *
> +media_request_get_entity_data(struct media_request *req,
> +			      struct media_request_entity *entity)
> +{
> +	struct media_request_entity_data *data;
> +
> +	/* First check that this entity is valid for this request at all */
> +	if (!req->mgr->ops->entity_valid(req, entity))
> +		return ERR_PTR(-EINVAL);
> +
> +	mutex_lock(&req->lock);
> +
> +	/* Lookup whether we already have entity data */
> +	list_for_each_entry(data, &req->data, list) {
> +		if (data->entity == entity)
> +			goto out;
> +	}
> +
> +	/* No entity data found, let's create it */
> +	data = entity->ops->data_alloc(req, entity);
> +	if (IS_ERR(data))
> +		goto out;
> +
> +	data->entity = entity;
> +	list_add_tail(&data->list, &req->data);
> +
> +out:
> +	mutex_unlock(&req->lock);
> +
> +	return data;
> +}
> +EXPORT_SYMBOL_GPL(media_request_get_entity_data);
> +
> +static unsigned int media_request_poll(struct file *file, poll_table *wait)
> +{
> +	struct media_request *req = file->private_data;
> +
> +	poll_wait(file, &req->complete_wait, wait);
> +
> +	if (req->state == MEDIA_REQUEST_STATE_COMPLETED)
> +		return POLLIN | POLLRDNORM;
> +
> +	return 0;
> +}
> +
> +static int media_request_release(struct inode *inode, struct file *filp)
> +{
> +	struct media_request *req = filp->private_data;
> +
> +	if (req == NULL)
> +		return 0;
> +
> +	req->mgr->ops->release(req);
> +	return 0;
> +}
> +
> +static long media_request_ioctl_submit(struct media_request *req)
> +{
> +	mutex_lock(&req->lock);
> +
> +	if (req->state != MEDIA_REQUEST_STATE_IDLE) {
> +		dev_warn(req->mgr->dev, "cannot submit request in state %s\n",
> +			 media_request_states[req->state]);
> +		mutex_unlock(&req->lock);
> +		return -EINVAL;
> +	}
> +
> +	req->state = MEDIA_REQUEST_STATE_SUBMITTED;
> +
> +	/*
> +	 * Nothing can change our state when we are submitted - no need to keep
> +	 * holding that lock.
> +	 */
> +	mutex_unlock(&req->lock);
> +
> +	/* Keep a reference to the request until it is completed */
> +	media_request_get(req);
> +
> +	return req->mgr->ops->submit(req);

What happens if submit() returns an error? I would expect that the state goes
back to IDLE and the reference is put().

> +}
> +
> +static long media_request_ioctl_reinit(struct media_request *req)
> +{
> +	struct media_request_entity_data *data, *next;
> +        LIST_HEAD(to_delete);

Weird indentation.

> +
> +	mutex_lock(&req->lock);
> +
> +	if (req->state == MEDIA_REQUEST_STATE_SUBMITTED) {
> +		dev_warn(req->mgr->dev,
> +			"%s: unable to reinit submitted request\n", __func__);
> +		mutex_unlock(&req->lock);
> +		return -EINVAL;
> +	}
> +
> +	/* delete all entity data */
> +	list_for_each_entry_safe(data, next, &req->data, list) {
> +		list_del(&data->list);
> +                list_add(&data->list, &to_delete);

Strange indentation.

You can also use list_move(&data->list, &to_delete).

> +	}
> +
> +	/* reinitialize request to idle state */
> +	req->state = MEDIA_REQUEST_STATE_IDLE;
> +
> +	mutex_unlock(&req->lock);
> +
> +        list_for_each_entry_safe(data, next, &to_delete, list)

Again strange indentation. Not sure what's going on with that.
I'll ignore it going forward.

> +		data->entity->ops->data_free(data);
> +
> +	return 0;
> +}
> +
> +#define MEDIA_REQUEST_IOC(__cmd, func)					\
> +	[_IOC_NR(MEDIA_REQUEST_IOC_##__cmd) - 0x80] = {			\
> +		.cmd = MEDIA_REQUEST_IOC_##__cmd,			\
> +		.fn = func,						\
> +	}
> +
> +struct media_request_ioctl_info {
> +	unsigned int cmd;
> +	long (*fn)(struct media_request *req);
> +};
> +
> +static const struct media_request_ioctl_info ioctl_info[] = {
> +	MEDIA_REQUEST_IOC(SUBMIT, media_request_ioctl_submit),
> +	MEDIA_REQUEST_IOC(REINIT, media_request_ioctl_reinit),

There are only two ioctls, so there is really no need for the
MEDIA_REQUEST_IOC define. Just keep it simple.

> +};
> +
> +static long media_request_ioctl(struct file *filp, unsigned int cmd,
> +				unsigned long __arg)
> +{
> +	struct media_request *req = filp->private_data;
> +	const struct media_request_ioctl_info *info;
> +
> +	if ((_IOC_NR(cmd) < 0x80) ||

Why start the ioctl number at 0x80? Why not just 0?
It avoids all this hassle with the 0x80 offset.

> +	     _IOC_NR(cmd) >= 0x80 + ARRAY_SIZE(ioctl_info) ||
> +	     ioctl_info[_IOC_NR(cmd) - 0x80].cmd != cmd)
> +		return -ENOIOCTLCMD;
> +
> +	info = &ioctl_info[_IOC_NR(cmd) - 0x80];
> +
> +	return info->fn(req);
> +}
> +
> +const struct file_operations request_fops = {
> +	.owner = THIS_MODULE,
> +	.poll = media_request_poll,
> +	.release = media_request_release,
> +	.unlocked_ioctl = media_request_ioctl,
> +};
> +
> +static void media_request_complete(struct media_request *req)
> +{
> +	struct device *dev = req->mgr->dev;
> +
> +	mutex_lock(&req->lock);
> +
> +	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_SUBMITTED)) {
> +		dev_warn(dev, "can't complete request in state %s\n",
> +			media_request_states[req->state]);
> +		mutex_unlock(&req->lock);
> +		return;
> +	}
> +
> +	req->state = MEDIA_REQUEST_STATE_COMPLETED;
> +
> +	wake_up_interruptible(&req->complete_wait);
> +
> +	mutex_unlock(&req->lock);
> +
> +	/* Release the reference acquired when we submitted the request */
> +	media_request_put(req);
> +}
> +
> +void media_request_entity_complete(struct media_request *req,
> +				   struct media_request_entity *completed)
> +{
> +	struct media_request_entity_data *data;
> +	int cpt = 0;
> +
> +	list_for_each_entry(data, &req->data, list) {
> +		if (data->entity == completed)
> +			data->completed = true;
> +		if (!data->completed)

This can be 'else if'.

> +			++cpt;
> +	}
> +
> +	if (cpt == 0)
> +		media_request_complete(req);
> +}
> +EXPORT_SYMBOL_GPL(media_request_entity_complete);
> +
> +long media_request_ioctl_new(struct media_request_mgr *mgr,
> +			     struct media_request_new *new)
> +{
> +	struct media_request *req;
> +	int err;
> +	int fd;
> +
> +	/* User only wants to check the availability of requests? */
> +	if (new->flags & MEDIA_REQUEST_FLAG_TEST)
> +		return 0;
> +
> +	fd = get_unused_fd_flags(O_CLOEXEC);
> +	if (fd < 0)
> +		return fd;
> +
> +	req = mgr->ops->alloc(mgr);
> +	if (IS_ERR(req)) {
> +		err = PTR_ERR(req);
> +		goto out_fd;
> +	}
> +
> +	req->file = anon_inode_getfile("request", &request_fops, req,
> +				       O_CLOEXEC);
> +	if (IS_ERR(req->file)) {
> +		err = PTR_ERR(req->file);
> +		mgr->ops->release(req);
> +		goto out_fd;
> +	}
> +
> +	fd_install(fd, req->file);
> +	new->fd = fd;
> +
> +	return 0;
> +
> +out_fd:
> +	put_unused_fd(fd);
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(media_request_ioctl_new);
> +
> +void media_request_entity_init(struct media_request_entity *entity,
> +			       enum media_request_entity_type type,
> +			       const struct media_request_entity_ops *ops)
> +{
> +	entity->type = type;
> +	entity->ops = ops;
> +}
> +EXPORT_SYMBOL_GPL(media_request_entity_init);
> +
> +void media_request_mgr_init(struct media_request_mgr *mgr, struct device *dev,
> +			    const struct media_request_ops *ops)
> +{
> +	mgr->dev = dev;
> +	mutex_init(&mgr->mutex);
> +	INIT_LIST_HEAD(&mgr->requests);
> +	mgr->ops = ops;
> +}
> +EXPORT_SYMBOL_GPL(media_request_mgr_init);
> +
> +void media_request_mgr_free(struct media_request_mgr *mgr)
> +{
> +	struct device *dev = mgr->dev;
> +
> +	/* Just a sanity check - we should have no remaining requests */
> +	while (!list_empty(&mgr->requests)) {
> +		struct media_request *req;
> +
> +		req = list_first_entry(&mgr->requests, typeof(*req), list);
> +		dev_warn(dev,
> +			"%s: request still referenced, deleting forcibly!\n",
> +			__func__);
> +		mgr->ops->release(req);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(media_request_mgr_free);
> +
> +MODULE_AUTHOR("Alexandre Courbot <acourbot@chromium.org>");
> +MODULE_DESCRIPTION("Core support for media request API");
> +MODULE_LICENSE("GPL");
> diff --git a/include/media/media-request.h b/include/media/media-request.h
> new file mode 100644
> index 000000000000..110dcdc1099f
> --- /dev/null
> +++ b/include/media/media-request.h
> @@ -0,0 +1,349 @@
> +/*
> + * Media requests.
> + *
> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _MEDIA_REQUEST_H
> +#define _MEDIA_REQUEST_H
> +
> +struct media_request;
> +struct media_request_entity;
> +struct media_request_entity_data;
> +struct media_request_mgr;
> +struct media_request_new;
> +
> +#include <linux/kconfig.h>
> +
> +enum media_request_state {
> +	MEDIA_REQUEST_STATE_IDLE,
> +	MEDIA_REQUEST_STATE_SUBMITTED,
> +	MEDIA_REQUEST_STATE_COMPLETED,
> +	MEDIA_REQUEST_STATE_INVALID,
> +};
> +
> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
> +
> +#include <linux/kref.h>
> +#include <linux/list.h>
> +#include <linux/notifier.h>
> +#include <linux/wait.h>
> +
> +/**
> + * struct media_request_entity_ops - request entity operations
> + *
> + * @data_alloc:	allocate memory to store that entity's relevant state
> + * @data_free:	free state previously allocated with data_alloc
> + * @submit:	perform all required actions to be ready to process that request
> + */
> +struct media_request_entity_ops {
> +	struct media_request_entity_data *
> +		(*data_alloc)(struct media_request *req,
> +			      struct media_request_entity *entity);
> +	void (*data_free)(struct media_request_entity_data *data);
> +	int (*submit)(struct media_request *req,
> +		      struct media_request_entity_data *data);
> +};
> +
> +/**
> + * enum media_request_entity_type - describe type of an entity
> + *
> + * This type lets us know the upper kind of a struct media_request_entity
> + * instance.
> + *
> + * @MEDIA_REQUEST_ENTITY_TYPE_V4L2:	instance can be upcasted to
> + * 					v4l2_request_entity
> + * @MEDIA_REQUEST_ENTITY_TYPE_MC:	instance can be updated to
> + * 					mc_request_entity
> + *
> + */
> +enum media_request_entity_type {
> +	MEDIA_REQUEST_ENTITY_TYPE_V4L2,
> +	MEDIA_REQUEST_ENTITY_TYPE_MC,
> +};
> +
> +/**
> + * struct media_request_entity - request entity base structure
> + *
> + * @type:	type of entity, indicating which upcast is safe to perform
> + * @ops:	operations that this entity can perform
> + *
> + * This structure is supposed to be embedded into a larger structure
> + * better representing the specifics of the instance (e.g. v4l2_request_entity
> + * for controlling V4L2 devices).
> + *
> + */
> +struct media_request_entity {
> +	enum media_request_entity_type type;
> +	const struct media_request_entity_ops *ops;
> +};
> +
> +/**
> + * media_request_entity_init() - initialize a request entity's base properties
> + *
> + * @entity:	entity to initialize
> + * @type:	type of this entity
> + * @ops:	operations that this entity will perform
> + */
> +void media_request_entity_init(struct media_request_entity *entity,
> +			       enum media_request_entity_type type,
> +			       const struct media_request_entity_ops *ops);
> +
> +/**
> + * struct media_request_entity_data - per-entity request data
> + *
> + * @request:	request instance this data belongs to
> + * @entity:	entity that stores data here
> + * @list:	entry in media_request::data
> + * @completed:	whether this entity has completed its part of the request
> + *
> + * Base structure used to store request state data. To be extended by actual
> + * implementation.
> + *
> + */
> +struct media_request_entity_data {
> +	struct media_request *request;
> +	struct media_request_entity *entity;
> +	struct list_head list;
> +	bool completed;
> +};
> +
> +/**
> + * struct media_request - Media request base structure
> + *
> + * @mgr:	manager this request belongs to
> + * @file:	used to export FDs to user-space and reference count
> + * @list:	entry in the media_request_mgr::requests list
> + * @lock:	protects following members against concurrent accesses
> + * @state:	current state of the request
> + * @data:	per-entity data list
> + * @complete_wait:	wait queue that signals once the request has completed
> + */
> +struct media_request {
> +	struct media_request_mgr *mgr;
> +	struct file *file;
> +	struct list_head list;
> +
> +	struct mutex lock;
> +	enum media_request_state state;
> +	struct list_head data;
> +	wait_queue_head_t complete_wait;
> +};
> +
> +/**
> + * media_request_get() - increment the reference counter of a request
> + *
> + * The calling context must call media_request_put() once it does not need
> + * the reference to the request anymore.
> + *
> + * Returns the request that has been passed as argument.
> + *
> + * @req:	request to acquire a reference of
> + */
> +struct media_request *media_request_get(struct media_request *req);
> +
> +/**
> + * media_request_get_from_fd() - lookup request by fd and acquire a reference.
> + *
> + * Look a request up from its fd, acquire a reference and return a pointer to
> + * the request. As for media_request_get(), media_request_put() must be called
> + * once the reference is not used anymore.
> + *
> + * @req:	request to lookup and acquire.
> + *
> + */
> +struct media_request *media_request_get_from_fd(int fd);
> +
> +/**
> + * media_request_put() - decrement the reference counter of a request
> + *
> + * Mirror function of media_request_get() and media_request_get_from_fd(). Will
> + * free the request if this was the last valid reference.
> + *
> + * @req:	request to release.
> + */
> +void media_request_put(struct media_request *req);
> +
> +/**
> + * media_request_lock() - prevent concurrent access to that request
> + *
> + * @req:	request to lock
> + */
> +static inline void media_request_lock(struct media_request *req)
> +{
> +	mutex_lock(&req->lock);
> +}
> +
> +/**
> + * media_request_unlock() - release previously acquired request lock
> + *
> + * @req:	request to release
> + */
> +static inline void media_request_unlock(struct media_request *req)
> +{
> +	mutex_unlock(&req->lock);
> +}
> +
> +/**
> + * media_request_get_state() - get the state of a request
> + *
> + * @req:	request which state we are interested in
> + *
> + * The request lock should always be acquired when confirming this value
> + * to avoid race conditions.
> + *
> + */
> +static inline enum media_request_state
> +media_request_get_state(struct media_request *req)
> +{
> +	return req->state;
> +}
> +
> +/**
> + * media_request_get_entity_data() - get per-entity data for a request
> + * @req:	request to get entity data from
> + * @entity:	entity to get data of
> + *
> + * Search and return the entity data associated associated to the request. If no
> + * such data exists, it is allocated as per the entity operations.
> + *
> + * Returns the per-entity data, or an error code if a problem happened. -EINVAL
> + * means that data for the entity already existed, but has been allocated under
> + * a different cookie.
> + */
> +struct media_request_entity_data *
> +media_request_get_entity_data(struct media_request *req,
> +			      struct media_request_entity *entity);
> +
> +/**
> + * media_request_entity_complete() - to be invoked when an entity completes its
> + *				     part of the request
> + *
> + * @req:	request which has completed
> + * @completed:	entity that has completed
> + */
> +void media_request_entity_complete(struct media_request *req,
> +				   struct media_request_entity *completed);
> +
> +/**
> + * media_request_ioctl_new() - process a NEW_REQUEST ioctl
> + *
> + * @mgr:	request manager from which to allocate the request
> + * @new:	media_request_new structure to be passed back to user-space
> + *
> + * This function is a helper to be called by actual handlers of *_NEW_REQUEST
> + * ioctls.
> + */
> +long media_request_ioctl_new(struct media_request_mgr *mgr,
> +			     struct media_request_new *new);
> +
> +/**
> + * struct media_request_ops - request operations
> + *
> + * @alloc:	allocate a request
> + * @release:	free a previously allocated request
> + * @entity_valid:	returns whether a given entity is valid for that request
> + * @submit:	allow the request to be processed
> + *
> + * This structure allows to specialize requests to a specific scope. For
> + * instance, requests obtained from a V4L2 device node should only be able to
> + * control that device. On the other hand, requests created from a media
> + * controller node will be able to control all the devices managed by this
> + * controller, and may want to implement some form of synchronization between
> + * them.
> + */
> +struct media_request_ops {
> +	struct media_request *(*alloc)(struct media_request_mgr *mgr);
> +	void (*release)(struct media_request *req);
> +	bool (*entity_valid)(const struct media_request *req,
> +			     const struct media_request_entity *entity);
> +	int (*submit)(struct media_request *req);
> +};
> +
> +/**
> + * struct media_request_mgr - requests manager
> + *
> + * @dev:	device owning this manager
> + * @ops:	implementation of the manager
> + * @mutex:	protects the requests list_head
> + * @requests:	list of alive requests produced by this manager
> + *
> + * This structure is mainly responsible for allocating requests. Although it is
> + * not strictly required for that purpose, having it allows us to account for
> + * all requests created by a given device, and to make sure they are all
> + * discarded by the time the device is destroyed.
> + */
> +struct media_request_mgr {
> +	struct device *dev;
> +	const struct media_request_ops *ops;
> +
> +	struct mutex mutex;
> +	struct list_head requests;
> +};
> +
> +/**
> + * media_request_mgr_init() - initialize a request manager.
> + *
> + * @mgr:	manager to initialize
> + */
> +void media_request_mgr_init(struct media_request_mgr *mgr, struct device *dev,
> +			    const struct media_request_ops *ops);
> +
> +/**
> + * media_request_mgr_free() - free a media manager
> + *
> + * This should only be called when all requests produced by this manager
> + * has been destroyed. Will warn if that is not the case.
> + */
> +void media_request_mgr_free(struct media_request_mgr *mgr);
> +
> +#else /* CONFIG_MEDIA_REQUEST_API */
> +
> +static inline void media_request_entity_complete(struct media_request *req,
> +					 struct media_request_entity *completed)
> +{
> +}
> +
> +static inline struct media_request_entity_data *
> +media_request_get_entity_data(struct media_request *req,
> +			      struct media_request_entity *entity)
> +{
> +	return ERR_PTR(-ENOTSUPP);
> +}
> +
> +static inline long media_request_ioctl_new(struct media_request_mgr *mgr,
> +					   struct media_request_new *new)
> +{
> +	return -ENOTTY;
> +}
> +
> +static inline void media_request_put(struct media_request *req)
> +{
> +}
> +
> +static inline void media_request_lock(struct media_request *req)
> +{
> +}
> +
> +static inline void media_request_unlock(struct media_request *req)
> +{
> +}
> +
> +static inline enum media_request_state
> +media_request_get_state(struct media_request *req)
> +{
> +	return MEDIA_REQUEST_STATE_INVALID;
> +}
> +
> +#endif /* CONFIG_MEDIA_REQUEST_API */
> +
> +#endif
> diff --git a/include/uapi/linux/media-request.h b/include/uapi/linux/media-request.h
> new file mode 100644
> index 000000000000..5d30f731a442
> --- /dev/null
> +++ b/include/uapi/linux/media-request.h
> @@ -0,0 +1,37 @@
> +/*
> + * Media requests UAPI
> + *
> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __LINUX_MEDIA_REQUEST_H
> +#define __LINUX_MEDIA_REQUEST_H
> +
> +#ifndef __KERNEL__
> +#include <stdint.h>
> +#endif
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +#include <linux/version.h>
> +
> +/* Only check that requests can be used, do not allocate */
> +#define MEDIA_REQUEST_FLAG_TEST			0x00000001
> +
> +struct media_request_new {
> +	__u32 flags;
> +	__s32 fd;
> +} __attribute__ ((packed));
> +
> +#define MEDIA_REQUEST_IOC_SUBMIT	  _IO('|',  128)
> +#define MEDIA_REQUEST_IOC_REINIT	  _IO('|',  129)
> +
> +#endif
> 

I need to think a bit more on this internal API, so I might come back
to this patch for more comments.

Regards,

	Hans

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

* Re: [RFCv4 08/21] [WAR] v4l2-ctrls: do not clone non-standard controls
  2018-02-20  4:44 ` [RFCv4 08/21] [WAR] v4l2-ctrls: do not clone non-standard controls Alexandre Courbot
@ 2018-02-20 13:05   ` Hans Verkuil
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 13:05 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel

On 02/20/18 05:44, Alexandre Courbot wrote:
> Only standard controls can be successfully cloned: handler_new_ref, used
> by v4l2_ctrl_request_clone(), forcibly calls v4l2_ctrl_new_std() which
> fails to find custom controls names, and we eventually hit the condition
> that name == NULL in v4l2_ctrl_new().

Hmm, the core reason is that handler_new_ref tries to automatically create
a new control class if it didn't exist yet. Which is OK for standard control
classes but not for non-standard control classes such as is used in vivid.

I will have to think about this.

Regards,

	Hans

> 
> This prevents us from using non-standard controls with requests, but
> that is enough for testing purposes.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index 166647817efb..7a81aa5959c3 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -2772,6 +2772,11 @@ int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
>  		if (filter && !filter(ctrl))
>  			continue;
>  		err = handler_new_ref(hdl, ctrl, &new_ref, false);
> +		if (err) {
> +			printk("%s: handler_new_ref on control %x (%s) returned %d\n", __func__, ctrl->id, ctrl->name, err);
> +			err = 0;
> +			continue;
> +		}
>  		if (err)
>  			break;
>  		if (from->is_request)
> 

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

* Re: [RFCv4 09/21] v4l2: add request API support
  2018-02-20  4:44 ` [RFCv4 09/21] v4l2: add request API support Alexandre Courbot
  2018-02-20  7:36   ` Philippe Ombredanne
@ 2018-02-20 13:25   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
  1 sibling, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 13:25 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel

On 02/20/18 05:44, Alexandre Courbot wrote:
> Add a v4l2 request entity data structure that takes care of storing the
> request-related state of a V4L2 device ; in this case, its controls.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  drivers/media/v4l2-core/Makefile       |   1 +
>  drivers/media/v4l2-core/v4l2-request.c | 178 +++++++++++++++++++++++++
>  include/media/v4l2-request.h           | 159 ++++++++++++++++++++++
>  3 files changed, 338 insertions(+)
>  create mode 100644 drivers/media/v4l2-core/v4l2-request.c
>  create mode 100644 include/media/v4l2-request.h
> 
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
> index 80de2cb9c476..13d0477535bd 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -16,6 +16,7 @@ ifeq ($(CONFIG_TRACEPOINTS),y)
>    videodev-objs += vb2-trace.o v4l2-trace.o
>  endif
>  videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
> +videodev-$(CONFIG_MEDIA_REQUEST_API) += v4l2-request.o
>  
>  obj-$(CONFIG_VIDEO_V4L2) += videodev.o
>  obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
> diff --git a/drivers/media/v4l2-core/v4l2-request.c b/drivers/media/v4l2-core/v4l2-request.c
> new file mode 100644
> index 000000000000..e8ad10e2f525
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-request.c
> @@ -0,0 +1,178 @@
> +/*
> + * Media requests support for V4L2
> + *
> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/slab.h>
> +
> +#include <media/v4l2-dev.h>
> +#include <media/v4l2-request.h>
> +#include <media/videobuf2-v4l2.h>
> +
> +void v4l2_request_entity_init(struct v4l2_request_entity *entity,
> +			      const struct media_request_entity_ops *ops,
> +			      struct video_device *vdev)
> +{
> +	media_request_entity_init(&entity->base, MEDIA_REQUEST_ENTITY_TYPE_V4L2, ops);
> +	entity->vdev = vdev;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_request_entity_init);
> +
> +struct media_request_entity_data *
> +v4l2_request_entity_data_alloc(struct media_request *req,
> +			       struct v4l2_ctrl_handler *hdl)
> +{
> +	struct v4l2_request_entity_data *data;
> +	int ret;
> +
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = v4l2_ctrl_request_init(&data->ctrls);
> +	if (ret) {
> +		kfree(data);
> +		return ERR_PTR(ret);
> +	}
> +	ret = v4l2_ctrl_request_clone(&data->ctrls, hdl, NULL);
> +	if (ret) {
> +		kfree(data);
> +		return ERR_PTR(ret);
> +	}
> +
> +	INIT_LIST_HEAD(&data->queued_buffers);
> +
> +	return &data->base;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_request_entity_data_alloc);
> +
> +void v4l2_request_entity_data_free(struct media_request_entity_data *_data)
> +{
> +	struct v4l2_request_entity_data *data;
> +	struct v4l2_vb2_request_buffer *qb, *n;
> +
> +	data = to_v4l2_entity_data(_data);
> +
> +	list_for_each_entry_safe(qb, n, &data->queued_buffers, node) {
> +		struct vb2_buffer *buf;
> +		dev_warn(_data->request->mgr->dev,
> +			 "entity data freed while buffer still queued!\n");
> +
> +		/* give buffer back to user-space */
> +		buf = qb->queue->bufs[qb->v4l2_buf.index];
> +		buf->state = qb->pre_req_state;
> +		buf->request = NULL;
> +
> +		kfree(qb);
> +	}
> +
> +	v4l2_ctrl_handler_free(&data->ctrls);
> +	kfree(data);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_request_entity_data_free);
> +
> +
> +
> +
> +
> +static struct media_request *v4l2_request_alloc(struct media_request_mgr *mgr)
> +{
> +	struct media_request *req;
> +
> +	req = kzalloc(sizeof(*req), GFP_KERNEL);
> +	if (!req)
> +		return ERR_PTR(-ENOMEM);
> +
> +	req->mgr = mgr;
> +	req->state = MEDIA_REQUEST_STATE_IDLE;
> +	INIT_LIST_HEAD(&req->data);
> +	init_waitqueue_head(&req->complete_wait);
> +	mutex_init(&req->lock);
> +
> +	mutex_lock(&mgr->mutex);
> +	list_add_tail(&req->list, &mgr->requests);
> +	mutex_unlock(&mgr->mutex);
> +
> +	return req;
> +}
> +
> +static void v4l2_request_free(struct media_request *req)
> +{
> +	struct media_request_mgr *mgr = req->mgr;
> +	struct media_request_entity_data *data, *next;
> +
> +	mutex_lock(&mgr->mutex);
> +	list_del(&req->list);
> +	mutex_unlock(&mgr->mutex);
> +
> +	list_for_each_entry_safe(data, next, &req->data, list) {
> +		list_del(&data->list);
> +		data->entity->ops->data_free(data);
> +	}
> +
> +	kfree(req);
> +}
> +
> +static bool v4l2_entity_valid(const struct media_request *req,
> +			      const struct media_request_entity *_entity)
> +{
> +	const struct v4l2_request_mgr *mgr;
> +	const struct v4l2_request_entity *entity;
> +
> +	if (_entity->type != MEDIA_REQUEST_ENTITY_TYPE_V4L2)
> +		return false;
> +
> +	entity = container_of(_entity, struct v4l2_request_entity, base);
> +	mgr = container_of(req->mgr, struct v4l2_request_mgr, base);
> +
> +	/* Entity is valid if it is the video device that created the manager */
> +	return entity->vdev == mgr->vdev;
> +}
> +
> +static int v4l2_request_submit(struct media_request *req)
> +{
> +	struct media_request_entity_data *data;
> +
> +        /* Submit for each entity */
> +	list_for_each_entry(data, &req->data, list) {
> +		int ret = data->entity->ops->submit(req, data);
> +		/* TODO proper error handling, abort on other entities? */
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +const struct media_request_ops v4l2_request_ops = {
> +	.alloc = v4l2_request_alloc,
> +	.release = v4l2_request_free,
> +	.entity_valid = v4l2_entity_valid,
> +	.submit = v4l2_request_submit,
> +};
> +EXPORT_SYMBOL_GPL(v4l2_request_ops);
> +
> +void v4l2_request_mgr_init(struct v4l2_request_mgr *mgr,
> +			  struct video_device *vdev,
> +			  const struct media_request_ops *ops)
> +{
> +	media_request_mgr_init(&mgr->base, &vdev->dev, ops);
> +	mgr->vdev = vdev;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_request_mgr_init);
> +
> +void v4l2_request_mgr_free(struct v4l2_request_mgr* mgr)
> +{
> +	media_request_mgr_free(&mgr->base);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_request_mgr_free);
> diff --git a/include/media/v4l2-request.h b/include/media/v4l2-request.h
> new file mode 100644
> index 000000000000..8a87ca455b74
> --- /dev/null
> +++ b/include/media/v4l2-request.h
> @@ -0,0 +1,159 @@
> +/*
> + * Media requests support for V4L2
> + *
> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef _MEDIA_V4L2_REQUEST_H
> +#define _MEDIA_V4L2_REQUEST_H
> +
> +#include <linux/kconfig.h>
> +#include <media/media-request.h>
> +
> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
> +
> +#include <linux/list.h>
> +
> +#include <media/videobuf2-core.h>
> +#include <media/v4l2-ctrls.h>
> +
> +/**
> + * struct v4l2_request_entity - entity used with V4L2 instances
> + *
> + * @base:	base media_request_entity struct
> + * @vdev:	video device that this entity represents
> + *
> + * This structure is used by V4L2 devices that support being controlled
> + * by requests. If should be added to the device-specific structure that the

If -> It

> + * driver wishes to control using requests.
> + *
> + * V4L2 request entities are able to receive queued buffers using vb2 queues,
> + * and control settings using the control framework.
> + *
> + */
> +struct v4l2_request_entity {
> +	struct media_request_entity base;
> +	struct video_device *vdev;
> +};
> +#define to_v4l2_entity(e) container_of(e, struct v4l2_request_entity, base)
> +
> +/**
> + * v4l2_request_entity_init() - initialize a struct v4l2_request_entity
> + *
> + * @entity:	entity to initialize
> + * @ops:	entity ops to use
> + * @vdev:	video device represented by this entity
> + */
> +void v4l2_request_entity_init(struct v4l2_request_entity *entity,
> +			      const struct media_request_entity_ops *ops,
> +			      struct video_device *vdev);
> +
> +/**
> + * struct v4l2_vb2_request_buffer - record buffer queue on behalf of a request
> + *
> + * @queue:		vb2 queue
> + * @pre_req_state:	keep track of the pre-QBUF state of the buffer
> + * @v4l2_buf:		user-space buffer queue ioctl data
> + * @node:		entry into v4l2_request_entity_data::queued_buffers
> + */
> +struct v4l2_vb2_request_buffer {
> +	struct vb2_queue *queue;
> +	enum vb2_buffer_state pre_req_state;
> +	struct v4l2_buffer v4l2_buf;
> +	struct list_head node;
> +};
> +
> +/**
> + * struct v4l2_request_entity_data - per-request data for V4L2 entities
> + *
> + * @base:		base entity data structure
> + * @ctrls:		record of controls set for this request
> + * @queued_buffers:	record of buffers queued for this request
> + */
> +struct v4l2_request_entity_data {
> +	struct media_request_entity_data base;
> +	struct v4l2_ctrl_handler ctrls;

Please call this field either 'hdl' or 'ctrl_handler'. 'ctrls' is very
confusing. That way I know it represents a control handler and not a
list or array of controls.

> +	struct list_head queued_buffers;
> +};
> +static inline struct v4l2_request_entity_data *
> +to_v4l2_entity_data(struct media_request_entity_data *data)
> +{
> +	if (IS_ERR(data))
> +		return (struct v4l2_request_entity_data *)data;
> +
> +	return container_of(data, struct v4l2_request_entity_data, base);
> +}
> +
> +/**
> + * v4l2_request_entity_data_alloc() - allocate data for a V4L2 entity
> + *
> + * @req:	request to allocate for
> + * @hdl:	control handler of the device we will be controlling
> + *
> + * Helper function to be used from the media_request_entity_ops::data_alloc
> + * hook.
> + */
> +struct media_request_entity_data *
> +v4l2_request_entity_data_alloc(struct media_request *req,
> +			       struct v4l2_ctrl_handler *hdl);
> +
> +/**
> + * v4l2_request_entity_data_free() - free per-request data of an entity
> + *
> + * @data:	entity data to free
> + *
> + * Helper function to be usedfrom the media_request_entity_ops::data_free
> + * hook.
> + */
> +void
> +v4l2_request_entity_data_free(struct media_request_entity_data *_data);
> +
> +
> +
> +
> +
> +/**
> + * struct v4l2_request_mgr - request manager producing requests suitable
> + *			     for managing single v4l2 devices.
> + *
> + * @base:	base manager structure
> + * @vdev:	device that our requests can control
> + */
> +struct v4l2_request_mgr {
> +	struct media_request_mgr base;
> +	struct video_device *vdev;
> +};
> +
> +/**
> + * v4l2_request_mgr_init() - initialize a v4l2_request_mgr
> + *
> + * @mgr:	manager to initialize
> + * @vdev:	video device that our instances will control
> + * @ops:	used to override ops if needed. &v4l2_request_ops is a good
> + *		default
> + */
> +void v4l2_request_mgr_init(struct v4l2_request_mgr *mgr,
> +			  struct video_device *vdev,
> +			  const struct media_request_ops *ops);
> +
> +/**
> + * v4l2_request_mgr_free() - free a v4l2 request manager
> + *
> + * @mgr:	manager to free
> + */
> +void v4l2_request_mgr_free(struct v4l2_request_mgr *mgr);
> +
> +extern const struct media_request_ops v4l2_request_ops;
> +
> +#endif /* CONFIG_MEDIA_REQUEST_API */
> +
> +#endif
> 

I'm not convinced by some of the naming, but I'll get back to that later.

Also very unclear is which objects here are refcounted and which have to
be manually freed. My control handler patch series adds a kref to struct
v4l2_ctrl_handler, but that isn't used AFAICT.

I will probably come back to this as well.

Regards,

	Hans

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

* Re: [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer
  2018-02-20  4:44 ` [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer Alexandre Courbot
@ 2018-02-20 15:20   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 15:20 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Hans Verkuil

On 02/20/18 05:44, Alexandre Courbot wrote:
> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> When queuing buffers allow for passing the request that should
> be associated with this buffer.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> [acourbot@chromium.org: make request ID 32-bit]
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 +-
>  drivers/media/usb/cpia2/cpia2_v4l.c             | 2 +-
>  drivers/media/v4l2-core/v4l2-compat-ioctl32.c   | 9 ++++++---
>  drivers/media/v4l2-core/v4l2-ioctl.c            | 4 ++--
>  include/uapi/linux/videodev2.h                  | 3 ++-
>  5 files changed, 12 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> index 886a2d8d5c6c..6d4d184aa68e 100644
> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> @@ -203,7 +203,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
>  	b->timestamp = ns_to_timeval(vb->timestamp);
>  	b->timecode = vbuf->timecode;
>  	b->sequence = vbuf->sequence;
> -	b->reserved2 = 0;
> +	b->request_fd = 0;
>  	b->reserved = 0;
>  
>  	if (q->is_multiplanar) {
> diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
> index 99f106b13280..af42ce3ceb48 100644
> --- a/drivers/media/usb/cpia2/cpia2_v4l.c
> +++ b/drivers/media/usb/cpia2/cpia2_v4l.c
> @@ -948,7 +948,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
>  	buf->sequence = cam->buffers[buf->index].seq;
>  	buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
>  	buf->length = cam->frame_size;
> -	buf->reserved2 = 0;
> +	buf->request_fd = 0;
>  	buf->reserved = 0;
>  	memset(&buf->timecode, 0, sizeof(buf->timecode));
>  
> diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> index 5198c9eeb348..32bf47489a2e 100644
> --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
> @@ -386,7 +386,7 @@ struct v4l2_buffer32 {
>  		__s32		fd;
>  	} m;
>  	__u32			length;
> -	__u32			reserved2;
> +	__s32			request_fd;
>  	__u32			reserved;
>  };
>  
> @@ -486,6 +486,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
>  {
>  	u32 type;
>  	u32 length;
> +	s32 request_fd;
>  	enum v4l2_memory memory;
>  	struct v4l2_plane32 __user *uplane32;
>  	struct v4l2_plane __user *uplane;
> @@ -500,7 +501,9 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
>  	    get_user(memory, &up->memory) ||
>  	    put_user(memory, &kp->memory) ||
>  	    get_user(length, &up->length) ||
> -	    put_user(length, &kp->length))
> +	    put_user(length, &kp->length) ||
> +	    get_user(request_fd, &up->request_fd) ||
> +	    put_user(request_fd, &kp->request_fd))
>  		return -EFAULT;
>  
>  	if (V4L2_TYPE_IS_OUTPUT(type))
> @@ -604,7 +607,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
>  	    assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
>  	    copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
>  	    assign_in_user(&up->sequence, &kp->sequence) ||
> -	    assign_in_user(&up->reserved2, &kp->reserved2) ||
> +	    assign_in_user(&up->request_fd, &kp->request_fd) ||
>  	    assign_in_user(&up->reserved, &kp->reserved) ||
>  	    get_user(length, &kp->length) ||
>  	    put_user(length, &up->length))
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 260288ca4f55..7bfeaf233d5a 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -437,13 +437,13 @@ static void v4l_print_buffer(const void *arg, bool write_only)
>  	const struct v4l2_plane *plane;
>  	int i;
>  
> -	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s",
> +	pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request_fd=%u, flags=0x%08x, field=%s, sequence=%d, memory=%s",
>  			p->timestamp.tv_sec / 3600,
>  			(int)(p->timestamp.tv_sec / 60) % 60,
>  			(int)(p->timestamp.tv_sec % 60),
>  			(long)p->timestamp.tv_usec,
>  			p->index,
> -			prt_names(p->type, v4l2_type_names),
> +			prt_names(p->type, v4l2_type_names), p->request_fd,
>  			p->flags, prt_names(p->field, v4l2_field_names),
>  			p->sequence, prt_names(p->memory, v4l2_memory_names));
>  
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 982718965180..4fd46ae8fad5 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -909,6 +909,7 @@ struct v4l2_plane {
>   * @length:	size in bytes of the buffer (NOT its payload) for single-plane
>   *		buffers (when type != *_MPLANE); number of elements in the
>   *		planes array for multi-plane buffers
> + * @request_fd: fd of the request that this buffer should use
>   *
>   * Contains data exchanged by application and driver using one of the Streaming
>   * I/O methods.
> @@ -932,7 +933,7 @@ struct v4l2_buffer {
>  		__s32		fd;
>  	} m;
>  	__u32			length;
> -	__u32			reserved2;
> +	__s32			request_fd;

This should be:

	union {
		__s32		request_fd;
		__u32		reserved2;
	};

Otherwise any existing application that sets 'reserved2 = 0;' would fail.
I encountered this issue when compiling v4l-utils.

Regards,

	Hans

>  	__u32			reserved;
>  };
>  
> 

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

* Re: [RFCv4 11/21] media: v4l2_fh: add request entity field
  2018-02-20  4:44 ` [RFCv4 11/21] media: v4l2_fh: add request entity field Alexandre Courbot
@ 2018-02-20 15:24   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 15:24 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel

On 02/20/18 05:44, Alexandre Courbot wrote:
> Allow drivers to assign a request entity to v4l2_fh. This will be useful
> for request-aware ioctls to find out which request entity to use.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  include/media/v4l2-fh.h | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
> index ea73fef8bdc0..f54cb319dd64 100644
> --- a/include/media/v4l2-fh.h
> +++ b/include/media/v4l2-fh.h
> @@ -28,6 +28,7 @@
>  
>  struct video_device;
>  struct v4l2_ctrl_handler;
> +struct media_request_entity;
>  
>  /**
>   * struct v4l2_fh - Describes a V4L2 file handler
> @@ -43,6 +44,7 @@ struct v4l2_ctrl_handler;
>   * @navailable: number of available events at @available list
>   * @sequence: event sequence number
>   * @m2m_ctx: pointer to &struct v4l2_m2m_ctx
> + * @entity: the request entity this fh operates on behalf of
>   */
>  struct v4l2_fh {
>  	struct list_head	list;
> @@ -60,6 +62,7 @@ struct v4l2_fh {
>  #if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
>  	struct v4l2_m2m_ctx	*m2m_ctx;
>  #endif
> +	struct media_request_entity *entity;

The name 'media_request_entity' is very confusing.

In the media controller API terminology an entity represents a piece
of hardware with inputs and outputs (very rough description), but a
request is not an entity. It may be associated with an entity, though.

So calling this field 'entity' is also very misleading.

As with previous patches, I'll have to think about this and try and
come up with better, less confusing names.

Regards,

	Hans

>  };
>  
>  /**
> 

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

* Re: [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-20  4:44 ` [RFCv4 13/21] media: videobuf2-v4l2: " Alexandre Courbot
@ 2018-02-20 16:18   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
  2018-02-23  6:34     ` Tomasz Figa
  2018-03-07 16:50   ` [RFCv4,13/21] " Paul Kocialkowski
  1 sibling, 2 replies; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 16:18 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel

On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
> that request-aware drivers can call to queue a buffer into a request
> instead of directly into the vb2 queue if relevent.
> 
> This function expects that drivers invoking it are using instances of
> v4l2_request_entity and v4l2_request_entity_data to describe their
> entity and entity data respectively.
> 
> Also add the vb2_request_submit() helper function which drivers can
> invoke in order to queue all the buffers previously queued into a
> request into the regular vb2 queue.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>  2 files changed, 187 insertions(+), 1 deletion(-)
> 

<snip>

> @@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
>  int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
>  {
>  	struct video_device *vdev = video_devdata(file);
> +	struct v4l2_fh *fh = NULL;
> +
> +	if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
> +		fh = file->private_data;

No need for this. All drivers using vb2 will also use v4l2_fh.

>  
>  	if (vb2_queue_is_busy(vdev, file))
>  		return -EBUSY;
> -	return vb2_qbuf(vdev->queue, p);
> +	return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
>  }
>  EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
>  
> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
> index 3d5e2d739f05..d4dfa266a0da 100644
> --- a/include/media/videobuf2-v4l2.h
> +++ b/include/media/videobuf2-v4l2.h
> @@ -23,6 +23,12 @@
>  #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
>  #endif
>  
> +struct media_entity;
> +struct v4l2_fh;
> +struct media_request;
> +struct media_request_entity;
> +struct v4l2_request_entity_data;
> +
>  /**
>   * struct vb2_v4l2_buffer - video buffer information for v4l2.
>   *
> @@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
>   */
>  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
>  
> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
> +
> +/**
> + * vb2_qbuf_request() - Queue a buffer, with request support
> + * @q:		pointer to &struct vb2_queue with videobuf2 queue.
> + * @b:		buffer structure passed from userspace to
> + *		&v4l2_ioctl_ops->vidioc_qbuf handler in driver
> + * @entity:	request entity to queue for if requests are used.
> + *
> + * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
> + *
> + * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
> + *
> + * If the request_fd member of b is set, then the buffer represented by b is
> + * queued in the request instead of the vb2 queue. The buffer will be passed
> + * to the vb2 queue when the request is submitted.

I would definitely also prepare the buffer at this time. That way you'll see any
errors relating to the prepare early on.

> + *
> + * The return values from this function are intended to be directly returned
> + * from &v4l2_ioctl_ops->vidioc_qbuf handler in driver.
> + */
> +int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
> +		     struct media_request_entity *entity);
> +
> +/**
> + * vb2_request_submit() - Queue all the buffers in a v4l2 request.
> + * @data:	request entity data to queue buffers of
> + *
> + * This function should be called from the media_request_entity_ops::submit
> + * hook for instances of media_request_v4l2_entity_data. It will immediately
> + * queue all the request-bound buffers to their respective vb2 queues.
> + *
> + * Errors from vb2_core_qbuf() are returned if something happened. Also, since
> + * v4l2 request entities require at least one buffer for the request to trigger,
> + * this function will return -EINVAL if no buffer have been bound at all for
> + * this entity.
> + */
> +int vb2_request_submit(struct v4l2_request_entity_data *data);
> +
> +#else /* CONFIG_MEDIA_REQUEST_API */
> +
> +static inline int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
> +				   struct media_request_entity *entity)
> +{
> +	return vb2_qbuf(q, b);
> +}
> +
> +static inline int vb2_request_submit(struct v4l2_request_entity_data *data)
> +{
> +	return -ENOTSUPP;
> +}
> +
> +#endif /* CONFIG_MEDIA_REQUEST_API */
> +
>  /**
>   * vb2_expbuf() - Export a buffer as a file descriptor
>   * @q:		pointer to &struct vb2_queue with videobuf2 queue.
> 

Regards,

	Hans

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

* Re: [RFCv4 16/21] v4l2: video_device: support for creating requests
  2018-02-20  4:44 ` [RFCv4 16/21] v4l2: video_device: support for creating requests Alexandre Courbot
@ 2018-02-20 16:35   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-20 16:35 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel

On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
> Add a new VIDIOC_NEW_REQUEST ioctl, which allows to instanciate requests
> on devices that support the request API. Requests created that way can
> only control the device they originate from, making them suitable for
> simple devices, but not complex pipelines.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  Documentation/ioctl/ioctl-number.txt |  1 +
>  drivers/media/v4l2-core/v4l2-dev.c   |  2 ++
>  drivers/media/v4l2-core/v4l2-ioctl.c | 25 +++++++++++++++++++++++++
>  include/media/v4l2-dev.h             |  2 ++
>  include/uapi/linux/videodev2.h       |  3 +++
>  5 files changed, 33 insertions(+)
> 
> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
> index 6501389d55b9..afdc9ed255b0 100644
> --- a/Documentation/ioctl/ioctl-number.txt
> +++ b/Documentation/ioctl/ioctl-number.txt
> @@ -286,6 +286,7 @@ Code  Seq#(hex)	Include File		Comments
>  					<mailto:oe@port.de>
>  'z'	10-4F	drivers/s390/crypto/zcrypt_api.h	conflict!
>  '|'	00-7F	linux/media.h
> +'|'	80-9F	linux/media-request.h
>  0x80	00-1F	linux/fb.h
>  0x89	00-06	arch/x86/include/asm/sockios.h
>  0x89	0B-DF	linux/sockios.h

This ^^^^ doesn't belong in this patch.

> diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
> index 0301fe426a43..062ebee5bffc 100644
> --- a/drivers/media/v4l2-core/v4l2-dev.c
> +++ b/drivers/media/v4l2-core/v4l2-dev.c
> @@ -559,6 +559,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
>  		set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
>  	if (vdev->ctrl_handler || ops->vidioc_querymenu)
>  		set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
> +	if (vdev->req_mgr)
> +		set_bit(_IOC_NR(VIDIOC_NEW_REQUEST), valid_ioctls);
>  	SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
>  	SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
>  	SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index ab4968ea443f..a45fe078f8ae 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -21,6 +21,7 @@
>  
>  #include <linux/videodev2.h>
>  
> +#include <media/media-request.h>
>  #include <media/v4l2-common.h>
>  #include <media/v4l2-ioctl.h>
>  #include <media/v4l2-ctrls.h>
> @@ -842,6 +843,13 @@ static void v4l_print_freq_band(const void *arg, bool write_only)
>  			p->rangehigh, p->modulation);
>  }
>  
> +static void vidioc_print_new_request(const void *arg, bool write_only)
> +{
> +	const struct media_request_new *new = arg;
> +
> +	pr_cont("fd=0x%x\n", new->fd);

I'd use %d since fds are typically shown as signed integers.

> +}
> +
>  static void v4l_print_edid(const void *arg, bool write_only)
>  {
>  	const struct v4l2_edid *p = arg;
> @@ -2486,6 +2494,22 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
>  	return -ENOTTY;
>  }
>  
> +static int vidioc_new_request(const struct v4l2_ioctl_ops *ops,
> +			      struct file *file, void *fh, void *arg)
> +{
> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
> +	struct media_request_new *new = arg;
> +	struct video_device *vfd = video_devdata(file);
> +
> +	if (!vfd->req_mgr)
> +		return -ENOTTY;
> +
> +	return media_request_ioctl_new(vfd->req_mgr, new);
> +#else
> +	return -ENOTTY;
> +#endif
> +}

You don't need the #ifdef's here. media_request_ioctl_new() will be stubbed if
CONFIG_MEDIA_REQUEST_API isn't set.

> +
>  struct v4l2_ioctl_info {
>  	unsigned int ioctl;
>  	u32 flags;
> @@ -2617,6 +2641,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
>  	IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
>  	IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
>  	IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
> +	IOCTL_INFO_FNC(VIDIOC_NEW_REQUEST, vidioc_new_request, vidioc_print_new_request, 0),
>  };
>  #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
>  
> diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
> index 53f32022fabe..e6c4e10889bc 100644
> --- a/include/media/v4l2-dev.h
> +++ b/include/media/v4l2-dev.h
> @@ -209,6 +209,7 @@ struct v4l2_file_operations {
>   * @entity: &struct media_entity
>   * @intf_devnode: pointer to &struct media_intf_devnode
>   * @pipe: &struct media_pipeline
> + * @req_mgr: request manager to use if this device supports creating requests
>   * @fops: pointer to &struct v4l2_file_operations for the video device
>   * @device_caps: device capabilities as used in v4l2_capabilities
>   * @dev: &struct device for the video device
> @@ -251,6 +252,7 @@ struct video_device
>  	struct media_intf_devnode *intf_devnode;
>  	struct media_pipeline pipe;
>  #endif
> +	struct media_request_mgr *req_mgr;
>  	const struct v4l2_file_operations *fops;
>  
>  	u32 device_caps;
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 91cfe0cbd5c5..35706204e81d 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -63,6 +63,7 @@
>  #include <linux/compiler.h>
>  #include <linux/ioctl.h>
>  #include <linux/types.h>
> +#include <linux/media-request.h>
>  #include <linux/v4l2-common.h>
>  #include <linux/v4l2-controls.h>
>  
> @@ -2407,6 +2408,8 @@ struct v4l2_create_buffers {
>  
>  #define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
>  
> +#define VIDIOC_NEW_REQUEST	_IOWR('V', 104, struct media_request_new)

Hmm, I probably call this VIDIOC_CREATE_REQUEST (analogous to CREATE_BUFS).
Ditto struct media_create_request and MEDIA_IOC_CREATE_REQUEST.

I'm still not convinced this is the right approach (as opposed to using the media
device node). I plan to dig deeper into the data structures tomorrow morning.

Regards,

	Hans

> +
>  /* Reminder: when adding new ioctls please add support for them to
>     drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
>  
> 

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

* Re: [RFCv4 01/21] media: add request API core and UAPI
  2018-02-20 10:36   ` Hans Verkuil
@ 2018-02-21  6:01     ` Alexandre Courbot
  2018-02-21  7:29       ` Hans Verkuil
  0 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-21  6:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

Hi Hans,

On Tue, Feb 20, 2018 at 7:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/18 05:44, Alexandre Courbot wrote:
>> The request API provides a way to group buffers and device parameters
>> into units of work to be queued and executed. This patch introduces the
>> UAPI and core framework.
>>
>> This patch is based on the previous work by Laurent Pinchart. The core
>> has changed considerably, but the UAPI is mostly untouched.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  drivers/media/Kconfig              |   3 +
>>  drivers/media/Makefile             |   6 +
>>  drivers/media/media-request.c      | 341 ++++++++++++++++++++++++++++
>>  include/media/media-request.h      | 349 +++++++++++++++++++++++++++++
>>  include/uapi/linux/media-request.h |  37 +++
>>  5 files changed, 736 insertions(+)
>>  create mode 100644 drivers/media/media-request.c
>>  create mode 100644 include/media/media-request.h
>>  create mode 100644 include/uapi/linux/media-request.h
>>
>> diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
>> index 145e12bfb819..db30fc9547d2 100644
>> --- a/drivers/media/Kconfig
>> +++ b/drivers/media/Kconfig
>> @@ -130,6 +130,9 @@ config VIDEO_V4L2_SUBDEV_API
>>
>>         This API is mostly used by camera interfaces in embedded platforms.
>>
>> +config MEDIA_REQUEST_API
>> +     tristate
>> +
>>  source "drivers/media/v4l2-core/Kconfig"
>>
>>  #
>> diff --git a/drivers/media/Makefile b/drivers/media/Makefile
>> index 594b462ddf0e..03c0a39ad344 100644
>> --- a/drivers/media/Makefile
>> +++ b/drivers/media/Makefile
>> @@ -5,6 +5,12 @@
>>
>>  media-objs   := media-device.o media-devnode.o media-entity.o
>>
>> +#
>> +# Request API support comes as its own module since it can be used by
>> +# both media and video devices
>> +#
>> +obj-$(CONFIG_MEDIA_REQUEST_API) += media-request.o
>> +
>>  #
>>  # I2C drivers should come before other drivers, otherwise they'll fail
>>  # when compiled as builtin drivers
>> diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
>> new file mode 100644
>> index 000000000000..b88362028561
>> --- /dev/null
>> +++ b/drivers/media/media-request.c
>> @@ -0,0 +1,341 @@
>> +/*
>> + * Request base implementation
>> + *
>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/anon_inodes.h>
>> +#include <linux/fs.h>
>> +#include <linux/file.h>
>> +#include <linux/list.h>
>> +#include <linux/device.h>
>> +#include <linux/media-request.h>
>> +#include <linux/module.h>
>> +#include <linux/poll.h>
>> +#include <linux/slab.h>
>> +
>> +#include <media/media-request.h>
>> +
>> +const struct file_operations request_fops;
>> +
>> +static const char * const media_request_states[] __maybe_unused = {
>
> Why 'maybe_unused'?
>
>> +     "IDLE",
>> +     "SUBMITTED",
>> +     "COMPLETED",
>> +     "INVALID",
>
> I don't like to yell. I prefer "Idle", "Submitted", etc.

Sure.

>
>> +};
>> +
>> +struct media_request *media_request_get(struct media_request *req)
>> +{
>> +     get_file(req->file);
>> +     return req;
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_get);
>> +
>> +struct media_request *media_request_get_from_fd(int fd)
>> +{
>> +     struct file *f;
>> +
>> +     f = fget(fd);
>> +     if (!f)
>> +             return NULL;
>> +
>> +     /* Not a request FD? */
>> +     if (f->f_op != &request_fops) {
>> +             fput(f);
>> +             return NULL;
>> +     }
>> +
>> +     return f->private_data;
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_get_from_fd);
>> +
>> +void media_request_put(struct media_request *req)
>> +{
>> +     if (WARN_ON(req == NULL))
>> +             return;
>> +
>> +     fput(req->file);
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_put);
>> +
>> +struct media_request_entity_data *
>> +media_request_get_entity_data(struct media_request *req,
>> +                           struct media_request_entity *entity)
>> +{
>> +     struct media_request_entity_data *data;
>> +
>> +     /* First check that this entity is valid for this request at all */
>> +     if (!req->mgr->ops->entity_valid(req, entity))
>> +             return ERR_PTR(-EINVAL);
>> +
>> +     mutex_lock(&req->lock);
>> +
>> +     /* Lookup whether we already have entity data */
>> +     list_for_each_entry(data, &req->data, list) {
>> +             if (data->entity == entity)
>> +                     goto out;
>> +     }
>> +
>> +     /* No entity data found, let's create it */
>> +     data = entity->ops->data_alloc(req, entity);
>> +     if (IS_ERR(data))
>> +             goto out;
>> +
>> +     data->entity = entity;
>> +     list_add_tail(&data->list, &req->data);
>> +
>> +out:
>> +     mutex_unlock(&req->lock);
>> +
>> +     return data;
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_get_entity_data);
>> +
>> +static unsigned int media_request_poll(struct file *file, poll_table *wait)
>> +{
>> +     struct media_request *req = file->private_data;
>> +
>> +     poll_wait(file, &req->complete_wait, wait);
>> +
>> +     if (req->state == MEDIA_REQUEST_STATE_COMPLETED)
>> +             return POLLIN | POLLRDNORM;
>> +
>> +     return 0;
>> +}
>> +
>> +static int media_request_release(struct inode *inode, struct file *filp)
>> +{
>> +     struct media_request *req = filp->private_data;
>> +
>> +     if (req == NULL)
>> +             return 0;
>> +
>> +     req->mgr->ops->release(req);
>> +     return 0;
>> +}
>> +
>> +static long media_request_ioctl_submit(struct media_request *req)
>> +{
>> +     mutex_lock(&req->lock);
>> +
>> +     if (req->state != MEDIA_REQUEST_STATE_IDLE) {
>> +             dev_warn(req->mgr->dev, "cannot submit request in state %s\n",
>> +                      media_request_states[req->state]);
>> +             mutex_unlock(&req->lock);
>> +             return -EINVAL;
>> +     }
>> +
>> +     req->state = MEDIA_REQUEST_STATE_SUBMITTED;
>> +
>> +     /*
>> +      * Nothing can change our state when we are submitted - no need to keep
>> +      * holding that lock.
>> +      */
>> +     mutex_unlock(&req->lock);
>> +
>> +     /* Keep a reference to the request until it is completed */
>> +     media_request_get(req);
>> +
>> +     return req->mgr->ops->submit(req);
>
> What happens if submit() returns an error? I would expect that the state goes
> back to IDLE and the reference is put().

Fixed.

>
>> +}
>> +
>> +static long media_request_ioctl_reinit(struct media_request *req)
>> +{
>> +     struct media_request_entity_data *data, *next;
>> +        LIST_HEAD(to_delete);
>
> Weird indentation.

Indeed, fixed.

>
>> +
>> +     mutex_lock(&req->lock);
>> +
>> +     if (req->state == MEDIA_REQUEST_STATE_SUBMITTED) {
>> +             dev_warn(req->mgr->dev,
>> +                     "%s: unable to reinit submitted request\n", __func__);
>> +             mutex_unlock(&req->lock);
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* delete all entity data */
>> +     list_for_each_entry_safe(data, next, &req->data, list) {
>> +             list_del(&data->list);
>> +                list_add(&data->list, &to_delete);
>
> Strange indentation.
>
> You can also use list_move(&data->list, &to_delete).

Fixed and used list_move().

>
>> +     }
>> +
>> +     /* reinitialize request to idle state */
>> +     req->state = MEDIA_REQUEST_STATE_IDLE;
>> +
>> +     mutex_unlock(&req->lock);
>> +
>> +        list_for_each_entry_safe(data, next, &to_delete, list)
>
> Again strange indentation. Not sure what's going on with that.
> I'll ignore it going forward.

Yeah, sorry about that. Not sure what I did wrong here, besides not
running checkpatch on this set :/.

>
>> +             data->entity->ops->data_free(data);
>> +
>> +     return 0;
>> +}
>> +
>> +#define MEDIA_REQUEST_IOC(__cmd, func)                                       \
>> +     [_IOC_NR(MEDIA_REQUEST_IOC_##__cmd) - 0x80] = {                 \
>> +             .cmd = MEDIA_REQUEST_IOC_##__cmd,                       \
>> +             .fn = func,                                             \
>> +     }
>> +
>> +struct media_request_ioctl_info {
>> +     unsigned int cmd;
>> +     long (*fn)(struct media_request *req);
>> +};
>> +
>> +static const struct media_request_ioctl_info ioctl_info[] = {
>> +     MEDIA_REQUEST_IOC(SUBMIT, media_request_ioctl_submit),
>> +     MEDIA_REQUEST_IOC(REINIT, media_request_ioctl_reinit),
>
> There are only two ioctls, so there is really no need for the
> MEDIA_REQUEST_IOC define. Just keep it simple.

The number of times it is used doesn't change the fact that it helps
with readability IMHO.

>
>> +};
>> +
>> +static long media_request_ioctl(struct file *filp, unsigned int cmd,
>> +                             unsigned long __arg)
>> +{
>> +     struct media_request *req = filp->private_data;
>> +     const struct media_request_ioctl_info *info;
>> +
>> +     if ((_IOC_NR(cmd) < 0x80) ||
>
> Why start the ioctl number at 0x80? Why not just 0?
> It avoids all this hassle with the 0x80 offset.
>
>> +          _IOC_NR(cmd) >= 0x80 + ARRAY_SIZE(ioctl_info) ||
>> +          ioctl_info[_IOC_NR(cmd) - 0x80].cmd != cmd)
>> +             return -ENOIOCTLCMD;
>> +
>> +     info = &ioctl_info[_IOC_NR(cmd) - 0x80];
>> +
>> +     return info->fn(req);
>> +}
>> +
>> +const struct file_operations request_fops = {
>> +     .owner = THIS_MODULE,
>> +     .poll = media_request_poll,
>> +     .release = media_request_release,
>> +     .unlocked_ioctl = media_request_ioctl,
>> +};
>> +
>> +static void media_request_complete(struct media_request *req)
>> +{
>> +     struct device *dev = req->mgr->dev;
>> +
>> +     mutex_lock(&req->lock);
>> +
>> +     if (WARN_ON(req->state != MEDIA_REQUEST_STATE_SUBMITTED)) {
>> +             dev_warn(dev, "can't complete request in state %s\n",
>> +                     media_request_states[req->state]);
>> +             mutex_unlock(&req->lock);
>> +             return;
>> +     }
>> +
>> +     req->state = MEDIA_REQUEST_STATE_COMPLETED;
>> +
>> +     wake_up_interruptible(&req->complete_wait);
>> +
>> +     mutex_unlock(&req->lock);
>> +
>> +     /* Release the reference acquired when we submitted the request */
>> +     media_request_put(req);
>> +}
>> +
>> +void media_request_entity_complete(struct media_request *req,
>> +                                struct media_request_entity *completed)
>> +{
>> +     struct media_request_entity_data *data;
>> +     int cpt = 0;
>> +
>> +     list_for_each_entry(data, &req->data, list) {
>> +             if (data->entity == completed)
>> +                     data->completed = true;
>> +             if (!data->completed)
>
> This can be 'else if'.

Fixed.

>
>> +                     ++cpt;
>> +     }
>> +
>> +     if (cpt == 0)
>> +             media_request_complete(req);
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_entity_complete);
>> +
>> +long media_request_ioctl_new(struct media_request_mgr *mgr,
>> +                          struct media_request_new *new)
>> +{
>> +     struct media_request *req;
>> +     int err;
>> +     int fd;
>> +
>> +     /* User only wants to check the availability of requests? */
>> +     if (new->flags & MEDIA_REQUEST_FLAG_TEST)
>> +             return 0;
>> +
>> +     fd = get_unused_fd_flags(O_CLOEXEC);
>> +     if (fd < 0)
>> +             return fd;
>> +
>> +     req = mgr->ops->alloc(mgr);
>> +     if (IS_ERR(req)) {
>> +             err = PTR_ERR(req);
>> +             goto out_fd;
>> +     }
>> +
>> +     req->file = anon_inode_getfile("request", &request_fops, req,
>> +                                    O_CLOEXEC);
>> +     if (IS_ERR(req->file)) {
>> +             err = PTR_ERR(req->file);
>> +             mgr->ops->release(req);
>> +             goto out_fd;
>> +     }
>> +
>> +     fd_install(fd, req->file);
>> +     new->fd = fd;
>> +
>> +     return 0;
>> +
>> +out_fd:
>> +     put_unused_fd(fd);
>> +     return err;
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_ioctl_new);
>> +
>> +void media_request_entity_init(struct media_request_entity *entity,
>> +                            enum media_request_entity_type type,
>> +                            const struct media_request_entity_ops *ops)
>> +{
>> +     entity->type = type;
>> +     entity->ops = ops;
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_entity_init);
>> +
>> +void media_request_mgr_init(struct media_request_mgr *mgr, struct device *dev,
>> +                         const struct media_request_ops *ops)
>> +{
>> +     mgr->dev = dev;
>> +     mutex_init(&mgr->mutex);
>> +     INIT_LIST_HEAD(&mgr->requests);
>> +     mgr->ops = ops;
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_mgr_init);
>> +
>> +void media_request_mgr_free(struct media_request_mgr *mgr)
>> +{
>> +     struct device *dev = mgr->dev;
>> +
>> +     /* Just a sanity check - we should have no remaining requests */
>> +     while (!list_empty(&mgr->requests)) {
>> +             struct media_request *req;
>> +
>> +             req = list_first_entry(&mgr->requests, typeof(*req), list);
>> +             dev_warn(dev,
>> +                     "%s: request still referenced, deleting forcibly!\n",
>> +                     __func__);
>> +             mgr->ops->release(req);
>> +     }
>> +}
>> +EXPORT_SYMBOL_GPL(media_request_mgr_free);
>> +
>> +MODULE_AUTHOR("Alexandre Courbot <acourbot@chromium.org>");
>> +MODULE_DESCRIPTION("Core support for media request API");
>> +MODULE_LICENSE("GPL");
>> diff --git a/include/media/media-request.h b/include/media/media-request.h
>> new file mode 100644
>> index 000000000000..110dcdc1099f
>> --- /dev/null
>> +++ b/include/media/media-request.h
>> @@ -0,0 +1,349 @@
>> +/*
>> + * Media requests.
>> + *
>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef _MEDIA_REQUEST_H
>> +#define _MEDIA_REQUEST_H
>> +
>> +struct media_request;
>> +struct media_request_entity;
>> +struct media_request_entity_data;
>> +struct media_request_mgr;
>> +struct media_request_new;
>> +
>> +#include <linux/kconfig.h>
>> +
>> +enum media_request_state {
>> +     MEDIA_REQUEST_STATE_IDLE,
>> +     MEDIA_REQUEST_STATE_SUBMITTED,
>> +     MEDIA_REQUEST_STATE_COMPLETED,
>> +     MEDIA_REQUEST_STATE_INVALID,
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>> +
>> +#include <linux/kref.h>
>> +#include <linux/list.h>
>> +#include <linux/notifier.h>
>> +#include <linux/wait.h>
>> +
>> +/**
>> + * struct media_request_entity_ops - request entity operations
>> + *
>> + * @data_alloc:      allocate memory to store that entity's relevant state
>> + * @data_free:       free state previously allocated with data_alloc
>> + * @submit:  perform all required actions to be ready to process that request
>> + */
>> +struct media_request_entity_ops {
>> +     struct media_request_entity_data *
>> +             (*data_alloc)(struct media_request *req,
>> +                           struct media_request_entity *entity);
>> +     void (*data_free)(struct media_request_entity_data *data);
>> +     int (*submit)(struct media_request *req,
>> +                   struct media_request_entity_data *data);
>> +};
>> +
>> +/**
>> + * enum media_request_entity_type - describe type of an entity
>> + *
>> + * This type lets us know the upper kind of a struct media_request_entity
>> + * instance.
>> + *
>> + * @MEDIA_REQUEST_ENTITY_TYPE_V4L2:  instance can be upcasted to
>> + *                                   v4l2_request_entity
>> + * @MEDIA_REQUEST_ENTITY_TYPE_MC:    instance can be updated to
>> + *                                   mc_request_entity
>> + *
>> + */
>> +enum media_request_entity_type {
>> +     MEDIA_REQUEST_ENTITY_TYPE_V4L2,
>> +     MEDIA_REQUEST_ENTITY_TYPE_MC,
>> +};
>> +
>> +/**
>> + * struct media_request_entity - request entity base structure
>> + *
>> + * @type:    type of entity, indicating which upcast is safe to perform
>> + * @ops:     operations that this entity can perform
>> + *
>> + * This structure is supposed to be embedded into a larger structure
>> + * better representing the specifics of the instance (e.g. v4l2_request_entity
>> + * for controlling V4L2 devices).
>> + *
>> + */
>> +struct media_request_entity {
>> +     enum media_request_entity_type type;
>> +     const struct media_request_entity_ops *ops;
>> +};
>> +
>> +/**
>> + * media_request_entity_init() - initialize a request entity's base properties
>> + *
>> + * @entity:  entity to initialize
>> + * @type:    type of this entity
>> + * @ops:     operations that this entity will perform
>> + */
>> +void media_request_entity_init(struct media_request_entity *entity,
>> +                            enum media_request_entity_type type,
>> +                            const struct media_request_entity_ops *ops);
>> +
>> +/**
>> + * struct media_request_entity_data - per-entity request data
>> + *
>> + * @request: request instance this data belongs to
>> + * @entity:  entity that stores data here
>> + * @list:    entry in media_request::data
>> + * @completed:       whether this entity has completed its part of the request
>> + *
>> + * Base structure used to store request state data. To be extended by actual
>> + * implementation.
>> + *
>> + */
>> +struct media_request_entity_data {
>> +     struct media_request *request;
>> +     struct media_request_entity *entity;
>> +     struct list_head list;
>> +     bool completed;
>> +};
>> +
>> +/**
>> + * struct media_request - Media request base structure
>> + *
>> + * @mgr:     manager this request belongs to
>> + * @file:    used to export FDs to user-space and reference count
>> + * @list:    entry in the media_request_mgr::requests list
>> + * @lock:    protects following members against concurrent accesses
>> + * @state:   current state of the request
>> + * @data:    per-entity data list
>> + * @complete_wait:   wait queue that signals once the request has completed
>> + */
>> +struct media_request {
>> +     struct media_request_mgr *mgr;
>> +     struct file *file;
>> +     struct list_head list;
>> +
>> +     struct mutex lock;
>> +     enum media_request_state state;
>> +     struct list_head data;
>> +     wait_queue_head_t complete_wait;
>> +};
>> +
>> +/**
>> + * media_request_get() - increment the reference counter of a request
>> + *
>> + * The calling context must call media_request_put() once it does not need
>> + * the reference to the request anymore.
>> + *
>> + * Returns the request that has been passed as argument.
>> + *
>> + * @req:     request to acquire a reference of
>> + */
>> +struct media_request *media_request_get(struct media_request *req);
>> +
>> +/**
>> + * media_request_get_from_fd() - lookup request by fd and acquire a reference.
>> + *
>> + * Look a request up from its fd, acquire a reference and return a pointer to
>> + * the request. As for media_request_get(), media_request_put() must be called
>> + * once the reference is not used anymore.
>> + *
>> + * @req:     request to lookup and acquire.
>> + *
>> + */
>> +struct media_request *media_request_get_from_fd(int fd);
>> +
>> +/**
>> + * media_request_put() - decrement the reference counter of a request
>> + *
>> + * Mirror function of media_request_get() and media_request_get_from_fd(). Will
>> + * free the request if this was the last valid reference.
>> + *
>> + * @req:     request to release.
>> + */
>> +void media_request_put(struct media_request *req);
>> +
>> +/**
>> + * media_request_lock() - prevent concurrent access to that request
>> + *
>> + * @req:     request to lock
>> + */
>> +static inline void media_request_lock(struct media_request *req)
>> +{
>> +     mutex_lock(&req->lock);
>> +}
>> +
>> +/**
>> + * media_request_unlock() - release previously acquired request lock
>> + *
>> + * @req:     request to release
>> + */
>> +static inline void media_request_unlock(struct media_request *req)
>> +{
>> +     mutex_unlock(&req->lock);
>> +}
>> +
>> +/**
>> + * media_request_get_state() - get the state of a request
>> + *
>> + * @req:     request which state we are interested in
>> + *
>> + * The request lock should always be acquired when confirming this value
>> + * to avoid race conditions.
>> + *
>> + */
>> +static inline enum media_request_state
>> +media_request_get_state(struct media_request *req)
>> +{
>> +     return req->state;
>> +}
>> +
>> +/**
>> + * media_request_get_entity_data() - get per-entity data for a request
>> + * @req:     request to get entity data from
>> + * @entity:  entity to get data of
>> + *
>> + * Search and return the entity data associated associated to the request. If no
>> + * such data exists, it is allocated as per the entity operations.
>> + *
>> + * Returns the per-entity data, or an error code if a problem happened. -EINVAL
>> + * means that data for the entity already existed, but has been allocated under
>> + * a different cookie.
>> + */
>> +struct media_request_entity_data *
>> +media_request_get_entity_data(struct media_request *req,
>> +                           struct media_request_entity *entity);
>> +
>> +/**
>> + * media_request_entity_complete() - to be invoked when an entity completes its
>> + *                                part of the request
>> + *
>> + * @req:     request which has completed
>> + * @completed:       entity that has completed
>> + */
>> +void media_request_entity_complete(struct media_request *req,
>> +                                struct media_request_entity *completed);
>> +
>> +/**
>> + * media_request_ioctl_new() - process a NEW_REQUEST ioctl
>> + *
>> + * @mgr:     request manager from which to allocate the request
>> + * @new:     media_request_new structure to be passed back to user-space
>> + *
>> + * This function is a helper to be called by actual handlers of *_NEW_REQUEST
>> + * ioctls.
>> + */
>> +long media_request_ioctl_new(struct media_request_mgr *mgr,
>> +                          struct media_request_new *new);
>> +
>> +/**
>> + * struct media_request_ops - request operations
>> + *
>> + * @alloc:   allocate a request
>> + * @release: free a previously allocated request
>> + * @entity_valid:    returns whether a given entity is valid for that request
>> + * @submit:  allow the request to be processed
>> + *
>> + * This structure allows to specialize requests to a specific scope. For
>> + * instance, requests obtained from a V4L2 device node should only be able to
>> + * control that device. On the other hand, requests created from a media
>> + * controller node will be able to control all the devices managed by this
>> + * controller, and may want to implement some form of synchronization between
>> + * them.
>> + */
>> +struct media_request_ops {
>> +     struct media_request *(*alloc)(struct media_request_mgr *mgr);
>> +     void (*release)(struct media_request *req);
>> +     bool (*entity_valid)(const struct media_request *req,
>> +                          const struct media_request_entity *entity);
>> +     int (*submit)(struct media_request *req);
>> +};
>> +
>> +/**
>> + * struct media_request_mgr - requests manager
>> + *
>> + * @dev:     device owning this manager
>> + * @ops:     implementation of the manager
>> + * @mutex:   protects the requests list_head
>> + * @requests:        list of alive requests produced by this manager
>> + *
>> + * This structure is mainly responsible for allocating requests. Although it is
>> + * not strictly required for that purpose, having it allows us to account for
>> + * all requests created by a given device, and to make sure they are all
>> + * discarded by the time the device is destroyed.
>> + */
>> +struct media_request_mgr {
>> +     struct device *dev;
>> +     const struct media_request_ops *ops;
>> +
>> +     struct mutex mutex;
>> +     struct list_head requests;
>> +};
>> +
>> +/**
>> + * media_request_mgr_init() - initialize a request manager.
>> + *
>> + * @mgr:     manager to initialize
>> + */
>> +void media_request_mgr_init(struct media_request_mgr *mgr, struct device *dev,
>> +                         const struct media_request_ops *ops);
>> +
>> +/**
>> + * media_request_mgr_free() - free a media manager
>> + *
>> + * This should only be called when all requests produced by this manager
>> + * has been destroyed. Will warn if that is not the case.
>> + */
>> +void media_request_mgr_free(struct media_request_mgr *mgr);
>> +
>> +#else /* CONFIG_MEDIA_REQUEST_API */
>> +
>> +static inline void media_request_entity_complete(struct media_request *req,
>> +                                      struct media_request_entity *completed)
>> +{
>> +}
>> +
>> +static inline struct media_request_entity_data *
>> +media_request_get_entity_data(struct media_request *req,
>> +                           struct media_request_entity *entity)
>> +{
>> +     return ERR_PTR(-ENOTSUPP);
>> +}
>> +
>> +static inline long media_request_ioctl_new(struct media_request_mgr *mgr,
>> +                                        struct media_request_new *new)
>> +{
>> +     return -ENOTTY;
>> +}
>> +
>> +static inline void media_request_put(struct media_request *req)
>> +{
>> +}
>> +
>> +static inline void media_request_lock(struct media_request *req)
>> +{
>> +}
>> +
>> +static inline void media_request_unlock(struct media_request *req)
>> +{
>> +}
>> +
>> +static inline enum media_request_state
>> +media_request_get_state(struct media_request *req)
>> +{
>> +     return MEDIA_REQUEST_STATE_INVALID;
>> +}
>> +
>> +#endif /* CONFIG_MEDIA_REQUEST_API */
>> +
>> +#endif
>> diff --git a/include/uapi/linux/media-request.h b/include/uapi/linux/media-request.h
>> new file mode 100644
>> index 000000000000..5d30f731a442
>> --- /dev/null
>> +++ b/include/uapi/linux/media-request.h
>> @@ -0,0 +1,37 @@
>> +/*
>> + * Media requests UAPI
>> + *
>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __LINUX_MEDIA_REQUEST_H
>> +#define __LINUX_MEDIA_REQUEST_H
>> +
>> +#ifndef __KERNEL__
>> +#include <stdint.h>
>> +#endif
>> +#include <linux/ioctl.h>
>> +#include <linux/types.h>
>> +#include <linux/version.h>
>> +
>> +/* Only check that requests can be used, do not allocate */
>> +#define MEDIA_REQUEST_FLAG_TEST                      0x00000001
>> +
>> +struct media_request_new {
>> +     __u32 flags;
>> +     __s32 fd;
>> +} __attribute__ ((packed));
>> +
>> +#define MEDIA_REQUEST_IOC_SUBMIT       _IO('|',  128)
>> +#define MEDIA_REQUEST_IOC_REINIT       _IO('|',  129)
>> +
>> +#endif
>>
>
> I need to think a bit more on this internal API, so I might come back
> to this patch for more comments.

I think I should probably elaborate on why I think it is advantageous
to have these ioctls handled here.

One of the reasons if that it does not force user-space to keep track
of who issued the request to operate on it. Semantically, the only
device a request could be submitted to is the device that produced it
anyway, so since that argument is constant we may as well get rid of
it (and we also don't need to pass the request FD as argument
anymore).

It also gives us more freedom when designing new request-related
ioctls: before, all request-related operations were multiplexed under
a single MEDIA_IOC_REQUEST_CMD ioctl, which cmd field indicated the
actual operation to perform. With this design, all the arguments must
fit within the media_request_cmd structure, which may cause confusion
as it will have to be variable-sized. I am thinking in particular
about a future atomic-like API to set topology, controls and buffers
related to a request all at the same time. Having it as a request
ioctl seems perfectly fitting to me.

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

* Re: [RFCv4 09/21] v4l2: add request API support
  2018-02-20 13:25   ` Hans Verkuil
@ 2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-21  6:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On Tue, Feb 20, 2018 at 10:25 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/18 05:44, Alexandre Courbot wrote:
>> Add a v4l2 request entity data structure that takes care of storing the
>> request-related state of a V4L2 device ; in this case, its controls.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  drivers/media/v4l2-core/Makefile       |   1 +
>>  drivers/media/v4l2-core/v4l2-request.c | 178 +++++++++++++++++++++++++
>>  include/media/v4l2-request.h           | 159 ++++++++++++++++++++++
>>  3 files changed, 338 insertions(+)
>>  create mode 100644 drivers/media/v4l2-core/v4l2-request.c
>>  create mode 100644 include/media/v4l2-request.h
>>
>> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
>> index 80de2cb9c476..13d0477535bd 100644
>> --- a/drivers/media/v4l2-core/Makefile
>> +++ b/drivers/media/v4l2-core/Makefile
>> @@ -16,6 +16,7 @@ ifeq ($(CONFIG_TRACEPOINTS),y)
>>    videodev-objs += vb2-trace.o v4l2-trace.o
>>  endif
>>  videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
>> +videodev-$(CONFIG_MEDIA_REQUEST_API) += v4l2-request.o
>>
>>  obj-$(CONFIG_VIDEO_V4L2) += videodev.o
>>  obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
>> diff --git a/drivers/media/v4l2-core/v4l2-request.c b/drivers/media/v4l2-core/v4l2-request.c
>> new file mode 100644
>> index 000000000000..e8ad10e2f525
>> --- /dev/null
>> +++ b/drivers/media/v4l2-core/v4l2-request.c
>> @@ -0,0 +1,178 @@
>> +/*
>> + * Media requests support for V4L2
>> + *
>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/slab.h>
>> +
>> +#include <media/v4l2-dev.h>
>> +#include <media/v4l2-request.h>
>> +#include <media/videobuf2-v4l2.h>
>> +
>> +void v4l2_request_entity_init(struct v4l2_request_entity *entity,
>> +                           const struct media_request_entity_ops *ops,
>> +                           struct video_device *vdev)
>> +{
>> +     media_request_entity_init(&entity->base, MEDIA_REQUEST_ENTITY_TYPE_V4L2, ops);
>> +     entity->vdev = vdev;
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_request_entity_init);
>> +
>> +struct media_request_entity_data *
>> +v4l2_request_entity_data_alloc(struct media_request *req,
>> +                            struct v4l2_ctrl_handler *hdl)
>> +{
>> +     struct v4l2_request_entity_data *data;
>> +     int ret;
>> +
>> +     data = kzalloc(sizeof(*data), GFP_KERNEL);
>> +     if (!data)
>> +             return ERR_PTR(-ENOMEM);
>> +
>> +     ret = v4l2_ctrl_request_init(&data->ctrls);
>> +     if (ret) {
>> +             kfree(data);
>> +             return ERR_PTR(ret);
>> +     }
>> +     ret = v4l2_ctrl_request_clone(&data->ctrls, hdl, NULL);
>> +     if (ret) {
>> +             kfree(data);
>> +             return ERR_PTR(ret);
>> +     }
>> +
>> +     INIT_LIST_HEAD(&data->queued_buffers);
>> +
>> +     return &data->base;
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_request_entity_data_alloc);
>> +
>> +void v4l2_request_entity_data_free(struct media_request_entity_data *_data)
>> +{
>> +     struct v4l2_request_entity_data *data;
>> +     struct v4l2_vb2_request_buffer *qb, *n;
>> +
>> +     data = to_v4l2_entity_data(_data);
>> +
>> +     list_for_each_entry_safe(qb, n, &data->queued_buffers, node) {
>> +             struct vb2_buffer *buf;
>> +             dev_warn(_data->request->mgr->dev,
>> +                      "entity data freed while buffer still queued!\n");
>> +
>> +             /* give buffer back to user-space */
>> +             buf = qb->queue->bufs[qb->v4l2_buf.index];
>> +             buf->state = qb->pre_req_state;
>> +             buf->request = NULL;
>> +
>> +             kfree(qb);
>> +     }
>> +
>> +     v4l2_ctrl_handler_free(&data->ctrls);
>> +     kfree(data);
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_request_entity_data_free);
>> +
>> +
>> +
>> +
>> +
>> +static struct media_request *v4l2_request_alloc(struct media_request_mgr *mgr)
>> +{
>> +     struct media_request *req;
>> +
>> +     req = kzalloc(sizeof(*req), GFP_KERNEL);
>> +     if (!req)
>> +             return ERR_PTR(-ENOMEM);
>> +
>> +     req->mgr = mgr;
>> +     req->state = MEDIA_REQUEST_STATE_IDLE;
>> +     INIT_LIST_HEAD(&req->data);
>> +     init_waitqueue_head(&req->complete_wait);
>> +     mutex_init(&req->lock);
>> +
>> +     mutex_lock(&mgr->mutex);
>> +     list_add_tail(&req->list, &mgr->requests);
>> +     mutex_unlock(&mgr->mutex);
>> +
>> +     return req;
>> +}
>> +
>> +static void v4l2_request_free(struct media_request *req)
>> +{
>> +     struct media_request_mgr *mgr = req->mgr;
>> +     struct media_request_entity_data *data, *next;
>> +
>> +     mutex_lock(&mgr->mutex);
>> +     list_del(&req->list);
>> +     mutex_unlock(&mgr->mutex);
>> +
>> +     list_for_each_entry_safe(data, next, &req->data, list) {
>> +             list_del(&data->list);
>> +             data->entity->ops->data_free(data);
>> +     }
>> +
>> +     kfree(req);
>> +}
>> +
>> +static bool v4l2_entity_valid(const struct media_request *req,
>> +                           const struct media_request_entity *_entity)
>> +{
>> +     const struct v4l2_request_mgr *mgr;
>> +     const struct v4l2_request_entity *entity;
>> +
>> +     if (_entity->type != MEDIA_REQUEST_ENTITY_TYPE_V4L2)
>> +             return false;
>> +
>> +     entity = container_of(_entity, struct v4l2_request_entity, base);
>> +     mgr = container_of(req->mgr, struct v4l2_request_mgr, base);
>> +
>> +     /* Entity is valid if it is the video device that created the manager */
>> +     return entity->vdev == mgr->vdev;
>> +}
>> +
>> +static int v4l2_request_submit(struct media_request *req)
>> +{
>> +     struct media_request_entity_data *data;
>> +
>> +        /* Submit for each entity */
>> +     list_for_each_entry(data, &req->data, list) {
>> +             int ret = data->entity->ops->submit(req, data);
>> +             /* TODO proper error handling, abort on other entities? */
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +const struct media_request_ops v4l2_request_ops = {
>> +     .alloc = v4l2_request_alloc,
>> +     .release = v4l2_request_free,
>> +     .entity_valid = v4l2_entity_valid,
>> +     .submit = v4l2_request_submit,
>> +};
>> +EXPORT_SYMBOL_GPL(v4l2_request_ops);
>> +
>> +void v4l2_request_mgr_init(struct v4l2_request_mgr *mgr,
>> +                       struct video_device *vdev,
>> +                       const struct media_request_ops *ops)
>> +{
>> +     media_request_mgr_init(&mgr->base, &vdev->dev, ops);
>> +     mgr->vdev = vdev;
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_request_mgr_init);
>> +
>> +void v4l2_request_mgr_free(struct v4l2_request_mgr* mgr)
>> +{
>> +     media_request_mgr_free(&mgr->base);
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_request_mgr_free);
>> diff --git a/include/media/v4l2-request.h b/include/media/v4l2-request.h
>> new file mode 100644
>> index 000000000000..8a87ca455b74
>> --- /dev/null
>> +++ b/include/media/v4l2-request.h
>> @@ -0,0 +1,159 @@
>> +/*
>> + * Media requests support for V4L2
>> + *
>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef _MEDIA_V4L2_REQUEST_H
>> +#define _MEDIA_V4L2_REQUEST_H
>> +
>> +#include <linux/kconfig.h>
>> +#include <media/media-request.h>
>> +
>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>> +
>> +#include <linux/list.h>
>> +
>> +#include <media/videobuf2-core.h>
>> +#include <media/v4l2-ctrls.h>
>> +
>> +/**
>> + * struct v4l2_request_entity - entity used with V4L2 instances
>> + *
>> + * @base:    base media_request_entity struct
>> + * @vdev:    video device that this entity represents
>> + *
>> + * This structure is used by V4L2 devices that support being controlled
>> + * by requests. If should be added to the device-specific structure that the
>
> If -> It

Fixed.

>
>> + * driver wishes to control using requests.
>> + *
>> + * V4L2 request entities are able to receive queued buffers using vb2 queues,
>> + * and control settings using the control framework.

I noticed the current documentation of this structure is misleading.
v4l2_request_entity_data is the structure that allows queuing buffers
and setting controls to a V4L2 device. It does not necessarily need to
be looked up through a v4l2_request_entity. This is important for
media controller support, as in that case V4L2 drivers under a mc will
use mc_request_entity instead of v4l2_request_entity.

I also understand that this whole file may be a bit misleading as it
takes care of two different things:

1) Allowing V4L2 devices to have their QBUF and S/G/TRY_EXT_CTRLS
ioctls stored in requests (struct v4l2_request_entity_data and related
functions).
2) Allowing V4L2 devices to allocate simple requests via the
VIDIOC_NEW_REQUEST ioctl (struct v4l2_request and
v4l2_request_entity).

Maybe this should be split into two source files, and driver support
for both features be split into different patches as well?

>> + *
>> + */
>> +struct v4l2_request_entity {
>> +     struct media_request_entity base;
>> +     struct video_device *vdev;
>> +};
>> +#define to_v4l2_entity(e) container_of(e, struct v4l2_request_entity, base)
>> +
>> +/**
>> + * v4l2_request_entity_init() - initialize a struct v4l2_request_entity
>> + *
>> + * @entity:  entity to initialize
>> + * @ops:     entity ops to use
>> + * @vdev:    video device represented by this entity
>> + */
>> +void v4l2_request_entity_init(struct v4l2_request_entity *entity,
>> +                           const struct media_request_entity_ops *ops,
>> +                           struct video_device *vdev);
>> +
>> +/**
>> + * struct v4l2_vb2_request_buffer - record buffer queue on behalf of a request
>> + *
>> + * @queue:           vb2 queue
>> + * @pre_req_state:   keep track of the pre-QBUF state of the buffer
>> + * @v4l2_buf:                user-space buffer queue ioctl data
>> + * @node:            entry into v4l2_request_entity_data::queued_buffers
>> + */
>> +struct v4l2_vb2_request_buffer {
>> +     struct vb2_queue *queue;
>> +     enum vb2_buffer_state pre_req_state;
>> +     struct v4l2_buffer v4l2_buf;
>> +     struct list_head node;
>> +};
>> +
>> +/**
>> + * struct v4l2_request_entity_data - per-request data for V4L2 entities
>> + *
>> + * @base:            base entity data structure
>> + * @ctrls:           record of controls set for this request
>> + * @queued_buffers:  record of buffers queued for this request
>> + */
>> +struct v4l2_request_entity_data {
>> +     struct media_request_entity_data base;
>> +     struct v4l2_ctrl_handler ctrls;
>
> Please call this field either 'hdl' or 'ctrl_handler'. 'ctrls' is very
> confusing. That way I know it represents a control handler and not a
> list or array of controls.

Sure.

>
>> +     struct list_head queued_buffers;
>> +};
>> +static inline struct v4l2_request_entity_data *
>> +to_v4l2_entity_data(struct media_request_entity_data *data)
>> +{
>> +     if (IS_ERR(data))
>> +             return (struct v4l2_request_entity_data *)data;
>> +
>> +     return container_of(data, struct v4l2_request_entity_data, base);
>> +}
>> +
>> +/**
>> + * v4l2_request_entity_data_alloc() - allocate data for a V4L2 entity
>> + *
>> + * @req:     request to allocate for
>> + * @hdl:     control handler of the device we will be controlling
>> + *
>> + * Helper function to be used from the media_request_entity_ops::data_alloc
>> + * hook.
>> + */
>> +struct media_request_entity_data *
>> +v4l2_request_entity_data_alloc(struct media_request *req,
>> +                            struct v4l2_ctrl_handler *hdl);
>> +
>> +/**
>> + * v4l2_request_entity_data_free() - free per-request data of an entity
>> + *
>> + * @data:    entity data to free
>> + *
>> + * Helper function to be usedfrom the media_request_entity_ops::data_free
>> + * hook.
>> + */
>> +void
>> +v4l2_request_entity_data_free(struct media_request_entity_data *_data);
>> +
>> +
>> +
>> +
>> +
>> +/**
>> + * struct v4l2_request_mgr - request manager producing requests suitable
>> + *                        for managing single v4l2 devices.
>> + *
>> + * @base:    base manager structure
>> + * @vdev:    device that our requests can control
>> + */
>> +struct v4l2_request_mgr {
>> +     struct media_request_mgr base;
>> +     struct video_device *vdev;
>> +};
>> +
>> +/**
>> + * v4l2_request_mgr_init() - initialize a v4l2_request_mgr
>> + *
>> + * @mgr:     manager to initialize
>> + * @vdev:    video device that our instances will control
>> + * @ops:     used to override ops if needed. &v4l2_request_ops is a good
>> + *           default
>> + */
>> +void v4l2_request_mgr_init(struct v4l2_request_mgr *mgr,
>> +                       struct video_device *vdev,
>> +                       const struct media_request_ops *ops);
>> +
>> +/**
>> + * v4l2_request_mgr_free() - free a v4l2 request manager
>> + *
>> + * @mgr:     manager to free
>> + */
>> +void v4l2_request_mgr_free(struct v4l2_request_mgr *mgr);
>> +
>> +extern const struct media_request_ops v4l2_request_ops;
>> +
>> +#endif /* CONFIG_MEDIA_REQUEST_API */
>> +
>> +#endif
>>
>
> I'm not convinced by some of the naming, but I'll get back to that later.
>
> Also very unclear is which objects here are refcounted and which have to
> be manually freed. My control handler patch series adds a kref to struct
> v4l2_ctrl_handler, but that isn't used AFAICT.

Right. I overlooked it to be honest, and for now it does not seem to
be necessary since memory management is performed at the level of
v4l2_request_entity_data. But maybe we will need this when requests
start referencing each-other's controls.

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

* Re: [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer
  2018-02-20 15:20   ` Hans Verkuil
@ 2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-21  6:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML, Hans Verkuil

On Wed, Feb 21, 2018 at 12:20 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/18 05:44, Alexandre Courbot wrote:
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> When queuing buffers allow for passing the request that should
>> be associated with this buffer.
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> [acourbot@chromium.org: make request ID 32-bit]
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  drivers/media/common/videobuf2/videobuf2-v4l2.c | 2 +-
>>  drivers/media/usb/cpia2/cpia2_v4l.c             | 2 +-
>>  drivers/media/v4l2-core/v4l2-compat-ioctl32.c   | 9 ++++++---
>>  drivers/media/v4l2-core/v4l2-ioctl.c            | 4 ++--
>>  include/uapi/linux/videodev2.h                  | 3 ++-
>>  5 files changed, 12 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> index 886a2d8d5c6c..6d4d184aa68e 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> @@ -203,7 +203,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
>>       b->timestamp = ns_to_timeval(vb->timestamp);
>>       b->timecode = vbuf->timecode;
>>       b->sequence = vbuf->sequence;
>> -     b->reserved2 = 0;
>> +     b->request_fd = 0;
>>       b->reserved = 0;
>>
>>       if (q->is_multiplanar) {
>> diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
>> index 99f106b13280..af42ce3ceb48 100644
>> --- a/drivers/media/usb/cpia2/cpia2_v4l.c
>> +++ b/drivers/media/usb/cpia2/cpia2_v4l.c
>> @@ -948,7 +948,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
>>       buf->sequence = cam->buffers[buf->index].seq;
>>       buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer;
>>       buf->length = cam->frame_size;
>> -     buf->reserved2 = 0;
>> +     buf->request_fd = 0;
>>       buf->reserved = 0;
>>       memset(&buf->timecode, 0, sizeof(buf->timecode));
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
>> index 5198c9eeb348..32bf47489a2e 100644
>> --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
>> +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
>> @@ -386,7 +386,7 @@ struct v4l2_buffer32 {
>>               __s32           fd;
>>       } m;
>>       __u32                   length;
>> -     __u32                   reserved2;
>> +     __s32                   request_fd;
>>       __u32                   reserved;
>>  };
>>
>> @@ -486,6 +486,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
>>  {
>>       u32 type;
>>       u32 length;
>> +     s32 request_fd;
>>       enum v4l2_memory memory;
>>       struct v4l2_plane32 __user *uplane32;
>>       struct v4l2_plane __user *uplane;
>> @@ -500,7 +501,9 @@ static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
>>           get_user(memory, &up->memory) ||
>>           put_user(memory, &kp->memory) ||
>>           get_user(length, &up->length) ||
>> -         put_user(length, &kp->length))
>> +         put_user(length, &kp->length) ||
>> +         get_user(request_fd, &up->request_fd) ||
>> +         put_user(request_fd, &kp->request_fd))
>>               return -EFAULT;
>>
>>       if (V4L2_TYPE_IS_OUTPUT(type))
>> @@ -604,7 +607,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
>>           assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
>>           copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
>>           assign_in_user(&up->sequence, &kp->sequence) ||
>> -         assign_in_user(&up->reserved2, &kp->reserved2) ||
>> +         assign_in_user(&up->request_fd, &kp->request_fd) ||
>>           assign_in_user(&up->reserved, &kp->reserved) ||
>>           get_user(length, &kp->length) ||
>>           put_user(length, &up->length))
>> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
>> index 260288ca4f55..7bfeaf233d5a 100644
>> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
>> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
>> @@ -437,13 +437,13 @@ static void v4l_print_buffer(const void *arg, bool write_only)
>>       const struct v4l2_plane *plane;
>>       int i;
>>
>> -     pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s",
>> +     pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, request_fd=%u, flags=0x%08x, field=%s, sequence=%d, memory=%s",
>>                       p->timestamp.tv_sec / 3600,
>>                       (int)(p->timestamp.tv_sec / 60) % 60,
>>                       (int)(p->timestamp.tv_sec % 60),
>>                       (long)p->timestamp.tv_usec,
>>                       p->index,
>> -                     prt_names(p->type, v4l2_type_names),
>> +                     prt_names(p->type, v4l2_type_names), p->request_fd,
>>                       p->flags, prt_names(p->field, v4l2_field_names),
>>                       p->sequence, prt_names(p->memory, v4l2_memory_names));
>>
>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>> index 982718965180..4fd46ae8fad5 100644
>> --- a/include/uapi/linux/videodev2.h
>> +++ b/include/uapi/linux/videodev2.h
>> @@ -909,6 +909,7 @@ struct v4l2_plane {
>>   * @length:  size in bytes of the buffer (NOT its payload) for single-plane
>>   *           buffers (when type != *_MPLANE); number of elements in the
>>   *           planes array for multi-plane buffers
>> + * @request_fd: fd of the request that this buffer should use
>>   *
>>   * Contains data exchanged by application and driver using one of the Streaming
>>   * I/O methods.
>> @@ -932,7 +933,7 @@ struct v4l2_buffer {
>>               __s32           fd;
>>       } m;
>>       __u32                   length;
>> -     __u32                   reserved2;
>> +     __s32                   request_fd;
>
> This should be:
>
>         union {
>                 __s32           request_fd;
>                 __u32           reserved2;
>         };
>
> Otherwise any existing application that sets 'reserved2 = 0;' would fail.
> I encountered this issue when compiling v4l-utils.

Fixed, thanks!

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

* Re: [RFCv4 11/21] media: v4l2_fh: add request entity field
  2018-02-20 15:24   ` Hans Verkuil
@ 2018-02-21  6:01     ` Alexandre Courbot
  0 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-21  6:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On Wed, Feb 21, 2018 at 12:24 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/18 05:44, Alexandre Courbot wrote:
>> Allow drivers to assign a request entity to v4l2_fh. This will be useful
>> for request-aware ioctls to find out which request entity to use.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  include/media/v4l2-fh.h | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
>> index ea73fef8bdc0..f54cb319dd64 100644
>> --- a/include/media/v4l2-fh.h
>> +++ b/include/media/v4l2-fh.h
>> @@ -28,6 +28,7 @@
>>
>>  struct video_device;
>>  struct v4l2_ctrl_handler;
>> +struct media_request_entity;
>>
>>  /**
>>   * struct v4l2_fh - Describes a V4L2 file handler
>> @@ -43,6 +44,7 @@ struct v4l2_ctrl_handler;
>>   * @navailable: number of available events at @available list
>>   * @sequence: event sequence number
>>   * @m2m_ctx: pointer to &struct v4l2_m2m_ctx
>> + * @entity: the request entity this fh operates on behalf of
>>   */
>>  struct v4l2_fh {
>>       struct list_head        list;
>> @@ -60,6 +62,7 @@ struct v4l2_fh {
>>  #if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
>>       struct v4l2_m2m_ctx     *m2m_ctx;
>>  #endif
>> +     struct media_request_entity *entity;
>
> The name 'media_request_entity' is very confusing.
>
> In the media controller API terminology an entity represents a piece
> of hardware with inputs and outputs (very rough description), but a
> request is not an entity. It may be associated with an entity, though.
>
> So calling this field 'entity' is also very misleading.

Note that this field is not a request though, it is a pointer to a
piece of hardware referenced by a request, which is closer to the MC
terminology. Or do you mean this should just be renamed
"request_entity"?

If we go all the way, the media_ prefix is also misleading - it
implies a dependency to the media controller framework, while there is
none (in this patchset at least).

However I thought that 'request' alone (instead of media_request) may
name-conflict with something else, and since 'media' is also the
umbrella term for anything under drivers/media it sounds fitting on
the other hand. Suggestions are welcome though.

>
> As with previous patches, I'll have to think about this and try and
> come up with better, less confusing names.

I will gladly take suggestions, have been trying to come with a better
name to reply to your comment above but could not find any. :)

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

* Re: [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-20 16:18   ` Hans Verkuil
@ 2018-02-21  6:01     ` Alexandre Courbot
  2018-02-23  6:34     ` Tomasz Figa
  1 sibling, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-21  6:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On Wed, Feb 21, 2018 at 1:18 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
>> that request-aware drivers can call to queue a buffer into a request
>> instead of directly into the vb2 queue if relevent.
>>
>> This function expects that drivers invoking it are using instances of
>> v4l2_request_entity and v4l2_request_entity_data to describe their
>> entity and entity data respectively.
>>
>> Also add the vb2_request_submit() helper function which drivers can
>> invoke in order to queue all the buffers previously queued into a
>> request into the regular vb2 queue.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
>>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>>  2 files changed, 187 insertions(+), 1 deletion(-)
>>
>
> <snip>
>
>> @@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
>>  int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
>>  {
>>       struct video_device *vdev = video_devdata(file);
>> +     struct v4l2_fh *fh = NULL;
>> +
>> +     if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
>> +             fh = file->private_data;
>
> No need for this. All drivers using vb2 will also use v4l2_fh.

Fixed.

>
>>
>>       if (vb2_queue_is_busy(vdev, file))
>>               return -EBUSY;
>> -     return vb2_qbuf(vdev->queue, p);
>> +     return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
>>  }
>>  EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
>>
>> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
>> index 3d5e2d739f05..d4dfa266a0da 100644
>> --- a/include/media/videobuf2-v4l2.h
>> +++ b/include/media/videobuf2-v4l2.h
>> @@ -23,6 +23,12 @@
>>  #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
>>  #endif
>>
>> +struct media_entity;
>> +struct v4l2_fh;
>> +struct media_request;
>> +struct media_request_entity;
>> +struct v4l2_request_entity_data;
>> +
>>  /**
>>   * struct vb2_v4l2_buffer - video buffer information for v4l2.
>>   *
>> @@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
>>   */
>>  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
>>
>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>> +
>> +/**
>> + * vb2_qbuf_request() - Queue a buffer, with request support
>> + * @q:               pointer to &struct vb2_queue with videobuf2 queue.
>> + * @b:               buffer structure passed from userspace to
>> + *           &v4l2_ioctl_ops->vidioc_qbuf handler in driver
>> + * @entity:  request entity to queue for if requests are used.
>> + *
>> + * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
>> + *
>> + * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
>> + *
>> + * If the request_fd member of b is set, then the buffer represented by b is
>> + * queued in the request instead of the vb2 queue. The buffer will be passed
>> + * to the vb2 queue when the request is submitted.
>
> I would definitely also prepare the buffer at this time. That way you'll see any
> errors relating to the prepare early on.

I was wondering about that, so glad to have your opinion on this. Will
make sure buffers are prepared before queuing them to a request.

>
>> + *
>> + * The return values from this function are intended to be directly returned
>> + * from &v4l2_ioctl_ops->vidioc_qbuf handler in driver.
>> + */
>> +int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
>> +                  struct media_request_entity *entity);
>> +
>> +/**
>> + * vb2_request_submit() - Queue all the buffers in a v4l2 request.
>> + * @data:    request entity data to queue buffers of
>> + *
>> + * This function should be called from the media_request_entity_ops::submit
>> + * hook for instances of media_request_v4l2_entity_data. It will immediately
>> + * queue all the request-bound buffers to their respective vb2 queues.
>> + *
>> + * Errors from vb2_core_qbuf() are returned if something happened. Also, since
>> + * v4l2 request entities require at least one buffer for the request to trigger,
>> + * this function will return -EINVAL if no buffer have been bound at all for
>> + * this entity.
>> + */
>> +int vb2_request_submit(struct v4l2_request_entity_data *data);
>> +
>> +#else /* CONFIG_MEDIA_REQUEST_API */
>> +
>> +static inline int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
>> +                                struct media_request_entity *entity)
>> +{
>> +     return vb2_qbuf(q, b);
>> +}
>> +
>> +static inline int vb2_request_submit(struct v4l2_request_entity_data *data)
>> +{
>> +     return -ENOTSUPP;
>> +}
>> +
>> +#endif /* CONFIG_MEDIA_REQUEST_API */
>> +
>>  /**
>>   * vb2_expbuf() - Export a buffer as a file descriptor
>>   * @q:               pointer to &struct vb2_queue with videobuf2 queue.
>>
>
> Regards,
>
>         Hans

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

* Re: [RFCv4 16/21] v4l2: video_device: support for creating requests
  2018-02-20 16:35   ` Hans Verkuil
@ 2018-02-21  6:01     ` Alexandre Courbot
  2018-02-21  7:37       ` Hans Verkuil
  0 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-21  6:01 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On Wed, Feb 21, 2018 at 1:35 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>> Add a new VIDIOC_NEW_REQUEST ioctl, which allows to instanciate requests
>> on devices that support the request API. Requests created that way can
>> only control the device they originate from, making them suitable for
>> simple devices, but not complex pipelines.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  Documentation/ioctl/ioctl-number.txt |  1 +
>>  drivers/media/v4l2-core/v4l2-dev.c   |  2 ++
>>  drivers/media/v4l2-core/v4l2-ioctl.c | 25 +++++++++++++++++++++++++
>>  include/media/v4l2-dev.h             |  2 ++
>>  include/uapi/linux/videodev2.h       |  3 +++
>>  5 files changed, 33 insertions(+)
>>
>> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
>> index 6501389d55b9..afdc9ed255b0 100644
>> --- a/Documentation/ioctl/ioctl-number.txt
>> +++ b/Documentation/ioctl/ioctl-number.txt
>> @@ -286,6 +286,7 @@ Code  Seq#(hex)   Include File            Comments
>>                                       <mailto:oe@port.de>
>>  'z'  10-4F   drivers/s390/crypto/zcrypt_api.h        conflict!
>>  '|'  00-7F   linux/media.h
>> +'|'  80-9F   linux/media-request.h
>>  0x80 00-1F   linux/fb.h
>>  0x89 00-06   arch/x86/include/asm/sockios.h
>>  0x89 0B-DF   linux/sockios.h
>
> This ^^^^ doesn't belong in this patch.

Do you mean we need a separate patch for this?

>
>> diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
>> index 0301fe426a43..062ebee5bffc 100644
>> --- a/drivers/media/v4l2-core/v4l2-dev.c
>> +++ b/drivers/media/v4l2-core/v4l2-dev.c
>> @@ -559,6 +559,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
>>               set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
>>       if (vdev->ctrl_handler || ops->vidioc_querymenu)
>>               set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
>> +     if (vdev->req_mgr)
>> +             set_bit(_IOC_NR(VIDIOC_NEW_REQUEST), valid_ioctls);
>>       SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
>>       SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
>>       SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
>> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
>> index ab4968ea443f..a45fe078f8ae 100644
>> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
>> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
>> @@ -21,6 +21,7 @@
>>
>>  #include <linux/videodev2.h>
>>
>> +#include <media/media-request.h>
>>  #include <media/v4l2-common.h>
>>  #include <media/v4l2-ioctl.h>
>>  #include <media/v4l2-ctrls.h>
>> @@ -842,6 +843,13 @@ static void v4l_print_freq_band(const void *arg, bool write_only)
>>                       p->rangehigh, p->modulation);
>>  }
>>
>> +static void vidioc_print_new_request(const void *arg, bool write_only)
>> +{
>> +     const struct media_request_new *new = arg;
>> +
>> +     pr_cont("fd=0x%x\n", new->fd);
>
> I'd use %d since fds are typically shown as signed integers.

Right.

>
>> +}
>> +
>>  static void v4l_print_edid(const void *arg, bool write_only)
>>  {
>>       const struct v4l2_edid *p = arg;
>> @@ -2486,6 +2494,22 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
>>       return -ENOTTY;
>>  }
>>
>> +static int vidioc_new_request(const struct v4l2_ioctl_ops *ops,
>> +                           struct file *file, void *fh, void *arg)
>> +{
>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>> +     struct media_request_new *new = arg;
>> +     struct video_device *vfd = video_devdata(file);
>> +
>> +     if (!vfd->req_mgr)
>> +             return -ENOTTY;
>> +
>> +     return media_request_ioctl_new(vfd->req_mgr, new);
>> +#else
>> +     return -ENOTTY;
>> +#endif
>> +}
>
> You don't need the #ifdef's here. media_request_ioctl_new() will be stubbed if
> CONFIG_MEDIA_REQUEST_API isn't set.

Correct.

>
>> +
>>  struct v4l2_ioctl_info {
>>       unsigned int ioctl;
>>       u32 flags;
>> @@ -2617,6 +2641,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
>>       IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
>>       IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
>>       IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
>> +     IOCTL_INFO_FNC(VIDIOC_NEW_REQUEST, vidioc_new_request, vidioc_print_new_request, 0),
>>  };
>>  #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
>>
>> diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
>> index 53f32022fabe..e6c4e10889bc 100644
>> --- a/include/media/v4l2-dev.h
>> +++ b/include/media/v4l2-dev.h
>> @@ -209,6 +209,7 @@ struct v4l2_file_operations {
>>   * @entity: &struct media_entity
>>   * @intf_devnode: pointer to &struct media_intf_devnode
>>   * @pipe: &struct media_pipeline
>> + * @req_mgr: request manager to use if this device supports creating requests
>>   * @fops: pointer to &struct v4l2_file_operations for the video device
>>   * @device_caps: device capabilities as used in v4l2_capabilities
>>   * @dev: &struct device for the video device
>> @@ -251,6 +252,7 @@ struct video_device
>>       struct media_intf_devnode *intf_devnode;
>>       struct media_pipeline pipe;
>>  #endif
>> +     struct media_request_mgr *req_mgr;
>>       const struct v4l2_file_operations *fops;
>>
>>       u32 device_caps;
>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>> index 91cfe0cbd5c5..35706204e81d 100644
>> --- a/include/uapi/linux/videodev2.h
>> +++ b/include/uapi/linux/videodev2.h
>> @@ -63,6 +63,7 @@
>>  #include <linux/compiler.h>
>>  #include <linux/ioctl.h>
>>  #include <linux/types.h>
>> +#include <linux/media-request.h>
>>  #include <linux/v4l2-common.h>
>>  #include <linux/v4l2-controls.h>
>>
>> @@ -2407,6 +2408,8 @@ struct v4l2_create_buffers {
>>
>>  #define VIDIOC_QUERY_EXT_CTRL        _IOWR('V', 103, struct v4l2_query_ext_ctrl)
>>
>> +#define VIDIOC_NEW_REQUEST   _IOWR('V', 104, struct media_request_new)
>
> Hmm, I probably call this VIDIOC_CREATE_REQUEST (analogous to CREATE_BUFS).
> Ditto struct media_create_request and MEDIA_IOC_CREATE_REQUEST.

Agree, it is better to keep consistency somehow.

>
> I'm still not convinced this is the right approach (as opposed to using the media
> device node). I plan to dig deeper into the data structures tomorrow morning.

I see no reason why this would not work. This seems more elegant than
relying on the media node for this, and also does not require pulling
the whole media controller support just to use requests on a simple
codec or m2m device.

But of course, I may not be seeing everything. :)

Thanks for the review!
Alex.

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

* Re: [RFCv4 01/21] media: add request API core and UAPI
  2018-02-21  6:01     ` Alexandre Courbot
@ 2018-02-21  7:29       ` Hans Verkuil
  2018-02-22  9:30         ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-21  7:29 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On 02/21/2018 07:01 AM, Alexandre Courbot wrote:
> Hi Hans,
> 
> On Tue, Feb 20, 2018 at 7:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/20/18 05:44, Alexandre Courbot wrote:

<snip>

>>> +#define MEDIA_REQUEST_IOC(__cmd, func)                                       \
>>> +     [_IOC_NR(MEDIA_REQUEST_IOC_##__cmd) - 0x80] = {                 \
>>> +             .cmd = MEDIA_REQUEST_IOC_##__cmd,                       \
>>> +             .fn = func,                                             \
>>> +     }
>>> +
>>> +struct media_request_ioctl_info {
>>> +     unsigned int cmd;
>>> +     long (*fn)(struct media_request *req);
>>> +};
>>> +
>>> +static const struct media_request_ioctl_info ioctl_info[] = {
>>> +     MEDIA_REQUEST_IOC(SUBMIT, media_request_ioctl_submit),
>>> +     MEDIA_REQUEST_IOC(REINIT, media_request_ioctl_reinit),
>>
>> There are only two ioctls, so there is really no need for the
>> MEDIA_REQUEST_IOC define. Just keep it simple.
> 
> The number of times it is used doesn't change the fact that it helps
> with readability IMHO.

But this macro just boils down to:

static const struct media_request_ioctl_info ioctl_info[] = {
	{ MEDIA_REQUEST_IOC_SUBMIT, media_request_ioctl_submit },
	{ MEDIA_REQUEST_IOC_REINIT, media_request_ioctl_reinit },
};

It's absolutely identical! So it seems senseless to me.

> 
>>
>>> +};
>>> +
>>> +static long media_request_ioctl(struct file *filp, unsigned int cmd,
>>> +                             unsigned long __arg)
>>> +{
>>> +     struct media_request *req = filp->private_data;
>>> +     const struct media_request_ioctl_info *info;
>>> +
>>> +     if ((_IOC_NR(cmd) < 0x80) ||
>>
>> Why start the ioctl number at 0x80? Why not just 0?
>> It avoids all this hassle with the 0x80 offset.

There is no clash with the MC ioctls, so I really don't believe the 0x80
offset is needed.

>>
>>> +          _IOC_NR(cmd) >= 0x80 + ARRAY_SIZE(ioctl_info) ||
>>> +          ioctl_info[_IOC_NR(cmd) - 0x80].cmd != cmd)
>>> +             return -ENOIOCTLCMD;
>>> +
>>> +     info = &ioctl_info[_IOC_NR(cmd) - 0x80];
>>> +
>>> +     return info->fn(req);
>>> +}

<snip>

>>> diff --git a/include/uapi/linux/media-request.h b/include/uapi/linux/media-request.h
>>> new file mode 100644
>>> index 000000000000..5d30f731a442
>>> --- /dev/null
>>> +++ b/include/uapi/linux/media-request.h
>>> @@ -0,0 +1,37 @@
>>> +/*
>>> + * Media requests UAPI
>>> + *
>>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + */
>>> +
>>> +#ifndef __LINUX_MEDIA_REQUEST_H
>>> +#define __LINUX_MEDIA_REQUEST_H
>>> +
>>> +#ifndef __KERNEL__
>>> +#include <stdint.h>
>>> +#endif
>>> +#include <linux/ioctl.h>
>>> +#include <linux/types.h>
>>> +#include <linux/version.h>
>>> +
>>> +/* Only check that requests can be used, do not allocate */
>>> +#define MEDIA_REQUEST_FLAG_TEST                      0x00000001
>>> +
>>> +struct media_request_new {
>>> +     __u32 flags;
>>> +     __s32 fd;
>>> +} __attribute__ ((packed));
>>> +
>>> +#define MEDIA_REQUEST_IOC_SUBMIT       _IO('|',  128)
>>> +#define MEDIA_REQUEST_IOC_REINIT       _IO('|',  129)
>>> +
>>> +#endif
>>>
>>
>> I need to think a bit more on this internal API, so I might come back
>> to this patch for more comments.
> 
> I think I should probably elaborate on why I think it is advantageous
> to have these ioctls handled here.

Sorry for the confusion, I was not actually referring to these ioctls.
In fact, I really like them. It was more a general comment about the
request API core.

I should have been more clear.

Regards,

	Hans

> 
> One of the reasons if that it does not force user-space to keep track
> of who issued the request to operate on it. Semantically, the only
> device a request could be submitted to is the device that produced it
> anyway, so since that argument is constant we may as well get rid of
> it (and we also don't need to pass the request FD as argument
> anymore).
> 
> It also gives us more freedom when designing new request-related
> ioctls: before, all request-related operations were multiplexed under
> a single MEDIA_IOC_REQUEST_CMD ioctl, which cmd field indicated the
> actual operation to perform. With this design, all the arguments must
> fit within the media_request_cmd structure, which may cause confusion
> as it will have to be variable-sized. I am thinking in particular
> about a future atomic-like API to set topology, controls and buffers
> related to a request all at the same time. Having it as a request
> ioctl seems perfectly fitting to me.
> 

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

* Re: [RFCv4 16/21] v4l2: video_device: support for creating requests
  2018-02-21  6:01     ` Alexandre Courbot
@ 2018-02-21  7:37       ` Hans Verkuil
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Verkuil @ 2018-02-21  7:37 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On 02/21/2018 07:01 AM, Alexandre Courbot wrote:
> On Wed, Feb 21, 2018 at 1:35 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>>> Add a new VIDIOC_NEW_REQUEST ioctl, which allows to instanciate requests
>>> on devices that support the request API. Requests created that way can
>>> only control the device they originate from, making them suitable for
>>> simple devices, but not complex pipelines.
>>>
>>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>>> ---
>>>  Documentation/ioctl/ioctl-number.txt |  1 +
>>>  drivers/media/v4l2-core/v4l2-dev.c   |  2 ++
>>>  drivers/media/v4l2-core/v4l2-ioctl.c | 25 +++++++++++++++++++++++++
>>>  include/media/v4l2-dev.h             |  2 ++
>>>  include/uapi/linux/videodev2.h       |  3 +++
>>>  5 files changed, 33 insertions(+)
>>>
>>> diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
>>> index 6501389d55b9..afdc9ed255b0 100644
>>> --- a/Documentation/ioctl/ioctl-number.txt
>>> +++ b/Documentation/ioctl/ioctl-number.txt
>>> @@ -286,6 +286,7 @@ Code  Seq#(hex)   Include File            Comments
>>>                                       <mailto:oe@port.de>
>>>  'z'  10-4F   drivers/s390/crypto/zcrypt_api.h        conflict!
>>>  '|'  00-7F   linux/media.h
>>> +'|'  80-9F   linux/media-request.h
>>>  0x80 00-1F   linux/fb.h
>>>  0x89 00-06   arch/x86/include/asm/sockios.h
>>>  0x89 0B-DF   linux/sockios.h
>>
>> This ^^^^ doesn't belong in this patch.
> 
> Do you mean we need a separate patch for this?

Yes.

I now also see why you started at 0x80. Let's keep that for now.

> 
>>
>>> diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
>>> index 0301fe426a43..062ebee5bffc 100644
>>> --- a/drivers/media/v4l2-core/v4l2-dev.c
>>> +++ b/drivers/media/v4l2-core/v4l2-dev.c
>>> @@ -559,6 +559,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
>>>               set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
>>>       if (vdev->ctrl_handler || ops->vidioc_querymenu)
>>>               set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
>>> +     if (vdev->req_mgr)
>>> +             set_bit(_IOC_NR(VIDIOC_NEW_REQUEST), valid_ioctls);
>>>       SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
>>>       SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
>>>       SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
>>> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
>>> index ab4968ea443f..a45fe078f8ae 100644
>>> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
>>> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
>>> @@ -21,6 +21,7 @@
>>>
>>>  #include <linux/videodev2.h>
>>>
>>> +#include <media/media-request.h>
>>>  #include <media/v4l2-common.h>
>>>  #include <media/v4l2-ioctl.h>
>>>  #include <media/v4l2-ctrls.h>
>>> @@ -842,6 +843,13 @@ static void v4l_print_freq_band(const void *arg, bool write_only)
>>>                       p->rangehigh, p->modulation);
>>>  }
>>>
>>> +static void vidioc_print_new_request(const void *arg, bool write_only)
>>> +{
>>> +     const struct media_request_new *new = arg;
>>> +
>>> +     pr_cont("fd=0x%x\n", new->fd);
>>
>> I'd use %d since fds are typically shown as signed integers.
> 
> Right.
> 
>>
>>> +}
>>> +
>>>  static void v4l_print_edid(const void *arg, bool write_only)
>>>  {
>>>       const struct v4l2_edid *p = arg;
>>> @@ -2486,6 +2494,22 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
>>>       return -ENOTTY;
>>>  }
>>>
>>> +static int vidioc_new_request(const struct v4l2_ioctl_ops *ops,
>>> +                           struct file *file, void *fh, void *arg)
>>> +{
>>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>>> +     struct media_request_new *new = arg;
>>> +     struct video_device *vfd = video_devdata(file);
>>> +
>>> +     if (!vfd->req_mgr)
>>> +             return -ENOTTY;
>>> +
>>> +     return media_request_ioctl_new(vfd->req_mgr, new);
>>> +#else
>>> +     return -ENOTTY;
>>> +#endif
>>> +}
>>
>> You don't need the #ifdef's here. media_request_ioctl_new() will be stubbed if
>> CONFIG_MEDIA_REQUEST_API isn't set.
> 
> Correct.
> 
>>
>>> +
>>>  struct v4l2_ioctl_info {
>>>       unsigned int ioctl;
>>>       u32 flags;
>>> @@ -2617,6 +2641,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
>>>       IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
>>>       IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
>>>       IOCTL_INFO_FNC(VIDIOC_QUERY_EXT_CTRL, v4l_query_ext_ctrl, v4l_print_query_ext_ctrl, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_query_ext_ctrl, id)),
>>> +     IOCTL_INFO_FNC(VIDIOC_NEW_REQUEST, vidioc_new_request, vidioc_print_new_request, 0),
>>>  };
>>>  #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
>>>
>>> diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
>>> index 53f32022fabe..e6c4e10889bc 100644
>>> --- a/include/media/v4l2-dev.h
>>> +++ b/include/media/v4l2-dev.h
>>> @@ -209,6 +209,7 @@ struct v4l2_file_operations {
>>>   * @entity: &struct media_entity
>>>   * @intf_devnode: pointer to &struct media_intf_devnode
>>>   * @pipe: &struct media_pipeline
>>> + * @req_mgr: request manager to use if this device supports creating requests
>>>   * @fops: pointer to &struct v4l2_file_operations for the video device
>>>   * @device_caps: device capabilities as used in v4l2_capabilities
>>>   * @dev: &struct device for the video device
>>> @@ -251,6 +252,7 @@ struct video_device
>>>       struct media_intf_devnode *intf_devnode;
>>>       struct media_pipeline pipe;
>>>  #endif
>>> +     struct media_request_mgr *req_mgr;
>>>       const struct v4l2_file_operations *fops;
>>>
>>>       u32 device_caps;
>>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>>> index 91cfe0cbd5c5..35706204e81d 100644
>>> --- a/include/uapi/linux/videodev2.h
>>> +++ b/include/uapi/linux/videodev2.h
>>> @@ -63,6 +63,7 @@
>>>  #include <linux/compiler.h>
>>>  #include <linux/ioctl.h>
>>>  #include <linux/types.h>
>>> +#include <linux/media-request.h>
>>>  #include <linux/v4l2-common.h>
>>>  #include <linux/v4l2-controls.h>
>>>
>>> @@ -2407,6 +2408,8 @@ struct v4l2_create_buffers {
>>>
>>>  #define VIDIOC_QUERY_EXT_CTRL        _IOWR('V', 103, struct v4l2_query_ext_ctrl)
>>>
>>> +#define VIDIOC_NEW_REQUEST   _IOWR('V', 104, struct media_request_new)
>>
>> Hmm, I probably call this VIDIOC_CREATE_REQUEST (analogous to CREATE_BUFS).
>> Ditto struct media_create_request and MEDIA_IOC_CREATE_REQUEST.
> 
> Agree, it is better to keep consistency somehow.
> 
>>
>> I'm still not convinced this is the right approach (as opposed to using the media
>> device node). I plan to dig deeper into the data structures tomorrow morning.
> 
> I see no reason why this would not work. This seems more elegant than
> relying on the media node for this, and also does not require pulling
> the whole media controller support just to use requests on a simple
> codec or m2m device.
> 
> But of course, I may not be seeing everything. :)
> 
> Thanks for the review!
> Alex.
> 

Regards,

	Hans

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

* Re: [RFCv4 01/21] media: add request API core and UAPI
  2018-02-21  7:29       ` Hans Verkuil
@ 2018-02-22  9:30         ` Alexandre Courbot
  2018-02-22  9:38           ` Hans Verkuil
  0 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-02-22  9:30 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On Wed, Feb 21, 2018 at 4:29 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/21/2018 07:01 AM, Alexandre Courbot wrote:
>> Hi Hans,
>>
>> On Tue, Feb 20, 2018 at 7:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> On 02/20/18 05:44, Alexandre Courbot wrote:
>
> <snip>
>
>>>> +#define MEDIA_REQUEST_IOC(__cmd, func)                                       \
>>>> +     [_IOC_NR(MEDIA_REQUEST_IOC_##__cmd) - 0x80] = {                 \
>>>> +             .cmd = MEDIA_REQUEST_IOC_##__cmd,                       \
>>>> +             .fn = func,                                             \
>>>> +     }
>>>> +
>>>> +struct media_request_ioctl_info {
>>>> +     unsigned int cmd;
>>>> +     long (*fn)(struct media_request *req);
>>>> +};
>>>> +
>>>> +static const struct media_request_ioctl_info ioctl_info[] = {
>>>> +     MEDIA_REQUEST_IOC(SUBMIT, media_request_ioctl_submit),
>>>> +     MEDIA_REQUEST_IOC(REINIT, media_request_ioctl_reinit),
>>>
>>> There are only two ioctls, so there is really no need for the
>>> MEDIA_REQUEST_IOC define. Just keep it simple.
>>
>> The number of times it is used doesn't change the fact that it helps
>> with readability IMHO.
>
> But this macro just boils down to:
>
> static const struct media_request_ioctl_info ioctl_info[] = {
>         { MEDIA_REQUEST_IOC_SUBMIT, media_request_ioctl_submit },
>         { MEDIA_REQUEST_IOC_REINIT, media_request_ioctl_reinit },
> };
>
> It's absolutely identical! So it seems senseless to me.

This expands to more than that - the index needs to be offset by 0x80,
something we probably don't want to repeat every line.

>
>>
>>>
>>>> +};
>>>> +
>>>> +static long media_request_ioctl(struct file *filp, unsigned int cmd,
>>>> +                             unsigned long __arg)
>>>> +{
>>>> +     struct media_request *req = filp->private_data;
>>>> +     const struct media_request_ioctl_info *info;
>>>> +
>>>> +     if ((_IOC_NR(cmd) < 0x80) ||
>>>
>>> Why start the ioctl number at 0x80? Why not just 0?
>>> It avoids all this hassle with the 0x80 offset.
>
> There is no clash with the MC ioctls, so I really don't believe the 0x80
> offset is needed.

I suppose your comment in patch 16 supersedes this one. :)

>
>>>
>>>> +          _IOC_NR(cmd) >= 0x80 + ARRAY_SIZE(ioctl_info) ||
>>>> +          ioctl_info[_IOC_NR(cmd) - 0x80].cmd != cmd)
>>>> +             return -ENOIOCTLCMD;
>>>> +
>>>> +     info = &ioctl_info[_IOC_NR(cmd) - 0x80];
>>>> +
>>>> +     return info->fn(req);
>>>> +}
>
> <snip>
>
>>>> diff --git a/include/uapi/linux/media-request.h b/include/uapi/linux/media-request.h
>>>> new file mode 100644
>>>> index 000000000000..5d30f731a442
>>>> --- /dev/null
>>>> +++ b/include/uapi/linux/media-request.h
>>>> @@ -0,0 +1,37 @@
>>>> +/*
>>>> + * Media requests UAPI
>>>> + *
>>>> + * Copyright (C) 2018, The Chromium OS Authors.  All rights reserved.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope that it will be useful,
>>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> + * GNU General Public License for more details.
>>>> + */
>>>> +
>>>> +#ifndef __LINUX_MEDIA_REQUEST_H
>>>> +#define __LINUX_MEDIA_REQUEST_H
>>>> +
>>>> +#ifndef __KERNEL__
>>>> +#include <stdint.h>
>>>> +#endif
>>>> +#include <linux/ioctl.h>
>>>> +#include <linux/types.h>
>>>> +#include <linux/version.h>
>>>> +
>>>> +/* Only check that requests can be used, do not allocate */
>>>> +#define MEDIA_REQUEST_FLAG_TEST                      0x00000001
>>>> +
>>>> +struct media_request_new {
>>>> +     __u32 flags;
>>>> +     __s32 fd;
>>>> +} __attribute__ ((packed));
>>>> +
>>>> +#define MEDIA_REQUEST_IOC_SUBMIT       _IO('|',  128)
>>>> +#define MEDIA_REQUEST_IOC_REINIT       _IO('|',  129)
>>>> +
>>>> +#endif
>>>>
>>>
>>> I need to think a bit more on this internal API, so I might come back
>>> to this patch for more comments.
>>
>> I think I should probably elaborate on why I think it is advantageous
>> to have these ioctls handled here.
>
> Sorry for the confusion, I was not actually referring to these ioctls.
> In fact, I really like them. It was more a general comment about the
> request API core.
>
> I should have been more clear.
>
> Regards,
>
>         Hans
>
>>
>> One of the reasons if that it does not force user-space to keep track
>> of who issued the request to operate on it. Semantically, the only
>> device a request could be submitted to is the device that produced it
>> anyway, so since that argument is constant we may as well get rid of
>> it (and we also don't need to pass the request FD as argument
>> anymore).
>>
>> It also gives us more freedom when designing new request-related
>> ioctls: before, all request-related operations were multiplexed under
>> a single MEDIA_IOC_REQUEST_CMD ioctl, which cmd field indicated the
>> actual operation to perform. With this design, all the arguments must
>> fit within the media_request_cmd structure, which may cause confusion
>> as it will have to be variable-sized. I am thinking in particular
>> about a future atomic-like API to set topology, controls and buffers
>> related to a request all at the same time. Having it as a request
>> ioctl seems perfectly fitting to me.
>>
>

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

* Re: [RFCv4 01/21] media: add request API core and UAPI
  2018-02-22  9:30         ` Alexandre Courbot
@ 2018-02-22  9:38           ` Hans Verkuil
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Verkuil @ 2018-02-22  9:38 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mauro Carvalho Chehab, Laurent Pinchart, Pawel Osciak,
	Marek Szyprowski, Tomasz Figa, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, LKML

On 02/22/18 10:30, Alexandre Courbot wrote:
> On Wed, Feb 21, 2018 at 4:29 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/21/2018 07:01 AM, Alexandre Courbot wrote:
>>> Hi Hans,
>>>
>>> On Tue, Feb 20, 2018 at 7:36 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>> On 02/20/18 05:44, Alexandre Courbot wrote:
>>
>> <snip>
>>
>>>>> +#define MEDIA_REQUEST_IOC(__cmd, func)                                       \
>>>>> +     [_IOC_NR(MEDIA_REQUEST_IOC_##__cmd) - 0x80] = {                 \
>>>>> +             .cmd = MEDIA_REQUEST_IOC_##__cmd,                       \
>>>>> +             .fn = func,                                             \
>>>>> +     }
>>>>> +
>>>>> +struct media_request_ioctl_info {
>>>>> +     unsigned int cmd;
>>>>> +     long (*fn)(struct media_request *req);
>>>>> +};
>>>>> +
>>>>> +static const struct media_request_ioctl_info ioctl_info[] = {
>>>>> +     MEDIA_REQUEST_IOC(SUBMIT, media_request_ioctl_submit),
>>>>> +     MEDIA_REQUEST_IOC(REINIT, media_request_ioctl_reinit),
>>>>
>>>> There are only two ioctls, so there is really no need for the
>>>> MEDIA_REQUEST_IOC define. Just keep it simple.
>>>
>>> The number of times it is used doesn't change the fact that it helps
>>> with readability IMHO.
>>
>> But this macro just boils down to:
>>
>> static const struct media_request_ioctl_info ioctl_info[] = {
>>         { MEDIA_REQUEST_IOC_SUBMIT, media_request_ioctl_submit },
>>         { MEDIA_REQUEST_IOC_REINIT, media_request_ioctl_reinit },
>> };
>>
>> It's absolutely identical! So it seems senseless to me.
> 
> This expands to more than that - the index needs to be offset by 0x80,
> something we probably don't want to repeat every line.
> 
>>
>>>
>>>>
>>>>> +};
>>>>> +
>>>>> +static long media_request_ioctl(struct file *filp, unsigned int cmd,
>>>>> +                             unsigned long __arg)
>>>>> +{
>>>>> +     struct media_request *req = filp->private_data;
>>>>> +     const struct media_request_ioctl_info *info;
>>>>> +
>>>>> +     if ((_IOC_NR(cmd) < 0x80) ||
>>>>
>>>> Why start the ioctl number at 0x80? Why not just 0?
>>>> It avoids all this hassle with the 0x80 offset.
>>
>> There is no clash with the MC ioctls, so I really don't believe the 0x80
>> offset is needed.
> 
> I suppose your comment in patch 16 supersedes this one. :)

Yes, it does. I realized later why this was done like this.

That said, I don't like the magic value. Something like this might be
cleaner:

	const unsigned int first_ioc_nr = _IOC_NR(MEDIA_REQUEST_IOC_SUBMIT);

Then use first_ioc_nr (or nr_offset or whatever) instead of 0x80.

Regards,

	Hans

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

* Re: [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-20 16:18   ` Hans Verkuil
  2018-02-21  6:01     ` Alexandre Courbot
@ 2018-02-23  6:34     ` Tomasz Figa
  2018-02-23  7:21       ` Hans Verkuil
  1 sibling, 1 reply; 63+ messages in thread
From: Tomasz Figa @ 2018-02-23  6:34 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, Linux Kernel Mailing List

On Wed, Feb 21, 2018 at 1:18 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
>> that request-aware drivers can call to queue a buffer into a request
>> instead of directly into the vb2 queue if relevent.
>>
>> This function expects that drivers invoking it are using instances of
>> v4l2_request_entity and v4l2_request_entity_data to describe their
>> entity and entity data respectively.
>>
>> Also add the vb2_request_submit() helper function which drivers can
>> invoke in order to queue all the buffers previously queued into a
>> request into the regular vb2 queue.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
>>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>>  2 files changed, 187 insertions(+), 1 deletion(-)
>>
>
> <snip>
>
>> @@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
>>  int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
>>  {
>>       struct video_device *vdev = video_devdata(file);
>> +     struct v4l2_fh *fh = NULL;
>> +
>> +     if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
>> +             fh = file->private_data;
>
> No need for this. All drivers using vb2 will also use v4l2_fh.
>
>>
>>       if (vb2_queue_is_busy(vdev, file))
>>               return -EBUSY;
>> -     return vb2_qbuf(vdev->queue, p);
>> +     return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
>>  }
>>  EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
>>
>> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
>> index 3d5e2d739f05..d4dfa266a0da 100644
>> --- a/include/media/videobuf2-v4l2.h
>> +++ b/include/media/videobuf2-v4l2.h
>> @@ -23,6 +23,12 @@
>>  #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
>>  #endif
>>
>> +struct media_entity;
>> +struct v4l2_fh;
>> +struct media_request;
>> +struct media_request_entity;
>> +struct v4l2_request_entity_data;
>> +
>>  /**
>>   * struct vb2_v4l2_buffer - video buffer information for v4l2.
>>   *
>> @@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
>>   */
>>  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
>>
>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>> +
>> +/**
>> + * vb2_qbuf_request() - Queue a buffer, with request support
>> + * @q:               pointer to &struct vb2_queue with videobuf2 queue.
>> + * @b:               buffer structure passed from userspace to
>> + *           &v4l2_ioctl_ops->vidioc_qbuf handler in driver
>> + * @entity:  request entity to queue for if requests are used.
>> + *
>> + * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
>> + *
>> + * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
>> + *
>> + * If the request_fd member of b is set, then the buffer represented by b is
>> + * queued in the request instead of the vb2 queue. The buffer will be passed
>> + * to the vb2 queue when the request is submitted.
>
> I would definitely also prepare the buffer at this time. That way you'll see any
> errors relating to the prepare early on.

Would the prepare operation be completely independent of other state?
I can see a case when how the buffer is to be prepared may depend on
values of some controls. If so, it would be only possible at request
submission time. Alternatively, the application would have to be
mandated to include any controls that may affect buffer preparing in
the request and before the QBUF is called.

Best regards,
Tomasz

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

* Re: [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-23  6:34     ` Tomasz Figa
@ 2018-02-23  7:21       ` Hans Verkuil
  2018-02-23  7:33         ` Tomasz Figa
  0 siblings, 1 reply; 63+ messages in thread
From: Hans Verkuil @ 2018-02-23  7:21 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, Linux Kernel Mailing List

On 02/23/2018 07:34 AM, Tomasz Figa wrote:
> On Wed, Feb 21, 2018 at 1:18 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>>> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
>>> that request-aware drivers can call to queue a buffer into a request
>>> instead of directly into the vb2 queue if relevent.
>>>
>>> This function expects that drivers invoking it are using instances of
>>> v4l2_request_entity and v4l2_request_entity_data to describe their
>>> entity and entity data respectively.
>>>
>>> Also add the vb2_request_submit() helper function which drivers can
>>> invoke in order to queue all the buffers previously queued into a
>>> request into the regular vb2 queue.
>>>
>>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>>> ---
>>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
>>>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>>>  2 files changed, 187 insertions(+), 1 deletion(-)
>>>
>>
>> <snip>
>>
>>> @@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
>>>  int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
>>>  {
>>>       struct video_device *vdev = video_devdata(file);
>>> +     struct v4l2_fh *fh = NULL;
>>> +
>>> +     if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
>>> +             fh = file->private_data;
>>
>> No need for this. All drivers using vb2 will also use v4l2_fh.
>>
>>>
>>>       if (vb2_queue_is_busy(vdev, file))
>>>               return -EBUSY;
>>> -     return vb2_qbuf(vdev->queue, p);
>>> +     return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
>>>  }
>>>  EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
>>>
>>> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
>>> index 3d5e2d739f05..d4dfa266a0da 100644
>>> --- a/include/media/videobuf2-v4l2.h
>>> +++ b/include/media/videobuf2-v4l2.h
>>> @@ -23,6 +23,12 @@
>>>  #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
>>>  #endif
>>>
>>> +struct media_entity;
>>> +struct v4l2_fh;
>>> +struct media_request;
>>> +struct media_request_entity;
>>> +struct v4l2_request_entity_data;
>>> +
>>>  /**
>>>   * struct vb2_v4l2_buffer - video buffer information for v4l2.
>>>   *
>>> @@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
>>>   */
>>>  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
>>>
>>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>>> +
>>> +/**
>>> + * vb2_qbuf_request() - Queue a buffer, with request support
>>> + * @q:               pointer to &struct vb2_queue with videobuf2 queue.
>>> + * @b:               buffer structure passed from userspace to
>>> + *           &v4l2_ioctl_ops->vidioc_qbuf handler in driver
>>> + * @entity:  request entity to queue for if requests are used.
>>> + *
>>> + * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
>>> + *
>>> + * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
>>> + *
>>> + * If the request_fd member of b is set, then the buffer represented by b is
>>> + * queued in the request instead of the vb2 queue. The buffer will be passed
>>> + * to the vb2 queue when the request is submitted.
>>
>> I would definitely also prepare the buffer at this time. That way you'll see any
>> errors relating to the prepare early on.
> 
> Would the prepare operation be completely independent of other state?
> I can see a case when how the buffer is to be prepared may depend on
> values of some controls. If so, it would be only possible at request
> submission time. Alternatively, the application would have to be
> mandated to include any controls that may affect buffer preparing in
> the request and before the QBUF is called.

The buffer is just memory. Controls play no role here. So the prepare
operation is indeed independent of other state. Anything else would make
this horrible complicated. And besides, with buffers allocated by other
subsystems (dmabuf) how could controls from our subsystems ever affect
those? The videobuf(2) frameworks have always just operated on memory
buffers without any knowledge of what it contains.

Regards,

	Hans

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

* Re: [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-23  7:21       ` Hans Verkuil
@ 2018-02-23  7:33         ` Tomasz Figa
  2018-02-23  7:43           ` Hans Verkuil
  0 siblings, 1 reply; 63+ messages in thread
From: Tomasz Figa @ 2018-02-23  7:33 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, Linux Kernel Mailing List

On Fri, Feb 23, 2018 at 4:21 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On 02/23/2018 07:34 AM, Tomasz Figa wrote:
>> On Wed, Feb 21, 2018 at 1:18 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>>>> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
>>>> that request-aware drivers can call to queue a buffer into a request
>>>> instead of directly into the vb2 queue if relevent.
>>>>
>>>> This function expects that drivers invoking it are using instances of
>>>> v4l2_request_entity and v4l2_request_entity_data to describe their
>>>> entity and entity data respectively.
>>>>
>>>> Also add the vb2_request_submit() helper function which drivers can
>>>> invoke in order to queue all the buffers previously queued into a
>>>> request into the regular vb2 queue.
>>>>
>>>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>>>> ---
>>>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
>>>>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>>>>  2 files changed, 187 insertions(+), 1 deletion(-)
>>>>
>>>
>>> <snip>
>>>
>>>> @@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
>>>>  int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
>>>>  {
>>>>       struct video_device *vdev = video_devdata(file);
>>>> +     struct v4l2_fh *fh = NULL;
>>>> +
>>>> +     if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
>>>> +             fh = file->private_data;
>>>
>>> No need for this. All drivers using vb2 will also use v4l2_fh.
>>>
>>>>
>>>>       if (vb2_queue_is_busy(vdev, file))
>>>>               return -EBUSY;
>>>> -     return vb2_qbuf(vdev->queue, p);
>>>> +     return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
>>>>  }
>>>>  EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
>>>>
>>>> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
>>>> index 3d5e2d739f05..d4dfa266a0da 100644
>>>> --- a/include/media/videobuf2-v4l2.h
>>>> +++ b/include/media/videobuf2-v4l2.h
>>>> @@ -23,6 +23,12 @@
>>>>  #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
>>>>  #endif
>>>>
>>>> +struct media_entity;
>>>> +struct v4l2_fh;
>>>> +struct media_request;
>>>> +struct media_request_entity;
>>>> +struct v4l2_request_entity_data;
>>>> +
>>>>  /**
>>>>   * struct vb2_v4l2_buffer - video buffer information for v4l2.
>>>>   *
>>>> @@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
>>>>   */
>>>>  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
>>>>
>>>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>>>> +
>>>> +/**
>>>> + * vb2_qbuf_request() - Queue a buffer, with request support
>>>> + * @q:               pointer to &struct vb2_queue with videobuf2 queue.
>>>> + * @b:               buffer structure passed from userspace to
>>>> + *           &v4l2_ioctl_ops->vidioc_qbuf handler in driver
>>>> + * @entity:  request entity to queue for if requests are used.
>>>> + *
>>>> + * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
>>>> + *
>>>> + * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
>>>> + *
>>>> + * If the request_fd member of b is set, then the buffer represented by b is
>>>> + * queued in the request instead of the vb2 queue. The buffer will be passed
>>>> + * to the vb2 queue when the request is submitted.
>>>
>>> I would definitely also prepare the buffer at this time. That way you'll see any
>>> errors relating to the prepare early on.
>>
>> Would the prepare operation be completely independent of other state?
>> I can see a case when how the buffer is to be prepared may depend on
>> values of some controls. If so, it would be only possible at request
>> submission time. Alternatively, the application would have to be
>> mandated to include any controls that may affect buffer preparing in
>> the request and before the QBUF is called.
>
> The buffer is just memory. Controls play no role here. So the prepare
> operation is indeed independent of other state. Anything else would make
> this horrible complicated. And besides, with buffers allocated by other
> subsystems (dmabuf) how could controls from our subsystems ever affect
> those? The videobuf(2) frameworks have always just operated on memory
> buffers without any knowledge of what it contains.

What you said applies to the videobuf(2) frameworks, but driver
callback is explicitly defined as having access to the buffer
contents:

 * @buf_prepare: called every time the buffer is queued from userspace
 * and from the VIDIOC_PREPARE_BUF() ioctl; drivers may
 * perform any initialization required before each
 * hardware operation in this callback; drivers can
 * access/modify the buffer here as it is still synced for
 * the CPU; drivers that support VIDIOC_CREATE_BUFS() must
 * also validate the buffer size; if an error is returned,
 * the buffer will not be queued in driver; optional.

https://elixir.bootlin.com/linux/latest/source/include/media/videobuf2-core.h#L330

Best regards,
Tomasz

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

* Re: [RFCv4 13/21] media: videobuf2-v4l2: support for requests
  2018-02-23  7:33         ` Tomasz Figa
@ 2018-02-23  7:43           ` Hans Verkuil
  0 siblings, 0 replies; 63+ messages in thread
From: Hans Verkuil @ 2018-02-23  7:43 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Sakari Ailus, Gustavo Padovan,
	Linux Media Mailing List, Linux Kernel Mailing List

On 02/23/2018 08:33 AM, Tomasz Figa wrote:
> On Fri, Feb 23, 2018 at 4:21 PM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>> On 02/23/2018 07:34 AM, Tomasz Figa wrote:
>>> On Wed, Feb 21, 2018 at 1:18 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
>>>> On 02/20/2018 05:44 AM, Alexandre Courbot wrote:
>>>>> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
>>>>> that request-aware drivers can call to queue a buffer into a request
>>>>> instead of directly into the vb2 queue if relevent.
>>>>>
>>>>> This function expects that drivers invoking it are using instances of
>>>>> v4l2_request_entity and v4l2_request_entity_data to describe their
>>>>> entity and entity data respectively.
>>>>>
>>>>> Also add the vb2_request_submit() helper function which drivers can
>>>>> invoke in order to queue all the buffers previously queued into a
>>>>> request into the regular vb2 queue.
>>>>>
>>>>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>>>>> ---
>>>>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129 +++++++++++++++++-
>>>>>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>>>>>  2 files changed, 187 insertions(+), 1 deletion(-)
>>>>>
>>>>
>>>> <snip>
>>>>
>>>>> @@ -776,10 +899,14 @@ EXPORT_SYMBOL_GPL(vb2_ioctl_querybuf);
>>>>>  int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
>>>>>  {
>>>>>       struct video_device *vdev = video_devdata(file);
>>>>> +     struct v4l2_fh *fh = NULL;
>>>>> +
>>>>> +     if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
>>>>> +             fh = file->private_data;
>>>>
>>>> No need for this. All drivers using vb2 will also use v4l2_fh.
>>>>
>>>>>
>>>>>       if (vb2_queue_is_busy(vdev, file))
>>>>>               return -EBUSY;
>>>>> -     return vb2_qbuf(vdev->queue, p);
>>>>> +     return vb2_qbuf_request(vdev->queue, p, fh ? fh->entity : NULL);
>>>>>  }
>>>>>  EXPORT_SYMBOL_GPL(vb2_ioctl_qbuf);
>>>>>
>>>>> diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
>>>>> index 3d5e2d739f05..d4dfa266a0da 100644
>>>>> --- a/include/media/videobuf2-v4l2.h
>>>>> +++ b/include/media/videobuf2-v4l2.h
>>>>> @@ -23,6 +23,12 @@
>>>>>  #error VB2_MAX_PLANES != VIDEO_MAX_PLANES
>>>>>  #endif
>>>>>
>>>>> +struct media_entity;
>>>>> +struct v4l2_fh;
>>>>> +struct media_request;
>>>>> +struct media_request_entity;
>>>>> +struct v4l2_request_entity_data;
>>>>> +
>>>>>  /**
>>>>>   * struct vb2_v4l2_buffer - video buffer information for v4l2.
>>>>>   *
>>>>> @@ -116,6 +122,59 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b);
>>>>>   */
>>>>>  int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b);
>>>>>
>>>>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>>>>> +
>>>>> +/**
>>>>> + * vb2_qbuf_request() - Queue a buffer, with request support
>>>>> + * @q:               pointer to &struct vb2_queue with videobuf2 queue.
>>>>> + * @b:               buffer structure passed from userspace to
>>>>> + *           &v4l2_ioctl_ops->vidioc_qbuf handler in driver
>>>>> + * @entity:  request entity to queue for if requests are used.
>>>>> + *
>>>>> + * Should be called from &v4l2_ioctl_ops->vidioc_qbuf handler of a driver.
>>>>> + *
>>>>> + * If requests are not in use, calling this is equivalent to calling vb2_qbuf().
>>>>> + *
>>>>> + * If the request_fd member of b is set, then the buffer represented by b is
>>>>> + * queued in the request instead of the vb2 queue. The buffer will be passed
>>>>> + * to the vb2 queue when the request is submitted.
>>>>
>>>> I would definitely also prepare the buffer at this time. That way you'll see any
>>>> errors relating to the prepare early on.
>>>
>>> Would the prepare operation be completely independent of other state?
>>> I can see a case when how the buffer is to be prepared may depend on
>>> values of some controls. If so, it would be only possible at request
>>> submission time. Alternatively, the application would have to be
>>> mandated to include any controls that may affect buffer preparing in
>>> the request and before the QBUF is called.
>>
>> The buffer is just memory. Controls play no role here. So the prepare
>> operation is indeed independent of other state. Anything else would make
>> this horrible complicated. And besides, with buffers allocated by other
>> subsystems (dmabuf) how could controls from our subsystems ever affect
>> those? The videobuf(2) frameworks have always just operated on memory
>> buffers without any knowledge of what it contains.
> 
> What you said applies to the videobuf(2) frameworks, but driver
> callback is explicitly defined as having access to the buffer
> contents:
> 
>  * @buf_prepare: called every time the buffer is queued from userspace
>  * and from the VIDIOC_PREPARE_BUF() ioctl; drivers may
>  * perform any initialization required before each
>  * hardware operation in this callback; drivers can
>  * access/modify the buffer here as it is still synced for
>  * the CPU; drivers that support VIDIOC_CREATE_BUFS() must
>  * also validate the buffer size; if an error is returned,
>  * the buffer will not be queued in driver; optional.

Ah, good point.

So the prepare step should be taken when the request is submitted.

You definitely want to know at submit time if all the buffers in the
request can be prepared so you can return an error.

Userspace can also prepare the buffer with VIDIOC_BUF_PREPARE before
queuing it into the request if it wants to.

Regards,

	Hans

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-02-20  4:44 ` [RFCv4 19/21] media: vim2m: add request support Alexandre Courbot
@ 2018-03-07 16:37   ` Paul Kocialkowski
  2018-03-08 13:48     ` Alexandre Courbot
                       ` (2 more replies)
  0 siblings, 3 replies; 63+ messages in thread
From: Paul Kocialkowski @ 2018-03-07 16:37 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Hans Verkuil,
	Laurent Pinchart, Pawel Osciak, Marek Szyprowski, Tomasz Figa,
	Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Maxime Ripard

[-- Attachment #1: Type: text/plain, Size: 3930 bytes --]

Hi,

First off, I'd like to take the occasion to say thank-you for your work.
This is a major piece of plumbing that is required for me to add support
for the Allwinner CedarX VPU hardware in upstream Linux. Other drivers,
such as tegra-vde (that was recently merged in staging) are also badly
in need of this API.

I have a few comments based on my experience integrating this request
API with the Cedrus VPU driver (and the associated libva backend), that
also concern the vim2m driver.

On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
> Set the necessary ops for supporting requests in vim2m.
> 
> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  drivers/media/platform/Kconfig |  1 +
>  drivers/media/platform/vim2m.c | 75
> ++++++++++++++++++++++++++++++++++
>  2 files changed, 76 insertions(+)
> 
> diff --git a/drivers/media/platform/Kconfig
> b/drivers/media/platform/Kconfig
> index 614fbef08ddc..09be0b5f9afe 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig

[...]

> +static int vim2m_request_submit(struct media_request *req,
> +				struct media_request_entity_data
> *_data)
> +{
> +	struct v4l2_request_entity_data *data;
> +
> +	data = to_v4l2_entity_data(_data);

We need to call v4l2_m2m_try_schedule here so that m2m scheduling can
happen when only 2 buffers were queued and no other action was taken
from usespace. In that scenario, m2m scheduling currently doesn't
happen.

However, this requires access to the m2m context, which is not easy to
get from req or _data. I'm not sure that some container_of magic would
even do the trick here.

> +	return vb2_request_submit(data);

vb2_request_submit does not lock the associated request mutex although
it accesses the associated queued buffers list, which I believe this
mutex is supposed to protect.

We could either wrap this call with media_request_lock(req) and
media_request_unlock(req) or have the lock in the function itself, which
would require passing it the req pointer.

The latter would probably be safer for future use of the function.

> +}
> +
> +static const struct media_request_entity_ops vim2m_request_entity_ops
> = {
> +	.data_alloc	= vim2m_entity_data_alloc,
> +	.data_free	= v4l2_request_entity_data_free,
> +	.submit		= vim2m_request_submit,
> +};
> +
>  /*
>   * File operations
>   */
> @@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
>  	ctx->dev = dev;
>  	hdl = &ctx->hdl;
>  	v4l2_ctrl_handler_init(hdl, 4);
> +	v4l2_request_entity_init(&ctx->req_entity,
> &vim2m_request_entity_ops,
> +				 &ctx->dev->vfd);
> +	ctx->fh.entity = &ctx->req_entity.base;
>  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1,
> 1, 0);
>  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1,
> 1, 0);
>  	v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
> @@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device
> *pdev)
>  	if (!dev)
>  		return -ENOMEM;
>  
> +	v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
> +			      &v4l2_request_ops);
> +
>  	spin_lock_init(&dev->irqlock);
>  
>  	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> @@ -1012,6 +1085,7 @@ static int vim2m_probe(struct platform_device
> *pdev)
>  	vfd = &dev->vfd;
>  	vfd->lock = &dev->dev_mutex;
>  	vfd->v4l2_dev = &dev->v4l2_dev;
> +	vfd->req_mgr = &dev->req_mgr.base;
>  
>  	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
>  	if (ret) {
> @@ -1054,6 +1128,7 @@ static int vim2m_remove(struct platform_device
> *pdev)
>  	del_timer_sync(&dev->timer);
>  	video_unregister_device(&dev->vfd);
>  	v4l2_device_unregister(&dev->v4l2_dev);
> +	v4l2_request_mgr_free(&dev->req_mgr);
>  
>  	return 0;
>  }

-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [RFCv4,13/21] media: videobuf2-v4l2: support for requests
  2018-02-20  4:44 ` [RFCv4 13/21] media: videobuf2-v4l2: " Alexandre Courbot
  2018-02-20 16:18   ` Hans Verkuil
@ 2018-03-07 16:50   ` Paul Kocialkowski
  2018-03-08 13:50     ` Alexandre Courbot
  1 sibling, 1 reply; 63+ messages in thread
From: Paul Kocialkowski @ 2018-03-07 16:50 UTC (permalink / raw)
  To: Alexandre Courbot, Mauro Carvalho Chehab, Hans Verkuil,
	Laurent Pinchart, Pawel Osciak, Marek Szyprowski, Tomasz Figa,
	Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Maxime Ripard

[-- Attachment #1: Type: text/plain, Size: 4128 bytes --]

Hi,

On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
> that request-aware drivers can call to queue a buffer into a request
> instead of directly into the vb2 queue if relevent.
> 
> This function expects that drivers invoking it are using instances of
> v4l2_request_entity and v4l2_request_entity_data to describe their
> entity and entity data respectively.
> 
> Also add the vb2_request_submit() helper function which drivers can
> invoke in order to queue all the buffers previously queued into a
> request into the regular vb2 queue.

See a comment/proposal below about an issue I encountered when using
multi-planar formats.

> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> ---
>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129
> +++++++++++++++++-
>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>  2 files changed, 187 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> b/drivers/media/common/videobuf2/videobuf2-v4l2.c
> index 6d4d184aa68e..0627c3339572 100644
> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c

[...]

> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
> +int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
> +		     struct media_request_entity *entity)
> +{
> +	struct v4l2_request_entity_data *data;
> +	struct v4l2_vb2_request_buffer *qb;
> +	struct media_request *req;
> +	struct vb2_buffer *vb;
> +	int ret = 0;
> +
> +	if (b->request_fd <= 0)
> +		return vb2_qbuf(q, b);
> +
> +	if (!q->allow_requests)
> +		return -EINVAL;
> +
> +	req = media_request_get_from_fd(b->request_fd);
> +	if (!req)
> +		return -EINVAL;
> +
> +	data = to_v4l2_entity_data(media_request_get_entity_data(req,
> entity));
> +	if (IS_ERR(data)) {
> +		ret = PTR_ERR(data);
> +		goto out;
> +	}
> +
> +	mutex_lock(&req->lock);
> +
> +	if (req->state != MEDIA_REQUEST_STATE_IDLE) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
> +	if (ret)
> +		goto out;
> +
> +	vb = q->bufs[b->index];
> +	switch (vb->state) {
> +	case VB2_BUF_STATE_DEQUEUED:
> +		break;
> +	case VB2_BUF_STATE_PREPARED:
> +		break;
> +	case VB2_BUF_STATE_PREPARING:
> +		dprintk(1, "buffer still being prepared\n");
> +		ret = -EINVAL;
> +		goto out;
> +	default:
> +		dprintk(1, "invalid buffer state %d\n", vb->state);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	/* do we already have a buffer for this request in the queue?
> */
> +	list_for_each_entry(qb, &data->queued_buffers, node) {
> +		if (qb->queue == q) {
> +			ret = -EBUSY;
> +			goto out;
> +		}
> +	}
> +
> +	qb = kzalloc(sizeof(*qb), GFP_KERNEL);
> +	if (!qb) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/*
> +	 * TODO should be prepare the buffer here if needed, to
> report errors
> +	 * early?
> +	 */
> +	qb->pre_req_state = vb->state;
> +	qb->queue = q;
> +	memcpy(&qb->v4l2_buf, b, sizeof(*b));

I am getting data corruption on qb->v4l2_buf.m.planes from this when
using planar buffers, only after exiting the ioctl handler (i.e. when
accessing this buffer later from the queue).

I initially thought this was because the planes pointer was copied as-is 
from userspace, but Maxime Ripard suggested that this would have
automatically triggered a visible fault in the kernel.

Thus, my best guess is that the data is properly copied from userspace
but freed when leaving the ioctl handler, which doesn't work our with
the request API.

A dirty fix that I came up with consists in re-allocating the planes
buffer here and copying its contents from "b", so that it can live
beyond the ioctl call.

I am not too sure whether this should be fixed here or in the part of
the v4l2 common code that frees this data. What do you think?

Cheers!

-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-07 16:37   ` [RFCv4,19/21] " Paul Kocialkowski
@ 2018-03-08 13:48     ` Alexandre Courbot
  2018-03-09 14:35       ` Paul Kocialkowski
  2018-03-11 19:40     ` Dmitry Osipenko
  2018-03-11 19:42     ` Dmitry Osipenko
  2 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-03-08 13:48 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML, Maxime Ripard

Hi Paul!

Thanks a lot for taking the time to try this! I am also working on
getting it to work with an actual driver, but you apparently found
rough edges that I missed.

On Thu, Mar 8, 2018 at 1:37 AM, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> Hi,
>
> First off, I'd like to take the occasion to say thank-you for your work.
> This is a major piece of plumbing that is required for me to add support
> for the Allwinner CedarX VPU hardware in upstream Linux. Other drivers,
> such as tegra-vde (that was recently merged in staging) are also badly
> in need of this API.
>
> I have a few comments based on my experience integrating this request
> API with the Cedrus VPU driver (and the associated libva backend), that
> also concern the vim2m driver.
>
> On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
>> Set the necessary ops for supporting requests in vim2m.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  drivers/media/platform/Kconfig |  1 +
>>  drivers/media/platform/vim2m.c | 75
>> ++++++++++++++++++++++++++++++++++
>>  2 files changed, 76 insertions(+)
>>
>> diff --git a/drivers/media/platform/Kconfig
>> b/drivers/media/platform/Kconfig
>> index 614fbef08ddc..09be0b5f9afe 100644
>> --- a/drivers/media/platform/Kconfig
>> +++ b/drivers/media/platform/Kconfig
>
> [...]
>
>> +static int vim2m_request_submit(struct media_request *req,
>> +                             struct media_request_entity_data
>> *_data)
>> +{
>> +     struct v4l2_request_entity_data *data;
>> +
>> +     data = to_v4l2_entity_data(_data);
>
> We need to call v4l2_m2m_try_schedule here so that m2m scheduling can
> happen when only 2 buffers were queued and no other action was taken
> from usespace. In that scenario, m2m scheduling currently doesn't
> happen.

I don't think I understand the sequence of events that results in
v4l2_m2m_try_schedule() not being called. Do you mean something like:

*
* QBUF on output queue with request set
* QBUF on capture queue
* SUBMIT_REQUEST

?

The call to vb2_request_submit() right after should trigger
v4l2_m2m_try_schedule(), since the buffers associated to the request
will enter the vb2 queue and be passed to the m2m framework, which
will then call v4l2_m2m_try_schedule(). Or maybe you are thinking
about a different sequence of events?

>
> However, this requires access to the m2m context, which is not easy to
> get from req or _data. I'm not sure that some container_of magic would
> even do the trick here.

data_->entity will give you a pointer to the media_request_entity,
which is part of vim2m_ctx. You can thus get the m2m context by doing
container_of(data_->entity, struct vim2m_ctx, req_entity). See
vim2m_entity_data_alloc() for an example.

>
>> +     return vb2_request_submit(data);
>
> vb2_request_submit does not lock the associated request mutex although
> it accesses the associated queued buffers list, which I believe this
> mutex is supposed to protect.

After a request is submitted, the data protected by the mutex can only
be accessed by the driver when it processes the request. It cannot be
modified concurrently, so I think we are safe here.

I am also wondering whether the ioctl locking doesn't make the request
locking redundant. Request information can only be modified and
accessed through ioctls until it is submitted, and after that there
are no concurrent accesses. I need to think a bit more about it
though.

Cheers,
Alex.

>
> We could either wrap this call with media_request_lock(req) and
> media_request_unlock(req) or have the lock in the function itself, which
> would require passing it the req pointer.
>
> The latter would probably be safer for future use of the function.
>
>> +}
>> +
>> +static const struct media_request_entity_ops vim2m_request_entity_ops
>> = {
>> +     .data_alloc     = vim2m_entity_data_alloc,
>> +     .data_free      = v4l2_request_entity_data_free,
>> +     .submit         = vim2m_request_submit,
>> +};
>> +
>>  /*
>>   * File operations
>>   */
>> @@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
>>       ctx->dev = dev;
>>       hdl = &ctx->hdl;
>>       v4l2_ctrl_handler_init(hdl, 4);
>> +     v4l2_request_entity_init(&ctx->req_entity,
>> &vim2m_request_entity_ops,
>> +                              &ctx->dev->vfd);
>> +     ctx->fh.entity = &ctx->req_entity.base;
>>       v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1,
>> 1, 0);
>>       v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1,
>> 1, 0);
>>       v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
>> @@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device
>> *pdev)
>>       if (!dev)
>>               return -ENOMEM;
>>
>> +     v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
>> +                           &v4l2_request_ops);
>> +
>>       spin_lock_init(&dev->irqlock);
>>
>>       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
>> @@ -1012,6 +1085,7 @@ static int vim2m_probe(struct platform_device
>> *pdev)
>>       vfd = &dev->vfd;
>>       vfd->lock = &dev->dev_mutex;
>>       vfd->v4l2_dev = &dev->v4l2_dev;
>> +     vfd->req_mgr = &dev->req_mgr.base;
>>
>>       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
>>       if (ret) {
>> @@ -1054,6 +1128,7 @@ static int vim2m_remove(struct platform_device
>> *pdev)
>>       del_timer_sync(&dev->timer);
>>       video_unregister_device(&dev->vfd);
>>       v4l2_device_unregister(&dev->v4l2_dev);
>> +     v4l2_request_mgr_free(&dev->req_mgr);
>>
>>       return 0;
>>  }
>
> --
> Paul Kocialkowski, Bootlin (formerly Free Electrons)
> Embedded Linux and kernel engineering
> https://bootlin.com

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

* Re: [RFCv4,13/21] media: videobuf2-v4l2: support for requests
  2018-03-07 16:50   ` [RFCv4,13/21] " Paul Kocialkowski
@ 2018-03-08 13:50     ` Alexandre Courbot
  0 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-03-08 13:50 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML, Maxime Ripard

On Thu, Mar 8, 2018 at 1:50 AM, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> Hi,
>
> On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
>> Add a new vb2_qbuf_request() (a request-aware version of vb2_qbuf())
>> that request-aware drivers can call to queue a buffer into a request
>> instead of directly into the vb2 queue if relevent.
>>
>> This function expects that drivers invoking it are using instances of
>> v4l2_request_entity and v4l2_request_entity_data to describe their
>> entity and entity data respectively.
>>
>> Also add the vb2_request_submit() helper function which drivers can
>> invoke in order to queue all the buffers previously queued into a
>> request into the regular vb2 queue.
>
> See a comment/proposal below about an issue I encountered when using
> multi-planar formats.
>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  .../media/common/videobuf2/videobuf2-v4l2.c   | 129
>> +++++++++++++++++-
>>  include/media/videobuf2-v4l2.h                |  59 ++++++++
>>  2 files changed, 187 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> index 6d4d184aa68e..0627c3339572 100644
>> --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
>> +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
>
> [...]
>
>> +#if IS_ENABLED(CONFIG_MEDIA_REQUEST_API)
>> +int vb2_qbuf_request(struct vb2_queue *q, struct v4l2_buffer *b,
>> +                  struct media_request_entity *entity)
>> +{
>> +     struct v4l2_request_entity_data *data;
>> +     struct v4l2_vb2_request_buffer *qb;
>> +     struct media_request *req;
>> +     struct vb2_buffer *vb;
>> +     int ret = 0;
>> +
>> +     if (b->request_fd <= 0)
>> +             return vb2_qbuf(q, b);
>> +
>> +     if (!q->allow_requests)
>> +             return -EINVAL;
>> +
>> +     req = media_request_get_from_fd(b->request_fd);
>> +     if (!req)
>> +             return -EINVAL;
>> +
>> +     data = to_v4l2_entity_data(media_request_get_entity_data(req,
>> entity));
>> +     if (IS_ERR(data)) {
>> +             ret = PTR_ERR(data);
>> +             goto out;
>> +     }
>> +
>> +     mutex_lock(&req->lock);
>> +
>> +     if (req->state != MEDIA_REQUEST_STATE_IDLE) {
>> +             ret = -EINVAL;
>> +             goto out;
>> +     }
>> +
>> +     ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
>> +     if (ret)
>> +             goto out;
>> +
>> +     vb = q->bufs[b->index];
>> +     switch (vb->state) {
>> +     case VB2_BUF_STATE_DEQUEUED:
>> +             break;
>> +     case VB2_BUF_STATE_PREPARED:
>> +             break;
>> +     case VB2_BUF_STATE_PREPARING:
>> +             dprintk(1, "buffer still being prepared\n");
>> +             ret = -EINVAL;
>> +             goto out;
>> +     default:
>> +             dprintk(1, "invalid buffer state %d\n", vb->state);
>> +             ret = -EINVAL;
>> +             goto out;
>> +     }
>> +
>> +     /* do we already have a buffer for this request in the queue?
>> */
>> +     list_for_each_entry(qb, &data->queued_buffers, node) {
>> +             if (qb->queue == q) {
>> +                     ret = -EBUSY;
>> +                     goto out;
>> +             }
>> +     }
>> +
>> +     qb = kzalloc(sizeof(*qb), GFP_KERNEL);
>> +     if (!qb) {
>> +             ret = -ENOMEM;
>> +             goto out;
>> +     }
>> +
>> +     /*
>> +      * TODO should be prepare the buffer here if needed, to
>> report errors
>> +      * early?
>> +      */
>> +     qb->pre_req_state = vb->state;
>> +     qb->queue = q;
>> +     memcpy(&qb->v4l2_buf, b, sizeof(*b));
>
> I am getting data corruption on qb->v4l2_buf.m.planes from this when
> using planar buffers, only after exiting the ioctl handler (i.e. when
> accessing this buffer later from the queue).
>
> I initially thought this was because the planes pointer was copied as-is
> from userspace, but Maxime Ripard suggested that this would have
> automatically triggered a visible fault in the kernel.
>
> Thus, my best guess is that the data is properly copied from userspace
> but freed when leaving the ioctl handler, which doesn't work our with
> the request API.
>
> A dirty fix that I came up with consists in re-allocating the planes
> buffer here and copying its contents from "b", so that it can live
> beyond the ioctl call.
>
> I am not too sure whether this should be fixed here or in the part of
> the v4l2 common code that frees this data. What do you think?

Oh, nice catch. Copying plane information indeed requires more work
than a dumb memcpy(). I suppose this should be handled here, but let
me come back to this after a good night of sleep. :)

Thanks! I will try to fix this tomorrow and push a temporary version
somewhere so you can move forward.

Alex.

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-08 13:48     ` Alexandre Courbot
@ 2018-03-09 14:35       ` Paul Kocialkowski
  2018-03-13 10:24         ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Paul Kocialkowski @ 2018-03-09 14:35 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML, Maxime Ripard

[-- Attachment #1: Type: text/plain, Size: 7293 bytes --]

Hi,

On Thu, 2018-03-08 at 22:48 +0900, Alexandre Courbot wrote:
> Hi Paul!
> 
> Thanks a lot for taking the time to try this! I am also working on
> getting it to work with an actual driver, but you apparently found
> rough edges that I missed.
> 
> On Thu, Mar 8, 2018 at 1:37 AM, Paul Kocialkowski
> <paul.kocialkowski@bootlin.com> wrote:
> > Hi,
> > 
> > First off, I'd like to take the occasion to say thank-you for your
> > work.
> > This is a major piece of plumbing that is required for me to add
> > support
> > for the Allwinner CedarX VPU hardware in upstream Linux. Other
> > drivers,
> > such as tegra-vde (that was recently merged in staging) are also
> > badly
> > in need of this API.
> > 
> > I have a few comments based on my experience integrating this
> > request
> > API with the Cedrus VPU driver (and the associated libva backend),
> > that
> > also concern the vim2m driver.
> > 
> > On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
> > > Set the necessary ops for supporting requests in vim2m.
> > > 
> > > Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> > > ---
> > >  drivers/media/platform/Kconfig |  1 +
> > >  drivers/media/platform/vim2m.c | 75
> > > ++++++++++++++++++++++++++++++++++
> > >  2 files changed, 76 insertions(+)
> > > 
> > > diff --git a/drivers/media/platform/Kconfig
> > > b/drivers/media/platform/Kconfig
> > > index 614fbef08ddc..09be0b5f9afe 100644
> > > --- a/drivers/media/platform/Kconfig
> > > +++ b/drivers/media/platform/Kconfig
> > 
> > [...]
> > 
> > > +static int vim2m_request_submit(struct media_request *req,
> > > +                             struct media_request_entity_data
> > > *_data)
> > > +{
> > > +     struct v4l2_request_entity_data *data;
> > > +
> > > +     data = to_v4l2_entity_data(_data);
> > 
> > We need to call v4l2_m2m_try_schedule here so that m2m scheduling
> > can
> > happen when only 2 buffers were queued and no other action was taken
> > from usespace. In that scenario, m2m scheduling currently doesn't
> > happen.
> 
> I don't think I understand the sequence of events that results in
> v4l2_m2m_try_schedule() not being called. Do you mean something like:
> 
> *
> * QBUF on output queue with request set
> * QBUF on capture queue
> * SUBMIT_REQUEST
> 
> ?
> 
> The call to vb2_request_submit() right after should trigger
> v4l2_m2m_try_schedule(), since the buffers associated to the request
> will enter the vb2 queue and be passed to the m2m framework, which
> will then call v4l2_m2m_try_schedule(). Or maybe you are thinking
> about a different sequence of events?

This is indeed the sequence of events that I'm seeing, but the
scheduling call simply did not happen on vb2_request_submit. I suppose I will need to investigate some more to find out exactly why.

IIRC, the m2m qbuf function is called (and fails to schedule) when the
ioctl happens, not when the task is submitted.

This issue is seen with vim2m as well as the rencently-submitted sunxi-
cedrus driver (with the in-driver calls to v4l2_m2m_try_schedule
removed, obviously). If needs be, I could provide a standalone test
program to reproduce it.

> > However, this requires access to the m2m context, which is not easy
> > to
> > get from req or _data. I'm not sure that some container_of magic
> > would
> > even do the trick here.
> 
> data_->entity will give you a pointer to the media_request_entity,
> which is part of vim2m_ctx. You can thus get the m2m context by doing
> container_of(data_->entity, struct vim2m_ctx, req_entity). See
> vim2m_entity_data_alloc() for an example.

Excellent, that's exactly what I was looking for! Thanks a lot and see
the related patch I submitted earlier today.

> > > +     return vb2_request_submit(data);
> > 
> > vb2_request_submit does not lock the associated request mutex
> > although
> > it accesses the associated queued buffers list, which I believe this
> > mutex is supposed to protect.
> 
> After a request is submitted, the data protected by the mutex can only
> be accessed by the driver when it processes the request. It cannot be
> modified concurrently, so I think we are safe here.

Fait enough, that should be enough then. I've dropped this change.

Cheers,

Paul

> I am also wondering whether the ioctl locking doesn't make the request
> locking redundant. Request information can only be modified and
> accessed through ioctls until it is submitted, and after that there
> are no concurrent accesses. I need to think a bit more about it
> though.
> 
> Cheers,
> Alex.
> 
> > 
> > We could either wrap this call with media_request_lock(req) and
> > media_request_unlock(req) or have the lock in the function itself,
> > which
> > would require passing it the req pointer.
> > 
> > The latter would probably be safer for future use of the function.
> > 
> > > +}
> > > +
> > > +static const struct media_request_entity_ops
> > > vim2m_request_entity_ops
> > > = {
> > > +     .data_alloc     = vim2m_entity_data_alloc,
> > > +     .data_free      = v4l2_request_entity_data_free,
> > > +     .submit         = vim2m_request_submit,
> > > +};
> > > +
> > >  /*
> > >   * File operations
> > >   */
> > > @@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
> > >       ctx->dev = dev;
> > >       hdl = &ctx->hdl;
> > >       v4l2_ctrl_handler_init(hdl, 4);
> > > +     v4l2_request_entity_init(&ctx->req_entity,
> > > &vim2m_request_entity_ops,
> > > +                              &ctx->dev->vfd);
> > > +     ctx->fh.entity = &ctx->req_entity.base;
> > >       v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0,
> > > 1,
> > > 1, 0);
> > >       v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0,
> > > 1,
> > > 1, 0);
> > >       v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec,
> > > NULL);
> > > @@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device
> > > *pdev)
> > >       if (!dev)
> > >               return -ENOMEM;
> > > 
> > > +     v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
> > > +                           &v4l2_request_ops);
> > > +
> > >       spin_lock_init(&dev->irqlock);
> > > 
> > >       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> > > @@ -1012,6 +1085,7 @@ static int vim2m_probe(struct
> > > platform_device
> > > *pdev)
> > >       vfd = &dev->vfd;
> > >       vfd->lock = &dev->dev_mutex;
> > >       vfd->v4l2_dev = &dev->v4l2_dev;
> > > +     vfd->req_mgr = &dev->req_mgr.base;
> > > 
> > >       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
> > >       if (ret) {
> > > @@ -1054,6 +1128,7 @@ static int vim2m_remove(struct
> > > platform_device
> > > *pdev)
> > >       del_timer_sync(&dev->timer);
> > >       video_unregister_device(&dev->vfd);
> > >       v4l2_device_unregister(&dev->v4l2_dev);
> > > +     v4l2_request_mgr_free(&dev->req_mgr);
> > > 
> > >       return 0;
> > >  }
> > 
> > --
> > Paul Kocialkowski, Bootlin (formerly Free Electrons)
> > Embedded Linux and kernel engineering
> > https://bootlin.com
-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-07 16:37   ` [RFCv4,19/21] " Paul Kocialkowski
  2018-03-08 13:48     ` Alexandre Courbot
@ 2018-03-11 19:40     ` Dmitry Osipenko
  2018-03-11 19:42     ` Dmitry Osipenko
  2 siblings, 0 replies; 63+ messages in thread
From: Dmitry Osipenko @ 2018-03-11 19:40 UTC (permalink / raw)
  To: linux-kernel; +Cc: linux-media

Hello,

On 07.03.2018 19:37, Paul Kocialkowski wrote:
> Hi,
> 
> First off, I'd like to take the occasion to say thank-you for your work.
> This is a major piece of plumbing that is required for me to add support
> for the Allwinner CedarX VPU hardware in upstream Linux. Other drivers,
> such as tegra-vde (that was recently merged in staging) are also badly
> in need of this API.

Certainly it would be good to have a common UAPI. Yet I haven't got my hands on
trying to implement the V4L interface for the tegra-vde driver, but I've taken a
look at Cedrus driver and for now I've one question:

Would it be possible (or maybe already is) to have a single IOCTL that takes
input/output buffers with codec parameters, processes the request(s) and returns
to userspace when everything is done? Having 5 context switches for a single
frame decode (like Cedrus VAAPI driver does) looks like a bit of overhead.

> I have a few comments based on my experience integrating this request
> API with the Cedrus VPU driver (and the associated libva backend), that
> also concern the vim2m driver.
> 
> On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
>> Set the necessary ops for supporting requests in vim2m.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  drivers/media/platform/Kconfig |  1 +
>>  drivers/media/platform/vim2m.c | 75
>> ++++++++++++++++++++++++++++++++++
>>  2 files changed, 76 insertions(+)
>>
>> diff --git a/drivers/media/platform/Kconfig
>> b/drivers/media/platform/Kconfig
>> index 614fbef08ddc..09be0b5f9afe 100644
>> --- a/drivers/media/platform/Kconfig
>> +++ b/drivers/media/platform/Kconfig
> 
> [...]
> 
>> +static int vim2m_request_submit(struct media_request *req,
>> +				struct media_request_entity_data
>> *_data)
>> +{
>> +	struct v4l2_request_entity_data *data;
>> +
>> +	data = to_v4l2_entity_data(_data);
> 
> We need to call v4l2_m2m_try_schedule here so that m2m scheduling can
> happen when only 2 buffers were queued and no other action was taken
> from usespace. In that scenario, m2m scheduling currently doesn't
> happen.
> 
> However, this requires access to the m2m context, which is not easy to
> get from req or _data. I'm not sure that some container_of magic would
> even do the trick here.
> 
>> +	return vb2_request_submit(data);
> 
> vb2_request_submit does not lock the associated request mutex although
> it accesses the associated queued buffers list, which I believe this
> mutex is supposed to protect.
> 
> We could either wrap this call with media_request_lock(req) and
> media_request_unlock(req) or have the lock in the function itself, which
> would require passing it the req pointer.
> 
> The latter would probably be safer for future use of the function.
> 
>> +}
>> +
>> +static const struct media_request_entity_ops vim2m_request_entity_ops
>> = {
>> +	.data_alloc	= vim2m_entity_data_alloc,
>> +	.data_free	= v4l2_request_entity_data_free,
>> +	.submit		= vim2m_request_submit,
>> +};
>> +
>>  /*
>>   * File operations
>>   */
>> @@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
>>  	ctx->dev = dev;
>>  	hdl = &ctx->hdl;
>>  	v4l2_ctrl_handler_init(hdl, 4);
>> +	v4l2_request_entity_init(&ctx->req_entity,
>> &vim2m_request_entity_ops,
>> +				 &ctx->dev->vfd);
>> +	ctx->fh.entity = &ctx->req_entity.base;
>>  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1,
>> 1, 0);
>>  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1,
>> 1, 0);
>>  	v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
>> @@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device
>> *pdev)
>>  	if (!dev)
>>  		return -ENOMEM;
>>  
>> +	v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
>> +			      &v4l2_request_ops);
>> +
>>  	spin_lock_init(&dev->irqlock);
>>  
>>  	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
>> @@ -1012,6 +1085,7 @@ static int vim2m_probe(struct platform_device
>> *pdev)
>>  	vfd = &dev->vfd;
>>  	vfd->lock = &dev->dev_mutex;
>>  	vfd->v4l2_dev = &dev->v4l2_dev;
>> +	vfd->req_mgr = &dev->req_mgr.base;
>>  
>>  	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
>>  	if (ret) {
>> @@ -1054,6 +1128,7 @@ static int vim2m_remove(struct platform_device
>> *pdev)
>>  	del_timer_sync(&dev->timer);
>>  	video_unregister_device(&dev->vfd);
>>  	v4l2_device_unregister(&dev->v4l2_dev);
>> +	v4l2_request_mgr_free(&dev->req_mgr);
>>  
>>  	return 0;
>>  }
> 


-- 
Dmitry

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-07 16:37   ` [RFCv4,19/21] " Paul Kocialkowski
  2018-03-08 13:48     ` Alexandre Courbot
  2018-03-11 19:40     ` Dmitry Osipenko
@ 2018-03-11 19:42     ` Dmitry Osipenko
  2018-03-12  8:10       ` Paul Kocialkowski
  2 siblings, 1 reply; 63+ messages in thread
From: Dmitry Osipenko @ 2018-03-11 19:42 UTC (permalink / raw)
  To: Paul Kocialkowski, Alexandre Courbot, Mauro Carvalho Chehab,
	Hans Verkuil, Laurent Pinchart, Pawel Osciak, Marek Szyprowski,
	Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Maxime Ripard

Hello,

On 07.03.2018 19:37, Paul Kocialkowski wrote:
> Hi,
> 
> First off, I'd like to take the occasion to say thank-you for your work.
> This is a major piece of plumbing that is required for me to add support
> for the Allwinner CedarX VPU hardware in upstream Linux. Other drivers,
> such as tegra-vde (that was recently merged in staging) are also badly
> in need of this API.

Certainly it would be good to have a common UAPI. Yet I haven't got my hands on
trying to implement the V4L interface for the tegra-vde driver, but I've taken a
look at Cedrus driver and for now I've one question:

Would it be possible (or maybe already is) to have a single IOCTL that takes
input/output buffers with codec parameters, processes the request(s) and returns
to userspace when everything is done? Having 5 context switches for a single
frame decode (like Cedrus VAAPI driver does) looks like a bit of overhead.

> I have a few comments based on my experience integrating this request
> API with the Cedrus VPU driver (and the associated libva backend), that
> also concern the vim2m driver.
> 
> On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
>> Set the necessary ops for supporting requests in vim2m.
>>
>> Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> ---
>>  drivers/media/platform/Kconfig |  1 +
>>  drivers/media/platform/vim2m.c | 75
>> ++++++++++++++++++++++++++++++++++
>>  2 files changed, 76 insertions(+)
>>
>> diff --git a/drivers/media/platform/Kconfig
>> b/drivers/media/platform/Kconfig
>> index 614fbef08ddc..09be0b5f9afe 100644
>> --- a/drivers/media/platform/Kconfig
>> +++ b/drivers/media/platform/Kconfig
> 
> [...]
> 
>> +static int vim2m_request_submit(struct media_request *req,
>> +				struct media_request_entity_data
>> *_data)
>> +{
>> +	struct v4l2_request_entity_data *data;
>> +
>> +	data = to_v4l2_entity_data(_data);
> 
> We need to call v4l2_m2m_try_schedule here so that m2m scheduling can
> happen when only 2 buffers were queued and no other action was taken
> from usespace. In that scenario, m2m scheduling currently doesn't
> happen.
> 
> However, this requires access to the m2m context, which is not easy to
> get from req or _data. I'm not sure that some container_of magic would
> even do the trick here.
> 
>> +	return vb2_request_submit(data);
> 
> vb2_request_submit does not lock the associated request mutex although
> it accesses the associated queued buffers list, which I believe this
> mutex is supposed to protect.
> 
> We could either wrap this call with media_request_lock(req) and
> media_request_unlock(req) or have the lock in the function itself, which
> would require passing it the req pointer.
> 
> The latter would probably be safer for future use of the function.
> 
>> +}
>> +
>> +static const struct media_request_entity_ops vim2m_request_entity_ops
>> = {
>> +	.data_alloc	= vim2m_entity_data_alloc,
>> +	.data_free	= v4l2_request_entity_data_free,
>> +	.submit		= vim2m_request_submit,
>> +};
>> +
>>  /*
>>   * File operations
>>   */
>> @@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
>>  	ctx->dev = dev;
>>  	hdl = &ctx->hdl;
>>  	v4l2_ctrl_handler_init(hdl, 4);
>> +	v4l2_request_entity_init(&ctx->req_entity,
>> &vim2m_request_entity_ops,
>> +				 &ctx->dev->vfd);
>> +	ctx->fh.entity = &ctx->req_entity.base;
>>  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1,
>> 1, 0);
>>  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1,
>> 1, 0);
>>  	v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
>> @@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device
>> *pdev)
>>  	if (!dev)
>>  		return -ENOMEM;
>>  
>> +	v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
>> +			      &v4l2_request_ops);
>> +
>>  	spin_lock_init(&dev->irqlock);
>>  
>>  	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
>> @@ -1012,6 +1085,7 @@ static int vim2m_probe(struct platform_device
>> *pdev)
>>  	vfd = &dev->vfd;
>>  	vfd->lock = &dev->dev_mutex;
>>  	vfd->v4l2_dev = &dev->v4l2_dev;
>> +	vfd->req_mgr = &dev->req_mgr.base;
>>  
>>  	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
>>  	if (ret) {
>> @@ -1054,6 +1128,7 @@ static int vim2m_remove(struct platform_device
>> *pdev)
>>  	del_timer_sync(&dev->timer);
>>  	video_unregister_device(&dev->vfd);
>>  	v4l2_device_unregister(&dev->v4l2_dev);
>> +	v4l2_request_mgr_free(&dev->req_mgr);
>>  
>>  	return 0;
>>  }
> 


-- 
Dmitry

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-11 19:42     ` Dmitry Osipenko
@ 2018-03-12  8:10       ` Paul Kocialkowski
  2018-03-12  8:15         ` Tomasz Figa
  0 siblings, 1 reply; 63+ messages in thread
From: Paul Kocialkowski @ 2018-03-12  8:10 UTC (permalink / raw)
  To: Dmitry Osipenko, Alexandre Courbot, Mauro Carvalho Chehab,
	Hans Verkuil, Laurent Pinchart, Pawel Osciak, Marek Szyprowski,
	Tomasz Figa, Sakari Ailus
  Cc: Gustavo Padovan, linux-media, linux-kernel, Maxime Ripard

[-- Attachment #1: Type: text/plain, Size: 5665 bytes --]

Hi,

On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
> Hello,
> 
> On 07.03.2018 19:37, Paul Kocialkowski wrote:
> > Hi,
> > 
> > First off, I'd like to take the occasion to say thank-you for your
> > work.
> > This is a major piece of plumbing that is required for me to add
> > support
> > for the Allwinner CedarX VPU hardware in upstream Linux. Other
> > drivers,
> > such as tegra-vde (that was recently merged in staging) are also
> > badly
> > in need of this API.
> 
> Certainly it would be good to have a common UAPI. Yet I haven't got my
> hands on
> trying to implement the V4L interface for the tegra-vde driver, but
> I've taken a
> look at Cedrus driver and for now I've one question:
> 
> Would it be possible (or maybe already is) to have a single IOCTL that
> takes input/output buffers with codec parameters, processes the
> request(s) and returns to userspace when everything is done? Having 5
> context switches for a single frame decode (like Cedrus VAAPI driver
> does) looks like a bit of overhead.

The V4L2 interface exposes ioctls for differents actions and I don't
think there's a combined ioctl for this. The request API was introduced
precisely because we need to have consistency between the various ioctls
needed for each frame. Maybe one single (atomic) ioctl would have worked
too, but that's apparently not how the V4L2 API was designed.

I don't think there is any particular overhead caused by having n ioctls
instead of a single one. At least that would be very surprising IMHO.

> > I have a few comments based on my experience integrating this
> > request API with the Cedrus VPU driver (and the associated libva
> > backend), that also concern the vim2m driver.
> > 
> > On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
> > > Set the necessary ops for supporting requests in vim2m.
> > > 
> > > Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
> > > ---
> > >  drivers/media/platform/Kconfig |  1 +
> > >  drivers/media/platform/vim2m.c | 75
> > > ++++++++++++++++++++++++++++++++++
> > >  2 files changed, 76 insertions(+)
> > > 
> > > diff --git a/drivers/media/platform/Kconfig
> > > b/drivers/media/platform/Kconfig
> > > index 614fbef08ddc..09be0b5f9afe 100644
> > > --- a/drivers/media/platform/Kconfig
> > > +++ b/drivers/media/platform/Kconfig
> > 
> > [...]
> > 
> > > +static int vim2m_request_submit(struct media_request *req,
> > > +				struct media_request_entity_data
> > > *_data)
> > > +{
> > > +	struct v4l2_request_entity_data *data;
> > > +
> > > +	data = to_v4l2_entity_data(_data);
> > 
> > We need to call v4l2_m2m_try_schedule here so that m2m scheduling
> > can
> > happen when only 2 buffers were queued and no other action was taken
> > from usespace. In that scenario, m2m scheduling currently doesn't
> > happen.
> > 
> > However, this requires access to the m2m context, which is not easy
> > to
> > get from req or _data. I'm not sure that some container_of magic
> > would
> > even do the trick here.
> > 
> > > +	return vb2_request_submit(data);
> > 
> > vb2_request_submit does not lock the associated request mutex
> > although
> > it accesses the associated queued buffers list, which I believe this
> > mutex is supposed to protect.
> > 
> > We could either wrap this call with media_request_lock(req) and
> > media_request_unlock(req) or have the lock in the function itself,
> > which
> > would require passing it the req pointer.
> > 
> > The latter would probably be safer for future use of the function.
> > 
> > > +}
> > > +
> > > +static const struct media_request_entity_ops
> > > vim2m_request_entity_ops
> > > = {
> > > +	.data_alloc	= vim2m_entity_data_alloc,
> > > +	.data_free	= v4l2_request_entity_data_free,
> > > +	.submit		= vim2m_request_submit,
> > > +};
> > > +
> > >  /*
> > >   * File operations
> > >   */
> > > @@ -900,6 +967,9 @@ static int vim2m_open(struct file *file)
> > >  	ctx->dev = dev;
> > >  	hdl = &ctx->hdl;
> > >  	v4l2_ctrl_handler_init(hdl, 4);
> > > +	v4l2_request_entity_init(&ctx->req_entity,
> > > &vim2m_request_entity_ops,
> > > +				 &ctx->dev->vfd);
> > > +	ctx->fh.entity = &ctx->req_entity.base;
> > >  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP,
> > > 0, 1,
> > > 1, 0);
> > >  	v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP,
> > > 0, 1,
> > > 1, 0);
> > >  	v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec,
> > > NULL);
> > > @@ -999,6 +1069,9 @@ static int vim2m_probe(struct platform_device
> > > *pdev)
> > >  	if (!dev)
> > >  		return -ENOMEM;
> > >  
> > > +	v4l2_request_mgr_init(&dev->req_mgr, &dev->vfd,
> > > +			      &v4l2_request_ops);
> > > +
> > >  	spin_lock_init(&dev->irqlock);
> > >  
> > >  	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> > > @@ -1012,6 +1085,7 @@ static int vim2m_probe(struct
> > > platform_device
> > > *pdev)
> > >  	vfd = &dev->vfd;
> > >  	vfd->lock = &dev->dev_mutex;
> > >  	vfd->v4l2_dev = &dev->v4l2_dev;
> > > +	vfd->req_mgr = &dev->req_mgr.base;
> > >  
> > >  	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
> > >  	if (ret) {
> > > @@ -1054,6 +1128,7 @@ static int vim2m_remove(struct
> > > platform_device
> > > *pdev)
> > >  	del_timer_sync(&dev->timer);
> > >  	video_unregister_device(&dev->vfd);
> > >  	v4l2_device_unregister(&dev->v4l2_dev);
> > > +	v4l2_request_mgr_free(&dev->req_mgr);
> > >  
> > >  	return 0;
> > >  }
> 
> 
-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-12  8:10       ` Paul Kocialkowski
@ 2018-03-12  8:15         ` Tomasz Figa
  2018-03-12  8:25           ` Paul Kocialkowski
  2018-03-12 12:32           ` Alexandre Courbot
  0 siblings, 2 replies; 63+ messages in thread
From: Tomasz Figa @ 2018-03-12  8:15 UTC (permalink / raw)
  To: Paul Kocialkowski, Dmitry Osipenko
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Hans Verkuil,
	Laurent Pinchart, Pawel Osciak, Marek Szyprowski, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List,
	Linux Kernel Mailing List, Maxime Ripard

Hi Paul, Dmitry,

On Mon, Mar 12, 2018 at 5:10 PM, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> Hi,
>
> On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
>> Hello,
>>
>> On 07.03.2018 19:37, Paul Kocialkowski wrote:
>> > Hi,
>> >
>> > First off, I'd like to take the occasion to say thank-you for your
>> > work.
>> > This is a major piece of plumbing that is required for me to add
>> > support
>> > for the Allwinner CedarX VPU hardware in upstream Linux. Other
>> > drivers,
>> > such as tegra-vde (that was recently merged in staging) are also
>> > badly
>> > in need of this API.
>>
>> Certainly it would be good to have a common UAPI. Yet I haven't got my
>> hands on
>> trying to implement the V4L interface for the tegra-vde driver, but
>> I've taken a
>> look at Cedrus driver and for now I've one question:
>>
>> Would it be possible (or maybe already is) to have a single IOCTL that
>> takes input/output buffers with codec parameters, processes the
>> request(s) and returns to userspace when everything is done? Having 5
>> context switches for a single frame decode (like Cedrus VAAPI driver
>> does) looks like a bit of overhead.
>
> The V4L2 interface exposes ioctls for differents actions and I don't
> think there's a combined ioctl for this. The request API was introduced
> precisely because we need to have consistency between the various ioctls
> needed for each frame. Maybe one single (atomic) ioctl would have worked
> too, but that's apparently not how the V4L2 API was designed.
>
> I don't think there is any particular overhead caused by having n ioctls
> instead of a single one. At least that would be very surprising IMHO.

Well, there is small syscall overhead, which normally shouldn't be
very painful, although with all the speculative execution hardening,
can't be sure of anything anymore. :)

Hans and Alex can correct me if I'm wrong, but I believe there is a
more atomic-like API being planned, which would only need one IOCTL to
do everything. However, that would be a more serious change to the
V4L2 interfaces, so should be decoupled from Request API itself.

Best regards,
Tomasz

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-12  8:15         ` Tomasz Figa
@ 2018-03-12  8:25           ` Paul Kocialkowski
  2018-03-12  8:29             ` Tomasz Figa
  2018-03-12 12:32           ` Alexandre Courbot
  1 sibling, 1 reply; 63+ messages in thread
From: Paul Kocialkowski @ 2018-03-12  8:25 UTC (permalink / raw)
  To: Tomasz Figa, Dmitry Osipenko
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Hans Verkuil,
	Laurent Pinchart, Pawel Osciak, Marek Szyprowski, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List,
	Linux Kernel Mailing List, Maxime Ripard

[-- Attachment #1: Type: text/plain, Size: 2728 bytes --]

Hi,

On Mon, 2018-03-12 at 17:15 +0900, Tomasz Figa wrote:
> Hi Paul, Dmitry,
> 
> On Mon, Mar 12, 2018 at 5:10 PM, Paul Kocialkowski
> <paul.kocialkowski@bootlin.com> wrote:
> > Hi,
> > 
> > On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
> > > Hello,
> > > 
> > > On 07.03.2018 19:37, Paul Kocialkowski wrote:
> > > > Hi,
> > > > 
> > > > First off, I'd like to take the occasion to say thank-you for
> > > > your
> > > > work.
> > > > This is a major piece of plumbing that is required for me to add
> > > > support
> > > > for the Allwinner CedarX VPU hardware in upstream Linux. Other
> > > > drivers,
> > > > such as tegra-vde (that was recently merged in staging) are also
> > > > badly
> > > > in need of this API.
> > > 
> > > Certainly it would be good to have a common UAPI. Yet I haven't
> > > got my
> > > hands on
> > > trying to implement the V4L interface for the tegra-vde driver,
> > > but
> > > I've taken a
> > > look at Cedrus driver and for now I've one question:
> > > 
> > > Would it be possible (or maybe already is) to have a single IOCTL
> > > that
> > > takes input/output buffers with codec parameters, processes the
> > > request(s) and returns to userspace when everything is done?
> > > Having 5
> > > context switches for a single frame decode (like Cedrus VAAPI
> > > driver
> > > does) looks like a bit of overhead.
> > 
> > The V4L2 interface exposes ioctls for differents actions and I don't
> > think there's a combined ioctl for this. The request API was
> > introduced
> > precisely because we need to have consistency between the various
> > ioctls
> > needed for each frame. Maybe one single (atomic) ioctl would have
> > worked
> > too, but that's apparently not how the V4L2 API was designed.
> > 
> > I don't think there is any particular overhead caused by having n
> > ioctls
> > instead of a single one. At least that would be very surprising
> > IMHO.
> 
> Well, there is small syscall overhead, which normally shouldn't be
> very painful, although with all the speculative execution hardening,
> can't be sure of anything anymore. :)

Oh, my mistake then, I had it in mind that it is not really something
noticeable. Hopefully, it won't be a limiting factor in our cases.

> Hans and Alex can correct me if I'm wrong, but I believe there is a
> more atomic-like API being planned, which would only need one IOCTL to
> do everything. However, that would be a more serious change to the
> V4L2 interfaces, so should be decoupled from Request API itself.
> 
> Best regards,
> Tomasz
-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-12  8:25           ` Paul Kocialkowski
@ 2018-03-12  8:29             ` Tomasz Figa
  2018-03-12 12:21               ` Dmitry Osipenko
  0 siblings, 1 reply; 63+ messages in thread
From: Tomasz Figa @ 2018-03-12  8:29 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: Dmitry Osipenko, Alexandre Courbot, Mauro Carvalho Chehab,
	Hans Verkuil, Laurent Pinchart, Pawel Osciak, Marek Szyprowski,
	Sakari Ailus, Gustavo Padovan, Linux Media Mailing List,
	Linux Kernel Mailing List, Maxime Ripard

On Mon, Mar 12, 2018 at 5:25 PM, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> Hi,
>
> On Mon, 2018-03-12 at 17:15 +0900, Tomasz Figa wrote:
>> Hi Paul, Dmitry,
>>
>> On Mon, Mar 12, 2018 at 5:10 PM, Paul Kocialkowski
>> <paul.kocialkowski@bootlin.com> wrote:
>> > Hi,
>> >
>> > On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
>> > > Hello,
>> > >
>> > > On 07.03.2018 19:37, Paul Kocialkowski wrote:
>> > > > Hi,
>> > > >
>> > > > First off, I'd like to take the occasion to say thank-you for
>> > > > your
>> > > > work.
>> > > > This is a major piece of plumbing that is required for me to add
>> > > > support
>> > > > for the Allwinner CedarX VPU hardware in upstream Linux. Other
>> > > > drivers,
>> > > > such as tegra-vde (that was recently merged in staging) are also
>> > > > badly
>> > > > in need of this API.
>> > >
>> > > Certainly it would be good to have a common UAPI. Yet I haven't
>> > > got my
>> > > hands on
>> > > trying to implement the V4L interface for the tegra-vde driver,
>> > > but
>> > > I've taken a
>> > > look at Cedrus driver and for now I've one question:
>> > >
>> > > Would it be possible (or maybe already is) to have a single IOCTL
>> > > that
>> > > takes input/output buffers with codec parameters, processes the
>> > > request(s) and returns to userspace when everything is done?
>> > > Having 5
>> > > context switches for a single frame decode (like Cedrus VAAPI
>> > > driver
>> > > does) looks like a bit of overhead.
>> >
>> > The V4L2 interface exposes ioctls for differents actions and I don't
>> > think there's a combined ioctl for this. The request API was
>> > introduced
>> > precisely because we need to have consistency between the various
>> > ioctls
>> > needed for each frame. Maybe one single (atomic) ioctl would have
>> > worked
>> > too, but that's apparently not how the V4L2 API was designed.
>> >
>> > I don't think there is any particular overhead caused by having n
>> > ioctls
>> > instead of a single one. At least that would be very surprising
>> > IMHO.
>>
>> Well, there is small syscall overhead, which normally shouldn't be
>> very painful, although with all the speculative execution hardening,
>> can't be sure of anything anymore. :)
>
> Oh, my mistake then, I had it in mind that it is not really something
> noticeable. Hopefully, it won't be a limiting factor in our cases.

With typical frame rates achievable by hardware codecs, I doubt that
it would be a limiting factor. We're using a similar API (a WiP
version of pre-Request API prototype from long ago) in Chrome OS
already without any performance issues.

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-12  8:29             ` Tomasz Figa
@ 2018-03-12 12:21               ` Dmitry Osipenko
  0 siblings, 0 replies; 63+ messages in thread
From: Dmitry Osipenko @ 2018-03-12 12:21 UTC (permalink / raw)
  To: Tomasz Figa, Paul Kocialkowski
  Cc: Alexandre Courbot, Mauro Carvalho Chehab, Hans Verkuil,
	Laurent Pinchart, Pawel Osciak, Marek Szyprowski, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List,
	Linux Kernel Mailing List, Maxime Ripard

On 12.03.2018 11:29, Tomasz Figa wrote:
> On Mon, Mar 12, 2018 at 5:25 PM, Paul Kocialkowski
> <paul.kocialkowski@bootlin.com> wrote:
>> Hi,
>>
>> On Mon, 2018-03-12 at 17:15 +0900, Tomasz Figa wrote:
>>> Hi Paul, Dmitry,
>>>
>>> On Mon, Mar 12, 2018 at 5:10 PM, Paul Kocialkowski
>>> <paul.kocialkowski@bootlin.com> wrote:
>>>> Hi,
>>>>
>>>> On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
>>>>> Hello,
>>>>>
>>>>> On 07.03.2018 19:37, Paul Kocialkowski wrote:
>>>>>> Hi,
>>>>>>
>>>>>> First off, I'd like to take the occasion to say thank-you for
>>>>>> your
>>>>>> work.
>>>>>> This is a major piece of plumbing that is required for me to add
>>>>>> support
>>>>>> for the Allwinner CedarX VPU hardware in upstream Linux. Other
>>>>>> drivers,
>>>>>> such as tegra-vde (that was recently merged in staging) are also
>>>>>> badly
>>>>>> in need of this API.
>>>>>
>>>>> Certainly it would be good to have a common UAPI. Yet I haven't
>>>>> got my
>>>>> hands on
>>>>> trying to implement the V4L interface for the tegra-vde driver,
>>>>> but
>>>>> I've taken a
>>>>> look at Cedrus driver and for now I've one question:
>>>>>
>>>>> Would it be possible (or maybe already is) to have a single IOCTL
>>>>> that
>>>>> takes input/output buffers with codec parameters, processes the
>>>>> request(s) and returns to userspace when everything is done?
>>>>> Having 5
>>>>> context switches for a single frame decode (like Cedrus VAAPI
>>>>> driver
>>>>> does) looks like a bit of overhead.
>>>>
>>>> The V4L2 interface exposes ioctls for differents actions and I don't
>>>> think there's a combined ioctl for this. The request API was
>>>> introduced
>>>> precisely because we need to have consistency between the various
>>>> ioctls
>>>> needed for each frame. Maybe one single (atomic) ioctl would have
>>>> worked
>>>> too, but that's apparently not how the V4L2 API was designed.
>>>>
>>>> I don't think there is any particular overhead caused by having n
>>>> ioctls
>>>> instead of a single one. At least that would be very surprising
>>>> IMHO.
>>>
>>> Well, there is small syscall overhead, which normally shouldn't be
>>> very painful, although with all the speculative execution hardening,
>>> can't be sure of anything anymore. :)
>>
>> Oh, my mistake then, I had it in mind that it is not really something
>> noticeable. Hopefully, it won't be a limiting factor in our cases.
> 
> With typical frame rates achievable by hardware codecs, I doubt that
> it would be a limiting factor. We're using a similar API (a WiP
> version of pre-Request API prototype from long ago) in Chrome OS
> already without any performance issues.

Thank you very much for the answers!

The syscalls overhead is miserable in comparison to the rest of decoding, though
I wanted to clarify whether there is a way to avoid it. Atomic API sounds like
something that would suit well for that.

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-12  8:15         ` Tomasz Figa
  2018-03-12  8:25           ` Paul Kocialkowski
@ 2018-03-12 12:32           ` Alexandre Courbot
  2018-03-12 14:44             ` Dmitry Osipenko
  1 sibling, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-03-12 12:32 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Paul Kocialkowski, Dmitry Osipenko, Mauro Carvalho Chehab,
	Hans Verkuil, Laurent Pinchart, Pawel Osciak, Marek Szyprowski,
	Sakari Ailus, Gustavo Padovan, Linux Media Mailing List,
	Linux Kernel Mailing List, Maxime Ripard

On Mon, Mar 12, 2018 at 5:15 PM, Tomasz Figa <tfiga@chromium.org> wrote:
> Hi Paul, Dmitry,
>
> On Mon, Mar 12, 2018 at 5:10 PM, Paul Kocialkowski
> <paul.kocialkowski@bootlin.com> wrote:
>> Hi,
>>
>> On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
>>> Hello,
>>>
>>> On 07.03.2018 19:37, Paul Kocialkowski wrote:
>>> > Hi,
>>> >
>>> > First off, I'd like to take the occasion to say thank-you for your
>>> > work.
>>> > This is a major piece of plumbing that is required for me to add
>>> > support
>>> > for the Allwinner CedarX VPU hardware in upstream Linux. Other
>>> > drivers,
>>> > such as tegra-vde (that was recently merged in staging) are also
>>> > badly
>>> > in need of this API.
>>>
>>> Certainly it would be good to have a common UAPI. Yet I haven't got my
>>> hands on
>>> trying to implement the V4L interface for the tegra-vde driver, but
>>> I've taken a
>>> look at Cedrus driver and for now I've one question:
>>>
>>> Would it be possible (or maybe already is) to have a single IOCTL that
>>> takes input/output buffers with codec parameters, processes the
>>> request(s) and returns to userspace when everything is done? Having 5
>>> context switches for a single frame decode (like Cedrus VAAPI driver
>>> does) looks like a bit of overhead.
>>
>> The V4L2 interface exposes ioctls for differents actions and I don't
>> think there's a combined ioctl for this. The request API was introduced
>> precisely because we need to have consistency between the various ioctls
>> needed for each frame. Maybe one single (atomic) ioctl would have worked
>> too, but that's apparently not how the V4L2 API was designed.
>>
>> I don't think there is any particular overhead caused by having n ioctls
>> instead of a single one. At least that would be very surprising IMHO.
>
> Well, there is small syscall overhead, which normally shouldn't be
> very painful, although with all the speculative execution hardening,
> can't be sure of anything anymore. :)
>
> Hans and Alex can correct me if I'm wrong, but I believe there is a
> more atomic-like API being planned, which would only need one IOCTL to
> do everything. However, that would be a more serious change to the
> V4L2 interfaces, so should be decoupled from Request API itself.

Indeed, we discussed the possibility to setup and submit requests in
one syscall, similarly (at least in spirit) to the DRM atomic API.

This has only been discussed though, and as a feature to consider
*after* the request API is merged for codecs (as the more complex
camera use-cases would benefit more from it). As Tomasz mentioned, the
overhead of ioctls is somehow negligible compared to the workload of
the encoding/decoding itself, although I suppose it can still add up.
The main advantage I can see for this is a simpler and less
error-prone setup of requests for user-space.

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-12 12:32           ` Alexandre Courbot
@ 2018-03-12 14:44             ` Dmitry Osipenko
  0 siblings, 0 replies; 63+ messages in thread
From: Dmitry Osipenko @ 2018-03-12 14:44 UTC (permalink / raw)
  To: Alexandre Courbot, Tomasz Figa
  Cc: Paul Kocialkowski, Mauro Carvalho Chehab, Hans Verkuil,
	Laurent Pinchart, Pawel Osciak, Marek Szyprowski, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List,
	Linux Kernel Mailing List, Maxime Ripard

On 12.03.2018 15:32, Alexandre Courbot wrote:
> On Mon, Mar 12, 2018 at 5:15 PM, Tomasz Figa <tfiga@chromium.org> wrote:
>> Hi Paul, Dmitry,
>>
>> On Mon, Mar 12, 2018 at 5:10 PM, Paul Kocialkowski
>> <paul.kocialkowski@bootlin.com> wrote:
>>> Hi,
>>>
>>> On Sun, 2018-03-11 at 22:42 +0300, Dmitry Osipenko wrote:
>>>> Hello,
>>>>
>>>> On 07.03.2018 19:37, Paul Kocialkowski wrote:
>>>>> Hi,
>>>>>
>>>>> First off, I'd like to take the occasion to say thank-you for your
>>>>> work.
>>>>> This is a major piece of plumbing that is required for me to add
>>>>> support
>>>>> for the Allwinner CedarX VPU hardware in upstream Linux. Other
>>>>> drivers,
>>>>> such as tegra-vde (that was recently merged in staging) are also
>>>>> badly
>>>>> in need of this API.
>>>>
>>>> Certainly it would be good to have a common UAPI. Yet I haven't got my
>>>> hands on
>>>> trying to implement the V4L interface for the tegra-vde driver, but
>>>> I've taken a
>>>> look at Cedrus driver and for now I've one question:
>>>>
>>>> Would it be possible (or maybe already is) to have a single IOCTL that
>>>> takes input/output buffers with codec parameters, processes the
>>>> request(s) and returns to userspace when everything is done? Having 5
>>>> context switches for a single frame decode (like Cedrus VAAPI driver
>>>> does) looks like a bit of overhead.
>>>
>>> The V4L2 interface exposes ioctls for differents actions and I don't
>>> think there's a combined ioctl for this. The request API was introduced
>>> precisely because we need to have consistency between the various ioctls
>>> needed for each frame. Maybe one single (atomic) ioctl would have worked
>>> too, but that's apparently not how the V4L2 API was designed.
>>>
>>> I don't think there is any particular overhead caused by having n ioctls
>>> instead of a single one. At least that would be very surprising IMHO.
>>
>> Well, there is small syscall overhead, which normally shouldn't be
>> very painful, although with all the speculative execution hardening,
>> can't be sure of anything anymore. :)
>>
>> Hans and Alex can correct me if I'm wrong, but I believe there is a
>> more atomic-like API being planned, which would only need one IOCTL to
>> do everything. However, that would be a more serious change to the
>> V4L2 interfaces, so should be decoupled from Request API itself.
> 
> Indeed, we discussed the possibility to setup and submit requests in
> one syscall, similarly (at least in spirit) to the DRM atomic API.
> 
> This has only been discussed though, and as a feature to consider
> *after* the request API is merged for codecs (as the more complex
> camera use-cases would benefit more from it). As Tomasz mentioned, the
> overhead of ioctls is somehow negligible compared to the workload of
> the encoding/decoding itself, although I suppose it can still add up.
> The main advantage I can see for this is a simpler and less
> error-prone setup of requests for user-space.

Indeed, atomic API should be nicer from a userspace perspective and a bit more
optimal for at least some of workloads. Would be good to have it.

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-09 14:35       ` Paul Kocialkowski
@ 2018-03-13 10:24         ` Alexandre Courbot
  2018-03-14 13:25           ` Paul Kocialkowski
  0 siblings, 1 reply; 63+ messages in thread
From: Alexandre Courbot @ 2018-03-13 10:24 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML, Maxime Ripard

On Fri, Mar 9, 2018 at 11:35 PM, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> Hi,
>
> On Thu, 2018-03-08 at 22:48 +0900, Alexandre Courbot wrote:
>> Hi Paul!
>>
>> Thanks a lot for taking the time to try this! I am also working on
>> getting it to work with an actual driver, but you apparently found
>> rough edges that I missed.
>>
>> On Thu, Mar 8, 2018 at 1:37 AM, Paul Kocialkowski
>> <paul.kocialkowski@bootlin.com> wrote:
>> > Hi,
>> >
>> > First off, I'd like to take the occasion to say thank-you for your
>> > work.
>> > This is a major piece of plumbing that is required for me to add
>> > support
>> > for the Allwinner CedarX VPU hardware in upstream Linux. Other
>> > drivers,
>> > such as tegra-vde (that was recently merged in staging) are also
>> > badly
>> > in need of this API.
>> >
>> > I have a few comments based on my experience integrating this
>> > request
>> > API with the Cedrus VPU driver (and the associated libva backend),
>> > that
>> > also concern the vim2m driver.
>> >
>> > On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
>> > > Set the necessary ops for supporting requests in vim2m.
>> > >
>> > > Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
>> > > ---
>> > >  drivers/media/platform/Kconfig |  1 +
>> > >  drivers/media/platform/vim2m.c | 75
>> > > ++++++++++++++++++++++++++++++++++
>> > >  2 files changed, 76 insertions(+)
>> > >
>> > > diff --git a/drivers/media/platform/Kconfig
>> > > b/drivers/media/platform/Kconfig
>> > > index 614fbef08ddc..09be0b5f9afe 100644
>> > > --- a/drivers/media/platform/Kconfig
>> > > +++ b/drivers/media/platform/Kconfig
>> >
>> > [...]
>> >
>> > > +static int vim2m_request_submit(struct media_request *req,
>> > > +                             struct media_request_entity_data
>> > > *_data)
>> > > +{
>> > > +     struct v4l2_request_entity_data *data;
>> > > +
>> > > +     data = to_v4l2_entity_data(_data);
>> >
>> > We need to call v4l2_m2m_try_schedule here so that m2m scheduling
>> > can
>> > happen when only 2 buffers were queued and no other action was taken
>> > from usespace. In that scenario, m2m scheduling currently doesn't
>> > happen.
>>
>> I don't think I understand the sequence of events that results in
>> v4l2_m2m_try_schedule() not being called. Do you mean something like:
>>
>> *
>> * QBUF on output queue with request set
>> * QBUF on capture queue
>> * SUBMIT_REQUEST
>>
>> ?
>>
>> The call to vb2_request_submit() right after should trigger
>> v4l2_m2m_try_schedule(), since the buffers associated to the request
>> will enter the vb2 queue and be passed to the m2m framework, which
>> will then call v4l2_m2m_try_schedule(). Or maybe you are thinking
>> about a different sequence of events?
>
> This is indeed the sequence of events that I'm seeing, but the
> scheduling call simply did not happen on vb2_request_submit. I suppose I will need to investigate some more to find out exactly why.
>
> IIRC, the m2m qbuf function is called (and fails to schedule) when the
> ioctl happens, not when the task is submitted.
>
> This issue is seen with vim2m as well as the rencently-submitted sunxi-
> cedrus driver (with the in-driver calls to v4l2_m2m_try_schedule
> removed, obviously). If needs be, I could provide a standalone test
> program to reproduce it.

If you have a standalone program that can reproduce this on vim2m,
then I would like to see it indeed, if only to understand what I have
missed.

Thanks,
Alex.

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-13 10:24         ` Alexandre Courbot
@ 2018-03-14 13:25           ` Paul Kocialkowski
  2018-03-19  9:17             ` Alexandre Courbot
  0 siblings, 1 reply; 63+ messages in thread
From: Paul Kocialkowski @ 2018-03-14 13:25 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML, Maxime Ripard

[-- Attachment #1: Type: text/plain, Size: 2923 bytes --]

Hi,

On Tue, 2018-03-13 at 19:24 +0900, Alexandre Courbot wrote:
> On Fri, Mar 9, 2018 at 11:35 PM, Paul Kocialkowski
> <paul.kocialkowski@bootlin.com> wrote:
> > Hi,
> > 
> > On Thu, 2018-03-08 at 22:48 +0900, Alexandre Courbot wrote:
> > > Hi Paul!
> > > 
> > > Thanks a lot for taking the time to try this! I am also working on
> > > getting it to work with an actual driver, but you apparently found
> > > rough edges that I missed.
> > > 
> > > On Thu, Mar 8, 2018 at 1:37 AM, Paul Kocialkowski
> > > <paul.kocialkowski@bootlin.com> wrote:
> > > > On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:

[...]

> > > > > +static int vim2m_request_submit(struct media_request *req,
> > > > > +                             struct media_request_entity_data
> > > > > *_data)
> > > > > +{
> > > > > +     struct v4l2_request_entity_data *data;
> > > > > +
> > > > > +     data = to_v4l2_entity_data(_data);
> > > > 
> > > > We need to call v4l2_m2m_try_schedule here so that m2m
> > > > scheduling
> > > > can
> > > > happen when only 2 buffers were queued and no other action was
> > > > taken
> > > > from usespace. In that scenario, m2m scheduling currently
> > > > doesn't
> > > > happen.
> > > 
> > > I don't think I understand the sequence of events that results in
> > > v4l2_m2m_try_schedule() not being called. Do you mean something
> > > like:
> > > 
> > > *
> > > * QBUF on output queue with request set
> > > * QBUF on capture queue
> > > * SUBMIT_REQUEST
> > > 
> > > ?
> > > 
> > > The call to vb2_request_submit() right after should trigger
> > > v4l2_m2m_try_schedule(), since the buffers associated to the
> > > request
> > > will enter the vb2 queue and be passed to the m2m framework, which
> > > will then call v4l2_m2m_try_schedule(). Or maybe you are thinking
> > > about a different sequence of events?
> > 
> > This is indeed the sequence of events that I'm seeing, but the
> > scheduling call simply did not happen on vb2_request_submit. I
> > suppose I will need to investigate some more to find out exactly
> > why.
> > 
> > IIRC, the m2m qbuf function is called (and fails to schedule) when
> > the
> > ioctl happens, not when the task is submitted.
> > 
> > This issue is seen with vim2m as well as the rencently-submitted
> > sunxi-
> > cedrus driver (with the in-driver calls to v4l2_m2m_try_schedule
> > removed, obviously). If needs be, I could provide a standalone test
> > program to reproduce it.
> 
> If you have a standalone program that can reproduce this on vim2m,
> then I would like to see it indeed, if only to understand what I have
> missed.

You can find the test file for this use case at:
https://gist.github.com/paulkocialkowski/4cfa350e1bbe8e3bf714480bba83ea72

Cheers!

-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [RFCv4,19/21] media: vim2m: add request support
  2018-03-14 13:25           ` Paul Kocialkowski
@ 2018-03-19  9:17             ` Alexandre Courbot
  0 siblings, 0 replies; 63+ messages in thread
From: Alexandre Courbot @ 2018-03-19  9:17 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: Mauro Carvalho Chehab, Hans Verkuil, Laurent Pinchart,
	Pawel Osciak, Marek Szyprowski, Tomasz Figa, Sakari Ailus,
	Gustavo Padovan, Linux Media Mailing List, LKML, Maxime Ripard

On Wed, Mar 14, 2018 at 10:25 PM, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> Hi,
>
> On Tue, 2018-03-13 at 19:24 +0900, Alexandre Courbot wrote:
>> On Fri, Mar 9, 2018 at 11:35 PM, Paul Kocialkowski
>> <paul.kocialkowski@bootlin.com> wrote:
>> > Hi,
>> >
>> > On Thu, 2018-03-08 at 22:48 +0900, Alexandre Courbot wrote:
>> > > Hi Paul!
>> > >
>> > > Thanks a lot for taking the time to try this! I am also working on
>> > > getting it to work with an actual driver, but you apparently found
>> > > rough edges that I missed.
>> > >
>> > > On Thu, Mar 8, 2018 at 1:37 AM, Paul Kocialkowski
>> > > <paul.kocialkowski@bootlin.com> wrote:
>> > > > On Tue, 2018-02-20 at 13:44 +0900, Alexandre Courbot wrote:
>
> [...]
>
>> > > > > +static int vim2m_request_submit(struct media_request *req,
>> > > > > +                             struct media_request_entity_data
>> > > > > *_data)
>> > > > > +{
>> > > > > +     struct v4l2_request_entity_data *data;
>> > > > > +
>> > > > > +     data = to_v4l2_entity_data(_data);
>> > > >
>> > > > We need to call v4l2_m2m_try_schedule here so that m2m
>> > > > scheduling
>> > > > can
>> > > > happen when only 2 buffers were queued and no other action was
>> > > > taken
>> > > > from usespace. In that scenario, m2m scheduling currently
>> > > > doesn't
>> > > > happen.
>> > >
>> > > I don't think I understand the sequence of events that results in
>> > > v4l2_m2m_try_schedule() not being called. Do you mean something
>> > > like:
>> > >
>> > > *
>> > > * QBUF on output queue with request set
>> > > * QBUF on capture queue
>> > > * SUBMIT_REQUEST
>> > >
>> > > ?
>> > >
>> > > The call to vb2_request_submit() right after should trigger
>> > > v4l2_m2m_try_schedule(), since the buffers associated to the
>> > > request
>> > > will enter the vb2 queue and be passed to the m2m framework, which
>> > > will then call v4l2_m2m_try_schedule(). Or maybe you are thinking
>> > > about a different sequence of events?
>> >
>> > This is indeed the sequence of events that I'm seeing, but the
>> > scheduling call simply did not happen on vb2_request_submit. I
>> > suppose I will need to investigate some more to find out exactly
>> > why.
>> >
>> > IIRC, the m2m qbuf function is called (and fails to schedule) when
>> > the
>> > ioctl happens, not when the task is submitted.
>> >
>> > This issue is seen with vim2m as well as the rencently-submitted
>> > sunxi-
>> > cedrus driver (with the in-driver calls to v4l2_m2m_try_schedule
>> > removed, obviously). If needs be, I could provide a standalone test
>> > program to reproduce it.
>>
>> If you have a standalone program that can reproduce this on vim2m,
>> then I would like to see it indeed, if only to understand what I have
>> missed.
>
> You can find the test file for this use case at:
> https://gist.github.com/paulkocialkowski/4cfa350e1bbe8e3bf714480bba83ea72

Thanks, I have been able to see what the issue was. One indeed needs
to call v4l2_m2m_try_schedule() when the request is queued, since the
driver qbuf() hook does not do it automatically.

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

end of thread, other threads:[~2018-03-19  9:18 UTC | newest]

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-20  4:44 [RFCv4 00/21] Request API Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 01/21] media: add request API core and UAPI Alexandre Courbot
2018-02-20 10:36   ` Hans Verkuil
2018-02-21  6:01     ` Alexandre Courbot
2018-02-21  7:29       ` Hans Verkuil
2018-02-22  9:30         ` Alexandre Courbot
2018-02-22  9:38           ` Hans Verkuil
2018-02-20  4:44 ` [RFCv4 02/21] v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 03/21] v4l2-ctrls: prepare internal structs for request API Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 04/21] v4l2-ctrls: add core " Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 05/21] v4l2-ctrls: use ref in helper instead of ctrl Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 06/21] v4l2-ctrls: support g/s_ext_ctrls for requests Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 07/21] v4l2-ctrls: add v4l2_ctrl_request_setup Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 08/21] [WAR] v4l2-ctrls: do not clone non-standard controls Alexandre Courbot
2018-02-20 13:05   ` Hans Verkuil
2018-02-20  4:44 ` [RFCv4 09/21] v4l2: add request API support Alexandre Courbot
2018-02-20  7:36   ` Philippe Ombredanne
2018-02-20  8:03     ` Alexandre Courbot
2018-02-20 13:25   ` Hans Verkuil
2018-02-21  6:01     ` Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 10/21] videodev2.h: Add request_fd field to v4l2_buffer Alexandre Courbot
2018-02-20 15:20   ` Hans Verkuil
2018-02-21  6:01     ` Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 11/21] media: v4l2_fh: add request entity field Alexandre Courbot
2018-02-20 15:24   ` Hans Verkuil
2018-02-21  6:01     ` Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 12/21] media: videobuf2: add support for requests Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 13/21] media: videobuf2-v4l2: " Alexandre Courbot
2018-02-20 16:18   ` Hans Verkuil
2018-02-21  6:01     ` Alexandre Courbot
2018-02-23  6:34     ` Tomasz Figa
2018-02-23  7:21       ` Hans Verkuil
2018-02-23  7:33         ` Tomasz Figa
2018-02-23  7:43           ` Hans Verkuil
2018-03-07 16:50   ` [RFCv4,13/21] " Paul Kocialkowski
2018-03-08 13:50     ` Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 14/21] videodev2.h: add request_fd field to v4l2_ext_controls Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 15/21] v4l2-ctrls: support requests in EXT_CTRLS ioctls Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 16/21] v4l2: video_device: support for creating requests Alexandre Courbot
2018-02-20 16:35   ` Hans Verkuil
2018-02-21  6:01     ` Alexandre Courbot
2018-02-21  7:37       ` Hans Verkuil
2018-02-20  4:44 ` [RFCv4 17/21] media: mem2mem: support for requests Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 18/21] Documentation: v4l: document request API Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 19/21] media: vim2m: add request support Alexandre Courbot
2018-03-07 16:37   ` [RFCv4,19/21] " Paul Kocialkowski
2018-03-08 13:48     ` Alexandre Courbot
2018-03-09 14:35       ` Paul Kocialkowski
2018-03-13 10:24         ` Alexandre Courbot
2018-03-14 13:25           ` Paul Kocialkowski
2018-03-19  9:17             ` Alexandre Courbot
2018-03-11 19:40     ` Dmitry Osipenko
2018-03-11 19:42     ` Dmitry Osipenko
2018-03-12  8:10       ` Paul Kocialkowski
2018-03-12  8:15         ` Tomasz Figa
2018-03-12  8:25           ` Paul Kocialkowski
2018-03-12  8:29             ` Tomasz Figa
2018-03-12 12:21               ` Dmitry Osipenko
2018-03-12 12:32           ` Alexandre Courbot
2018-03-12 14:44             ` Dmitry Osipenko
2018-02-20  4:44 ` [RFCv4 20/21] media: vivid: add request support for the video capture device Alexandre Courbot
2018-02-20  4:44 ` [RFCv4 21/21] [WIP] media: media-device: support for creating requests Alexandre Courbot
2018-02-20  4:54 ` [RFCv4 00/21] Request API Alexandre Courbot

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.