]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: core: Add bitmap manage bufs array entries
authorBenjamin Gaignard <benjamin.gaignard@collabora.com>
Thu, 14 Mar 2024 15:32:22 +0000 (16:32 +0100)
committerHans Verkuil <hverkuil-cisco@xs4all.nl>
Mon, 25 Mar 2024 11:00:44 +0000 (12:00 +0100)
Add a bitmap field to know which of bufs array entries are
used or not.
Remove no more used num_buffers field from queue structure.
Use bitmap_find_next_zero_area() to find the first possible
range when creating new buffers to fill the gaps.
If no suitable range is found try to allocate less buffers
than requested.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
Acked-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
drivers/media/common/videobuf2/videobuf2-core.c
include/media/videobuf2-core.h

index 8e819d198c348adcd22e84c4484964249e69dba1..ec81426d4d79837ca900185d79cdfbb4fc5236f1 100644 (file)
@@ -421,11 +421,12 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
  */
 static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index)
 {
-       WARN_ON(index >= q->max_num_buffers || q->bufs[index] || vb->vb2_queue);
+       WARN_ON(index >= q->max_num_buffers || test_bit(index, q->bufs_bitmap) || vb->vb2_queue);
 
        q->bufs[index] = vb;
        vb->index = index;
        vb->vb2_queue = q;
+       set_bit(index, q->bufs_bitmap);
 }
 
 /**
@@ -434,6 +435,7 @@ static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, uns
  */
 static void vb2_queue_remove_buffer(struct vb2_buffer *vb)
 {
+       clear_bit(vb->index, vb->vb2_queue->bufs_bitmap);
        vb->vb2_queue->bufs[vb->index] = NULL;
        vb->vb2_queue = NULL;
 }
@@ -452,9 +454,9 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                             const unsigned int plane_sizes[VB2_MAX_PLANES],
                             unsigned int *first_index)
 {
-       unsigned int q_num_buffers = vb2_get_num_buffers(q);
        unsigned int buffer, plane;
        struct vb2_buffer *vb;
+       unsigned long index = q->max_num_buffers;
        int ret;
 
        /*
@@ -462,9 +464,25 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
         * in the queue is below q->max_num_buffers
         */
        num_buffers = min_t(unsigned int, num_buffers,
-                           q->max_num_buffers - q_num_buffers);
+                           q->max_num_buffers - vb2_get_num_buffers(q));
+
+       while (num_buffers) {
+               index = bitmap_find_next_zero_area(q->bufs_bitmap, q->max_num_buffers,
+                                                  0, num_buffers, 0);
+
+               if (index < q->max_num_buffers)
+                       break;
+               /* Try to find free space for less buffers */
+               num_buffers--;
+       }
+
+       /* If there is no space left to allocate buffers return 0 to indicate the error */
+       if (!num_buffers) {
+               *first_index = 0;
+               return 0;
+       }
 
-       *first_index = q_num_buffers;
+       *first_index = index;
 
        for (buffer = 0; buffer < num_buffers; ++buffer) {
                /* Allocate vb2 buffer structures */
@@ -484,7 +502,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                        vb->planes[plane].min_length = plane_sizes[plane];
                }
 
-               vb2_queue_add_buffer(q, vb, q_num_buffers + buffer);
+               vb2_queue_add_buffer(q, vb, index++);
                call_void_bufop(q, init_buffer, vb);
 
                /* Allocate video buffer memory for the MMAP type */
@@ -664,7 +682,6 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
                kfree(vb);
        }
 
-       q->num_buffers -= buffers;
        if (!vb2_get_num_buffers(q)) {
                q->memory = VB2_MEMORY_UNKNOWN;
                INIT_LIST_HEAD(&q->queued_list);
@@ -818,6 +835,32 @@ static bool verify_coherency_flags(struct vb2_queue *q, bool non_coherent_mem)
        return true;
 }
 
+static int vb2_core_allocated_buffers_storage(struct vb2_queue *q)
+{
+       if (!q->bufs)
+               q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
+       if (!q->bufs)
+               return -ENOMEM;
+
+       if (!q->bufs_bitmap)
+               q->bufs_bitmap = bitmap_zalloc(q->max_num_buffers, GFP_KERNEL);
+       if (!q->bufs_bitmap) {
+               kfree(q->bufs);
+               q->bufs = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void vb2_core_free_buffers_storage(struct vb2_queue *q)
+{
+       kfree(q->bufs);
+       q->bufs = NULL;
+       bitmap_free(q->bufs_bitmap);
+       q->bufs_bitmap = NULL;
+}
+
 int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
                     unsigned int flags, unsigned int *count)
 {
@@ -879,10 +922,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
         * in the queue_setup op.
         */
        mutex_lock(&q->mmap_lock);
-       if (!q->bufs)
-               q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
-       if (!q->bufs)
-               ret = -ENOMEM;
+       ret = vb2_core_allocated_buffers_storage(q);
        q->memory = memory;
        mutex_unlock(&q->mmap_lock);
        if (ret)
@@ -954,7 +994,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
        }
 
        mutex_lock(&q->mmap_lock);
-       q->num_buffers = allocated_buffers;
 
        if (ret < 0) {
                /*
@@ -982,6 +1021,7 @@ error:
        mutex_lock(&q->mmap_lock);
        q->memory = VB2_MEMORY_UNKNOWN;
        mutex_unlock(&q->mmap_lock);
+       vb2_core_free_buffers_storage(q);
        return ret;
 }
 EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
@@ -1015,11 +1055,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
                 * value in the queue_setup op.
                 */
                mutex_lock(&q->mmap_lock);
+               ret = vb2_core_allocated_buffers_storage(q);
                q->memory = memory;
-               if (!q->bufs)
-                       q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
-               if (!q->bufs)
-                       ret = -ENOMEM;
                mutex_unlock(&q->mmap_lock);
                if (ret)
                        return ret;
@@ -1082,7 +1119,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
        }
 
        mutex_lock(&q->mmap_lock);
-       q->num_buffers += allocated_buffers;
 
        if (ret < 0) {
                /*
@@ -2583,8 +2619,7 @@ void vb2_core_queue_release(struct vb2_queue *q)
        __vb2_queue_cancel(q);
        mutex_lock(&q->mmap_lock);
        __vb2_queue_free(q, vb2_get_num_buffers(q));
-       kfree(q->bufs);
-       q->bufs = NULL;
+       vb2_core_free_buffers_storage(q);
        q->is_busy = 0;
        mutex_unlock(&q->mmap_lock);
 }
index 42526e289c8e8eb74def7d7c0b462e8bfad6444e..b9333e2c7797ef0130e55b39fb7a626374ef5ab0 100644 (file)
@@ -346,8 +346,8 @@ struct vb2_buffer {
  *                     describes the requested number of planes and sizes\[\]
  *                     contains the requested plane sizes. In this case
  *                     \*num_buffers are being allocated additionally to
- *                     q->num_buffers. If either \*num_planes or the requested
- *                     sizes are invalid callback must return %-EINVAL.
+ *                     the buffers already allocated. If either \*num_planes
+ *                     or the requested sizes are invalid callback must return %-EINVAL.
  * @wait_prepare:      release any locks taken while calling vb2 functions;
  *                     it is called before an ioctl needs to wait for a new
  *                     buffer to arrive; required to avoid a deadlock in
@@ -571,8 +571,9 @@ struct vb2_buf_ops {
  * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped
  * @memory:    current memory type used
  * @dma_dir:   DMA mapping direction.
- * @bufs:      videobuf2 buffer structures
- * @num_buffers: number of allocated/used buffers
+ * @bufs:      videobuf2 buffer structures. If it is non-NULL then
+ *             bufs_bitmap is also non-NULL.
+ * @bufs_bitmap: bitmap tracking whether each bufs[] entry is used
  * @max_num_buffers: upper limit of number of allocated/used buffers.
  *                  If set to 0 v4l2 core will change it VB2_MAX_FRAME
  *                  for backward compatibility.
@@ -643,7 +644,7 @@ struct vb2_queue {
        unsigned int                    memory;
        enum dma_data_direction         dma_dir;
        struct vb2_buffer               **bufs;
-       unsigned int                    num_buffers;
+       unsigned long                   *bufs_bitmap;
        unsigned int                    max_num_buffers;
 
        struct list_head                queued_list;
@@ -1173,7 +1174,10 @@ static inline bool vb2_fileio_is_active(struct vb2_queue *q)
  */
 static inline unsigned int vb2_get_num_buffers(struct vb2_queue *q)
 {
-       return q->num_buffers;
+       if (q->bufs_bitmap)
+               return bitmap_weight(q->bufs_bitmap, q->max_num_buffers);
+
+       return 0;
 }
 
 /**
@@ -1282,7 +1286,7 @@ static inline struct vb2_buffer *vb2_get_buffer(struct vb2_queue *q,
        if (index >= q->max_num_buffers)
                return NULL;
 
-       if (index < q->num_buffers)
+       if (test_bit(index, q->bufs_bitmap))
                return q->bufs[index];
        return NULL;
 }