[PATCH 01/25] drm: add generic lock-free queue implementation

Daniel Vetter daniel at ffwll.ch
Sun Jun 14 23:39:17 PDT 2015


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