2023-09-27 21:04:00

by Benjamin Gaignard

[permalink] [raw]
Subject: [PATCH v8 01/53] media: videobuf2: Rework offset 'cookie' encoding pattern

Change how offset 'cookie' field value is computed to make possible
to use more buffers (up to 0x7fff)
With this encoding pattern we know the maximum number that a queue
could store so we can check ing at queue init time.
It also make easier and faster to find buffer and plane from using
the offset field.
Change __find_plane_by_offset() prototype to return the video buffer
itself rather than it index.

Signed-off-by: Benjamin Gaignard <[email protected]>
---
.../media/common/videobuf2/videobuf2-core.c | 74 +++++++++----------
1 file changed, 35 insertions(+), 39 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index cf6727d9c81f..6eeddb3a01c7 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -31,6 +31,14 @@

#include <trace/events/vb2.h>

+#define PLANE_INDEX_SHIFT (PAGE_SHIFT + 3)
+#define PLANE_INDEX_MASK 0x7
+#define BUFFER_INDEX_MASK 0x7fff
+
+#if PAGE_SHIFT != 12
+#error Expected PAGE_SHIFT to be 12
+#endif
+
static int debug;
module_param(debug, int, 0644);

@@ -358,21 +366,23 @@ static void __setup_offsets(struct vb2_buffer *vb)
unsigned int plane;
unsigned long off = 0;

- if (vb->index) {
- struct vb2_buffer *prev = q->bufs[vb->index - 1];
- struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
-
- off = PAGE_ALIGN(p->m.offset + p->length);
- }
+ /*
+ * Offsets cookies value have the following constraints:
+ * - a buffer could have up to 8 planes.
+ * - v4l2 mem2mem use bit 30 to distinguish between source and destination buffers.
+ * - must be page aligned
+ * That led to this bit mapping:
+ * |30 |29 15|14 12|11 0|
+ * |DST_QUEUE_OFF_BASE|buffer index|plane index| 0 |
+ * where there are 15 bits to store buffer index.
+ */
+ off = vb->index << PLANE_INDEX_SHIFT;

for (plane = 0; plane < vb->num_planes; ++plane) {
- vb->planes[plane].m.offset = off;
+ vb->planes[plane].m.offset = off + (plane << PAGE_SHIFT);

dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n",
vb->index, plane, off);
-
- off += vb->planes[plane].length;
- off = PAGE_ALIGN(off);
}
}

@@ -2185,13 +2195,12 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type)
EXPORT_SYMBOL_GPL(vb2_core_streamoff);

/*
- * __find_plane_by_offset() - find plane associated with the given offset off
+ * __find_plane_by_offset() - find video buffer and plane associated with the given offset off
*/
static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
- unsigned int *_buffer, unsigned int *_plane)
+ struct vb2_buffer **vb, unsigned int *plane)
{
- struct vb2_buffer *vb;
- unsigned int buffer, plane;
+ unsigned int buffer;

/*
* Sanity checks to ensure the lock is held, MEMORY_MMAP is
@@ -2209,24 +2218,15 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
return -EBUSY;
}

- /*
- * Go over all buffers and their planes, comparing the given offset
- * with an offset assigned to each plane. If a match is found,
- * return its buffer and plane numbers.
- */
- for (buffer = 0; buffer < q->num_buffers; ++buffer) {
- vb = q->bufs[buffer];
+ /* Get buffer and plane from the offset */
+ buffer = (off >> PLANE_INDEX_SHIFT) & BUFFER_INDEX_MASK;
+ *plane = (off >> PAGE_SHIFT) & PLANE_INDEX_MASK;

- for (plane = 0; plane < vb->num_planes; ++plane) {
- if (vb->planes[plane].m.offset == off) {
- *_buffer = buffer;
- *_plane = plane;
- return 0;
- }
- }
- }
+ if (buffer >= q->num_buffers || *plane >= q->bufs[buffer]->num_planes)
+ return -EINVAL;

- return -EINVAL;
+ *vb = q->bufs[buffer];
+ return 0;
}

int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
@@ -2306,7 +2306,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
{
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
- unsigned int buffer = 0, plane = 0;
+ unsigned int plane = 0;
int ret;
unsigned long length;

@@ -2335,12 +2335,10 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
* Find the plane corresponding to the offset passed by userspace. This
* will return an error if not MEMORY_MMAP or file I/O is in progress.
*/
- ret = __find_plane_by_offset(q, off, &buffer, &plane);
+ ret = __find_plane_by_offset(q, off, &vb, &plane);
if (ret)
goto unlock;

- vb = q->bufs[buffer];
-
/*
* MMAP requires page_aligned buffers.
* The buffer length was page_aligned at __vb2_buf_mem_alloc(),
@@ -2368,7 +2366,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
if (ret)
return ret;

- dprintk(q, 3, "buffer %d, plane %d successfully mapped\n", buffer, plane);
+ dprintk(q, 3, "buffer %u, plane %d successfully mapped\n", vb->index, plane);
return 0;
}
EXPORT_SYMBOL_GPL(vb2_mmap);
@@ -2382,7 +2380,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
{
unsigned long off = pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
- unsigned int buffer, plane;
+ unsigned int plane;
void *vaddr;
int ret;

@@ -2392,12 +2390,10 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
* Find the plane corresponding to the offset passed by userspace. This
* will return an error if not MEMORY_MMAP or file I/O is in progress.
*/
- ret = __find_plane_by_offset(q, off, &buffer, &plane);
+ ret = __find_plane_by_offset(q, off, &vb, &plane);
if (ret)
goto unlock;

- vb = q->bufs[buffer];
-
vaddr = vb2_plane_vaddr(vb, plane);
mutex_unlock(&q->mmap_lock);
return vaddr ? (unsigned long)vaddr : -EINVAL;
--
2.39.2


2023-09-30 08:57:24

by Hans Verkuil

[permalink] [raw]
Subject: Re: [PATCH v8 01/53] media: videobuf2: Rework offset 'cookie' encoding pattern

On 27/09/2023 17:35, Benjamin Gaignard wrote:
> Change how offset 'cookie' field value is computed to make possible
> to use more buffers (up to 0x7fff)
> With this encoding pattern we know the maximum number that a queue
> could store so we can check ing at queue init time.
> It also make easier and faster to find buffer and plane from using
> the offset field.
> Change __find_plane_by_offset() prototype to return the video buffer
> itself rather than it index.
>
> Signed-off-by: Benjamin Gaignard <[email protected]>
> ---
> .../media/common/videobuf2/videobuf2-core.c | 74 +++++++++----------
> 1 file changed, 35 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
> index cf6727d9c81f..6eeddb3a01c7 100644
> --- a/drivers/media/common/videobuf2/videobuf2-core.c
> +++ b/drivers/media/common/videobuf2/videobuf2-core.c
> @@ -31,6 +31,14 @@
>
> #include <trace/events/vb2.h>
>
> +#define PLANE_INDEX_SHIFT (PAGE_SHIFT + 3)
> +#define PLANE_INDEX_MASK 0x7
> +#define BUFFER_INDEX_MASK 0x7fff
> +
> +#if PAGE_SHIFT != 12
> +#error Expected PAGE_SHIFT to be 12

So it turns out this can actually be something other than 12.
Search for CONFIG_ARM64_PAGE_SHIFT and CONFIG_PPC_PAGE_SHIFT.

arm64 supports 12, 14, 16 and powerpc64 supports 12, 14, 16, 18.

I think we should calculate the BUFFER_INDEX_MASK based on the
PAGE_SHIFT value. Even with a PAGE_SHIFT of 18, you can still
allocate up to 512 buffers.

Regards,

Hans