[PATCH 01/25] drm: add generic lock-free queue implementation
Zhou, Jammy
Jammy.Zhou at amd.com
Thu Jul 2 00:33:16 PDT 2015
Thanks Daniel. I had a look at kfifo implementation, and I think it can satisfy our requirements as well.
Regards,
Jammy
-----Original Message-----
From: Daniel Vetter [mailto:daniel.vetter at ffwll.ch] On Behalf Of Daniel Vetter
Sent: Monday, June 15, 2015 2:39 PM
To: Zhou, Jammy
Cc: dri-devel at lists.freedesktop.org; Liu, Shaoyun
Subject: Re: [PATCH 01/25] drm: add generic lock-free queue implementation
On Thu, Jun 04, 2015 at 06:38:21PM +0800, Jammy Zhou wrote:
> Signed-off-by: Jammy Zhou <Jammy.Zhou at amd.com>
> Signed-off-by: Shaoyun Liu <Shaoyun.liu at amd.com>
> Reviewed-by: Christian K?nig <christian.koenig at amd.com>
What exactly is this needed for? Is this really something that's useful in drm core (smells like yet another single purpose helper for just one driver)? Why is the one in lib/kfifo.c not good enough?
-Daniel
> ---
> drivers/gpu/drm/Makefile | 3 +-
> drivers/gpu/drm/drm_queue.c | 208 ++++++++++++++++++++++++++++++++++++++++++++
> include/drm/drm_queue.h | 47 ++++++++++
> 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644
> drivers/gpu/drm/drm_queue.c create mode 100644
> include/drm/drm_queue.h
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index
> 20f81fd..173d2b6 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -14,7 +14,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
> drm_info.o drm_debugfs.o drm_encoder_slave.o \
> drm_trace_points.o drm_global.o drm_prime.o \
> drm_rect.o drm_vma_manager.o drm_flip_work.o \
> - drm_modeset_lock.o drm_atomic.o drm_bridge.o
> + drm_modeset_lock.o drm_atomic.o drm_bridge.o \
> + drm_queue.o
>
> drm-$(CONFIG_COMPAT) += drm_ioc32.o
> drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o diff --git
> a/drivers/gpu/drm/drm_queue.c b/drivers/gpu/drm/drm_queue.c new file
> mode 100644 index 0000000..00cd649
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_queue.c
> @@ -0,0 +1,208 @@
> +/*
> + * Copyright 2015 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person
> +obtaining a
> + * copy of this software and associated documentation files (the
> +"Software"),
> + * to deal in the Software without restriction, including without
> +limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> +sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> +the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> +included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> +EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> +MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
> +SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM,
> +DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> +OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> +OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + *
> + * This file implement a generic circular array queue.
> + * It's lock free for single producer and single consumer.
> + *
> + */
> +
> +#include <linux/atomic.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <drm/drm_queue.h>
> +
> +#define QUEUE_IDX(_X_) ((_X_)&(queue->size-1))
> +
> +/**
> + * drm_queue_create - create the queue
> + *
> + * @size total number of elements for this queue
> + * @element_size the memory size of each element entry
> + *
> + * return pointer to the drm_queue structure if succeed, NULL if
> +failed */ struct drm_queue * drm_queue_create(uint32_t size,
> +uint32_t element_size) {
> + struct drm_queue *queue;
> +
> + /* check whether the size is power of 2*/
> + BUG_ON(size & (size - 1));
> +
> + queue = kzalloc(sizeof(struct drm_queue), GFP_KERNEL);
> + if (!queue)
> + return NULL;
> +
> + queue->size = size;
> + queue->element_size = element_size;
> + atomic_set(&queue->count, 0);
> + mutex_init(&queue->lock);
> + queue->data = kzalloc(size * element_size, GFP_KERNEL);
> + if (!queue->data) {
> + kfree(queue);
> + return NULL;
> + }
> +
> + return queue;
> +}
> +
> +EXPORT_SYMBOL(drm_queue_create);
> +
> +/**
> + * drm_queue_free - free the queue storage
> + *
> + * @queue pointer to the queue need to be destroied
> + *
> + * return 0 if succeed. -1 if failed.
> + */
> +int drm_queue_free(struct drm_queue *queue) {
> + BUG_ON(queue == NULL);
> +
> + kfree(queue->data);
> + kfree(queue);
> +
> + return 0;
> +}
> +
> +EXPORT_SYMBOL(drm_queue_free);
> +
> +/**
> + * drm_queue_get_count - Get active count of elements in the queue
> + *
> + * @queue pointer to the queue.
> + *
> + * return current occuptied count of the queue.
> + *
> + */
> +int drm_queue_get_count(struct drm_queue *queue) {
> + BUG_ON(queue == NULL);
> + return atomic_read(&queue->count);
> +}
> +
> +EXPORT_SYMBOL(drm_queue_get_count);
> +
> +/**
> + * drm_queue_push - push one element into the queue
> + *
> + * @queue pointer to the queue
> + * @data pointer to the element.
> + *
> + * return 0 if succeed.
> + * -EINVAL if the queue is not valid
> + * -ENOSPC if the queue is full.
> + *
> + * Only one producer is allowed.
> + */
> +int drm_queue_push(struct drm_queue *queue, void *data) {
> + uint32_t index;
> +
> + if (!(queue && queue->data))
> + return -EINVAL;
> +
> + if (atomic_read(&queue->count) >= queue->size)
> + return -ENOSPC;
> +
> + index = QUEUE_IDX(queue->w_idx++);
> + memcpy(queue->data + index * queue->element_size,
> + data, queue->element_size);
> + barrier();
> + atomic_inc(&queue->count);
> + return 0;
> +}
> +
> +EXPORT_SYMBOL(drm_queue_push);
> +
> +int drm_queue_push_safe(struct drm_queue *queue, void *data) {
> + int r;
> + mutex_lock(&queue->lock);
> + r = drm_queue_push(queue, data);
> + mutex_unlock(&queue->lock);
> + return r;
> +}
> +
> +EXPORT_SYMBOL(drm_queue_push_safe);
> +
> +/**
> + * drm_queue_pop - pop one element from the queue
> + *
> + * @queue pointer to the queue.
> + * @data pointer to place the element.
> + *
> + * return queue index if succeed.
> + * -EINVAL if the queue is not valid
> + * -ENOSPC if the queue is empty.
> + *
> + * Only one comsummer is allowed
> + */
> +
> +int drm_queue_pop(struct drm_queue *queue, void *data) {
> + uint32_t index;
> +
> + if (!(queue && queue->data))
> + return -EINVAL;
> +
> + if (atomic_read(&queue->count) == 0)
> + return -ENOSPC;
> +
> + index = QUEUE_IDX(queue->r_idx++);
> + memcpy(data, queue->data + index * queue->element_size,
> + queue->element_size);
> + barrier();
> + atomic_dec(&queue->count);
> + return queue->r_idx;
> +}
> +
> +EXPORT_SYMBOL(drm_queue_pop);
> +
> +/**
> + * drm_queue_peek - Get next element from the queue without removing
> +it
> + *
> + * @queue pointer to the queue.
> + * @data pointer to place the element.
> + *
> + * return 0 if succeed.
> + * -EINVAL if the queue is not valid
> + * -ENOSPC if the queue is empty.
> + */
> +
> +int drm_queue_peek(struct drm_queue *queue, void *data) {
> + uint32_t index;
> +
> + if (!(queue && queue->data))
> + return -EINVAL;
> +
> + if (atomic_read(&queue->count) == 0)
> + return -ENOSPC;
> +
> + index = QUEUE_IDX(queue->r_idx);
> + memcpy(data, queue->data + index * queue->element_size,
> + queue->element_size);
> +
> + return 0;
> +}
> +
> +EXPORT_SYMBOL(drm_queue_peek);
> diff --git a/include/drm/drm_queue.h b/include/drm/drm_queue.h new
> file mode 100644 index 0000000..b8161b4
> --- /dev/null
> +++ b/include/drm/drm_queue.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright 2015 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person
> +obtaining a
> + * copy of this software and associated documentation files (the
> +"Software"),
> + * to deal in the Software without restriction, including without
> +limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> +sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> +the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> +included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> +EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> +MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
> +SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM,
> +DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> +OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> +OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + *
> + * Header file for the generic lock free queue
> + *
> + */
> +
> +struct drm_queue {
> + /* Need to be power of 2*/
> + uint32_t size;
> + /* Current occupied count */
> + atomic_t count;
> + /* Where a new element will be inserted to*/
> + uint32_t w_idx;
> + /* Where the next element will be extracted from */
> + uint32_t r_idx;
> + struct mutex lock;
> + char *data;
> + uint32_t element_size;
> +};
> +
> +struct drm_queue *drm_queue_create(uint32_t size, uint32_t
> +element_size); int drm_queue_free(struct drm_queue *queue); int
> +drm_queue_push(struct drm_queue *queue, void *data); int
> +drm_queue_push_safe(struct drm_queue *queue, void *data); int
> +drm_queue_pop(struct drm_queue *queue, void *data); int
> +drm_queue_peek(struct drm_queue *queue, void *data); int
> +drm_queue_get_count(struct drm_queue *queue);
> --
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the dri-devel
mailing list