Signed-off-by: Jammy Zhou <Jammy.Zhou@xxxxxxx> Signed-off-by: Shaoyun Liu <Shaoyun.liu@xxxxxxx> Reviewed-by: Christian K?nig <christian.koenig@xxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel