| From 59fccce32428527237c011617cb7ad57a18693cc Mon Sep 17 00:00:00 2001 |
| From: Sergey Senozhatsky <senozhatsky@chromium.org> |
| Date: Thu, 9 Sep 2021 20:24:29 +0900 |
| Subject: [PATCH] BACKPORT: FROMLIST: videobuf2: handle |
| V4L2_MEMORY_FLAG_NON_COHERENT flag |
| |
| This patch lets user-space request a non-coherent memory |
| allocation during CREATE_BUFS and REQBUFS ioctl calls. |
| |
| = CREATE_BUFS |
| |
| struct v4l2_create_buffers has seven 4-byte reserved areas, |
| so reserved[0] is renamed to ->flags. The struct, thus, now |
| has six reserved 4-byte regions. |
| |
| = CREATE_BUFS32 |
| |
| struct v4l2_create_buffers32 has seven 4-byte reserved areas, |
| so reserved[0] is renamed to ->flags. The struct, thus, now |
| has six reserved 4-byte regions. |
| |
| = REQBUFS |
| |
| We use one byte of a 4 byte ->reserved[1] member of struct |
| v4l2_requestbuffers. The struct, thus, now has reserved 3 bytes. |
| |
| Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org> |
| (am from https://patchwork.kernel.org/patch/12482947/) |
| (also found at https://lore.kernel.org/r/20210909112430.61243-8-senozhatsky@chromium.org) |
| |
| [rebase(senozhatsky): Conflicts with compat32 code] |
| |
| BUG=b:167319762 |
| TEST=v4l2-compliance and contrib/test/test-media vivid |
| |
| Change-Id: I9b58788b75525301c1a304fd1a39fd16dd49f657 |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3160635 |
| Reviewed-by: Ricardo Ribalda <ribalda@chromium.org> |
| Tested-by: Sergey Senozhatsky <senozhatsky@chromium.org> |
| Commit-Queue: Sergey Senozhatsky <senozhatsky@chromium.org> |
| --- |
| .../media/v4l/vidioc-create-bufs.rst | 7 ++++- |
| .../media/v4l/vidioc-reqbufs.rst | 11 ++++--- |
| .../media/common/videobuf2/videobuf2-core.c | 4 +-- |
| .../media/common/videobuf2/videobuf2-v4l2.c | 31 +++++++++++++++++-- |
| drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 10 ++++-- |
| drivers/media/v4l2-core/v4l2-ioctl.c | 4 +-- |
| include/uapi/linux/videodev2.h | 9 ++++-- |
| 7 files changed, 60 insertions(+), 16 deletions(-) |
| |
| diff --git a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst |
| --- a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst |
| +++ b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst |
| @@ -113,7 +113,12 @@ than the number requested. |
| ``V4L2_MEMORY_MMAP`` and ``format.type`` to the buffer type. |
| |
| * - __u32 |
| - - ``reserved``\ [7] |
| + - ``flags`` |
| + - Specifies additional buffer management attributes. |
| + See :ref:`memory-flags`. |
| + |
| + * - __u32 |
| + - ``reserved``\ [6] |
| - A place holder for future extensions. Drivers and applications |
| must set the array to zero. |
| |
| diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst |
| --- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst |
| +++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst |
| @@ -104,10 +104,13 @@ aborting or finishing any DMA in progress, an implicit |
| ``V4L2_MEMORY_MMAP`` and ``type`` set to the buffer type. This will |
| free any previously allocated buffers, so this is typically something |
| that will be done at the start of the application. |
| - * - __u32 |
| - - ``reserved``\ [1] |
| - - A place holder for future extensions. Drivers and applications |
| - must set the array to zero. |
| + * - __u8 |
| + - ``flags`` |
| + - Specifies additional buffer management attributes. |
| + See :ref:`memory-flags`. |
| + * - __u8 |
| + - ``reserved``\ [3] |
| + - Reserved for future extensions. |
| |
| .. _v4l2-buf-capabilities: |
| .. _V4L2-BUF-CAP-SUPPORTS-MMAP: |
| diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c |
| --- a/drivers/media/common/videobuf2/videobuf2-core.c |
| +++ b/drivers/media/common/videobuf2/videobuf2-core.c |
| @@ -761,7 +761,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, |
| { |
| unsigned int num_buffers, allocated_buffers, num_planes = 0; |
| unsigned plane_sizes[VB2_MAX_PLANES] = { }; |
| - bool non_coherent_mem = false; |
| + bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; |
| unsigned int i; |
| int ret; |
| |
| @@ -905,7 +905,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, |
| { |
| unsigned int num_planes = 0, num_buffers, allocated_buffers; |
| unsigned plane_sizes[VB2_MAX_PLANES] = { }; |
| - bool non_coherent_mem = false; |
| + bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT; |
| int ret; |
| |
| if (q->num_buffers == VB2_MAX_FRAME) { |
| diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c |
| --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c |
| +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c |
| @@ -703,12 +703,32 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps) |
| #endif |
| } |
| |
| +static void validate_memory_flags(struct vb2_queue *q, |
| + int memory, |
| + u32 *flags) |
| +{ |
| + if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP) { |
| + /* |
| + * This needs to clear V4L2_MEMORY_FLAG_NON_COHERENT only, |
| + * but in order to avoid bugs we zero out all bits. |
| + */ |
| + *flags = 0; |
| + } else { |
| + /* Clear all unknown flags. */ |
| + *flags &= V4L2_MEMORY_FLAG_NON_COHERENT; |
| + } |
| +} |
| + |
| int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) |
| { |
| int ret = vb2_verify_memory_type(q, req->memory, req->type); |
| + u32 flags = req->flags; |
| |
| fill_buf_caps(q, &req->capabilities); |
| - return ret ? ret : vb2_core_reqbufs(q, req->memory, 0, &req->count); |
| + validate_memory_flags(q, req->memory, &flags); |
| + req->flags = flags; |
| + return ret ? ret : vb2_core_reqbufs(q, req->memory, |
| + req->flags, &req->count); |
| } |
| EXPORT_SYMBOL_GPL(vb2_reqbufs); |
| |
| @@ -740,6 +760,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) |
| unsigned i; |
| |
| fill_buf_caps(q, &create->capabilities); |
| + validate_memory_flags(q, create->memory, &create->flags); |
| create->index = q->num_buffers; |
| if (create->count == 0) |
| return ret != -EBUSY ? ret : 0; |
| @@ -783,7 +804,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) |
| if (requested_sizes[i] == 0) |
| return -EINVAL; |
| return ret ? ret : vb2_core_create_bufs(q, create->memory, |
| - 0, |
| + create->flags, |
| &create->count, |
| requested_planes, |
| requested_sizes); |
| @@ -980,13 +1001,16 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, |
| { |
| struct video_device *vdev = video_devdata(file); |
| int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type); |
| + u32 flags = p->flags; |
| |
| fill_buf_caps(vdev->queue, &p->capabilities); |
| + validate_memory_flags(vdev->queue, p->memory, &flags); |
| + p->flags = flags; |
| if (res) |
| return res; |
| if (vb2_queue_is_busy(vdev, file)) |
| return -EBUSY; |
| - res = vb2_core_reqbufs(vdev->queue, p->memory, 0, &p->count); |
| + res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count); |
| /* If count == 0, then the owner has released all buffers and he |
| is no longer owner of the queue. Otherwise we have a new owner. */ |
| if (res == 0) |
| @@ -1004,6 +1028,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, |
| |
| p->index = vdev->queue->num_buffers; |
| fill_buf_caps(vdev->queue, &p->capabilities); |
| + validate_memory_flags(vdev->queue, p->memory, &p->flags); |
| /* |
| * If count == 0, then just check if memory and type are valid. |
| * Any -EBUSY result from vb2_verify_memory_type can be mapped to 0. |
| diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c |
| --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c |
| +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c |
| @@ -126,6 +126,9 @@ struct v4l2_format32 { |
| * @memory: buffer memory type |
| * @format: frame format, for which buffers are requested |
| * @capabilities: capabilities of this buffer type. |
| + * @flags: additional buffer management attributes (ignored unless the |
| + * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and |
| + * configured for MMAP streaming I/O). |
| * @reserved: future extensions |
| */ |
| struct v4l2_create_buffers32 { |
| @@ -134,7 +137,8 @@ struct v4l2_create_buffers32 { |
| __u32 memory; /* enum v4l2_memory */ |
| struct v4l2_format32 format; |
| __u32 capabilities; |
| - __u32 reserved[7]; |
| + __u32 flags; |
| + __u32 reserved[6]; |
| }; |
| |
| static int get_v4l2_format32(struct v4l2_format *p64, |
| @@ -180,7 +184,8 @@ static int get_v4l2_create32(struct v4l2_create_buffers *p64, |
| struct v4l2_create_buffers32 __user *p32) |
| { |
| if (copy_from_user(p64, p32, |
| - offsetof(struct v4l2_create_buffers32, format))) |
| + offsetof(struct v4l2_create_buffers32, format)) || |
| + get_user(p64->flags, &p32->flags)) |
| return -EFAULT; |
| return get_v4l2_format32(&p64->format, &p32->format); |
| } |
| @@ -227,6 +232,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *p64, |
| if (copy_to_user(p32, p64, |
| offsetof(struct v4l2_create_buffers32, format)) || |
| put_user(p64->capabilities, &p32->capabilities) || |
| + put_user(p64->flags, &p32->flags) || |
| copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved))) |
| return -EFAULT; |
| return put_v4l2_format32(&p64->format, &p32->format); |
| diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c |
| --- a/drivers/media/v4l2-core/v4l2-ioctl.c |
| +++ b/drivers/media/v4l2-core/v4l2-ioctl.c |
| @@ -2044,7 +2044,7 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, |
| if (ret) |
| return ret; |
| |
| - CLEAR_AFTER_FIELD(p, capabilities); |
| + CLEAR_AFTER_FIELD(p, flags); |
| |
| return ops->vidioc_reqbufs(file, fh, p); |
| } |
| @@ -2085,7 +2085,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, |
| if (ret) |
| return ret; |
| |
| - CLEAR_AFTER_FIELD(create, capabilities); |
| + CLEAR_AFTER_FIELD(create, flags); |
| |
| v4l_sanitize_format(&create->format); |
| |
| diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h |
| --- a/include/uapi/linux/videodev2.h |
| +++ b/include/uapi/linux/videodev2.h |
| @@ -999,7 +999,8 @@ struct v4l2_requestbuffers { |
| __u32 type; /* enum v4l2_buf_type */ |
| __u32 memory; /* enum v4l2_memory */ |
| __u32 capabilities; |
| - __u32 reserved[1]; |
| + __u8 flags; |
| + __u8 reserved[3]; |
| }; |
| |
| #define V4L2_MEMORY_FLAG_NON_COHERENT (1 << 0) |
| @@ -2547,6 +2548,9 @@ struct v4l2_dbg_chip_info { |
| * @memory: enum v4l2_memory; buffer memory type |
| * @format: frame format, for which buffers are requested |
| * @capabilities: capabilities of this buffer type. |
| + * @flags: additional buffer management attributes (ignored unless the |
| + * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability |
| + * and configured for MMAP streaming I/O). |
| * @reserved: future extensions |
| */ |
| struct v4l2_create_buffers { |
| @@ -2555,7 +2559,8 @@ struct v4l2_create_buffers { |
| __u32 memory; |
| struct v4l2_format format; |
| __u32 capabilities; |
| - __u32 reserved[7]; |
| + __u32 flags; |
| + __u32 reserved[6]; |
| }; |
| |
| /* |
| -- |
| 2.33.0.685.g46640cef36-goog |
| |