From 2c3c1048746a4622d8c89a29670120dc8fab93c4 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:49:45 +0200 Subject: Adding upstream version 6.1.76. Signed-off-by: Daniel Baumann --- .../pci/base/circbuf/interface/ia_css_circbuf.h | 377 +++++++++++++++++++++ .../base/circbuf/interface/ia_css_circbuf_comm.h | 59 ++++ .../base/circbuf/interface/ia_css_circbuf_desc.h | 174 ++++++++++ .../media/atomisp/pci/base/circbuf/src/circbuf.c | 321 ++++++++++++++++++ .../pci/base/refcount/interface/ia_css_refcount.h | 85 +++++ .../media/atomisp/pci/base/refcount/src/refcount.c | 277 +++++++++++++++ 6 files changed, 1293 insertions(+) create mode 100644 drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h create mode 100644 drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h create mode 100644 drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h create mode 100644 drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c create mode 100644 drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h create mode 100644 drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c (limited to 'drivers/staging/media/atomisp/pci/base') diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h new file mode 100644 index 000000000..0579deac5 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h @@ -0,0 +1,377 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _IA_CSS_CIRCBUF_H +#define _IA_CSS_CIRCBUF_H + +#include +#include +#include +#include +#include +#include "ia_css_circbuf_comm.h" +#include "ia_css_circbuf_desc.h" + +/**************************************************************** + * + * Data structures. + * + ****************************************************************/ +/** + * @brief Data structure for the circular buffer. + */ +typedef struct ia_css_circbuf_s ia_css_circbuf_t; +struct ia_css_circbuf_s { + ia_css_circbuf_desc_t *desc; /* Pointer to the descriptor of the circbuf */ + ia_css_circbuf_elem_t *elems; /* an array of elements */ +}; + +/** + * @brief Create the circular buffer. + * + * @param cb The pointer to the circular buffer. + * @param elems An array of elements. + * @param desc The descriptor set to the size using ia_css_circbuf_desc_init(). + */ +void ia_css_circbuf_create( + ia_css_circbuf_t *cb, + ia_css_circbuf_elem_t *elems, + ia_css_circbuf_desc_t *desc); + +/** + * @brief Destroy the circular buffer. + * + * @param cb The pointer to the circular buffer. + */ +void ia_css_circbuf_destroy( + ia_css_circbuf_t *cb); + +/** + * @brief Pop a value out of the circular buffer. + * Get a value at the head of the circular buffer. + * The user should call "ia_css_circbuf_is_empty()" + * to avoid accessing to an empty buffer. + * + * @param cb The pointer to the circular buffer. + * + * @return the pop-out value. + */ +uint32_t ia_css_circbuf_pop( + ia_css_circbuf_t *cb); + +/** + * @brief Extract a value out of the circular buffer. + * Get a value at an arbitrary poistion in the circular + * buffer. The user should call "ia_css_circbuf_is_empty()" + * to avoid accessing to an empty buffer. + * + * @param cb The pointer to the circular buffer. + * @param offset The offset from "start" to the target position. + * + * @return the extracted value. + */ +uint32_t ia_css_circbuf_extract( + ia_css_circbuf_t *cb, + int offset); + +/**************************************************************** + * + * Inline functions. + * + ****************************************************************/ +/** + * @brief Set the "val" field in the element. + * + * @param elem The pointer to the element. + * @param val The value to be set. + */ +static inline void ia_css_circbuf_elem_set_val( + ia_css_circbuf_elem_t *elem, + uint32_t val) +{ + OP___assert(elem); + + elem->val = val; +} + +/** + * @brief Initialize the element. + * + * @param elem The pointer to the element. + */ +static inline void ia_css_circbuf_elem_init( + ia_css_circbuf_elem_t *elem) +{ + OP___assert(elem); + ia_css_circbuf_elem_set_val(elem, 0); +} + +/** + * @brief Copy an element. + * + * @param src The element as the copy source. + * @param dest The element as the copy destination. + */ +static inline void ia_css_circbuf_elem_cpy( + ia_css_circbuf_elem_t *src, + ia_css_circbuf_elem_t *dest) +{ + OP___assert(src); + OP___assert(dest); + + ia_css_circbuf_elem_set_val(dest, src->val); +} + +/** + * @brief Get position in the circular buffer. + * + * @param cb The pointer to the circular buffer. + * @param base The base position. + * @param offset The offset. + * + * @return the position at offset. + */ +static inline uint8_t ia_css_circbuf_get_pos_at_offset( + ia_css_circbuf_t *cb, + u32 base, + int offset) +{ + u8 dest; + + OP___assert(cb); + OP___assert(cb->desc); + OP___assert(cb->desc->size > 0); + + /* step 1: adjudst the offset */ + while (offset < 0) { + offset += cb->desc->size; + } + + /* step 2: shift and round by the upper limit */ + dest = OP_std_modadd(base, offset, cb->desc->size); + + return dest; +} + +/** + * @brief Get the offset between two positions in the circular buffer. + * Get the offset from the source position to the terminal position, + * along the direction in which the new elements come in. + * + * @param cb The pointer to the circular buffer. + * @param src_pos The source position. + * @param dest_pos The terminal position. + * + * @return the offset. + */ +static inline int ia_css_circbuf_get_offset( + ia_css_circbuf_t *cb, + u32 src_pos, + uint32_t dest_pos) +{ + int offset; + + OP___assert(cb); + OP___assert(cb->desc); + + offset = (int)(dest_pos - src_pos); + offset += (offset < 0) ? cb->desc->size : 0; + + return offset; +} + +/** + * @brief Get the maximum number of elements. + * + * @param cb The pointer to the circular buffer. + * + * @return the maximum number of elements. + * + * TODO: Test this API. + */ +static inline uint32_t ia_css_circbuf_get_size( + ia_css_circbuf_t *cb) +{ + OP___assert(cb); + OP___assert(cb->desc); + + return cb->desc->size; +} + +/** + * @brief Get the number of available elements. + * + * @param cb The pointer to the circular buffer. + * + * @return the number of available elements. + */ +static inline uint32_t ia_css_circbuf_get_num_elems( + ia_css_circbuf_t *cb) +{ + int num; + + OP___assert(cb); + OP___assert(cb->desc); + + num = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end); + + return (uint32_t)num; +} + +/** + * @brief Test if the circular buffer is empty. + * + * @param cb The pointer to the circular buffer. + * + * @return + * - true when it is empty. + * - false when it is not empty. + */ +static inline bool ia_css_circbuf_is_empty( + ia_css_circbuf_t *cb) +{ + OP___assert(cb); + OP___assert(cb->desc); + + return ia_css_circbuf_desc_is_empty(cb->desc); +} + +/** + * @brief Test if the circular buffer is full. + * + * @param cb The pointer to the circular buffer. + * + * @return + * - true when it is full. + * - false when it is not full. + */ +static inline bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) +{ + OP___assert(cb); + OP___assert(cb->desc); + + return ia_css_circbuf_desc_is_full(cb->desc); +} + +/** + * @brief Write a new element into the circular buffer. + * Write a new element WITHOUT checking whether the + * circular buffer is full or not. So it also overwrites + * the oldest element when the buffer is full. + * + * @param cb The pointer to the circular buffer. + * @param elem The new element. + */ +static inline void ia_css_circbuf_write( + ia_css_circbuf_t *cb, + ia_css_circbuf_elem_t elem) +{ + OP___assert(cb); + OP___assert(cb->desc); + + /* Cannot continue as the queue is full*/ + assert(!ia_css_circbuf_is_full(cb)); + + ia_css_circbuf_elem_cpy(&elem, &cb->elems[cb->desc->end]); + + cb->desc->end = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, 1); +} + +/** + * @brief Push a value in the circular buffer. + * Put a new value at the tail of the circular buffer. + * The user should call "ia_css_circbuf_is_full()" + * to avoid accessing to a full buffer. + * + * @param cb The pointer to the circular buffer. + * @param val The value to be pushed in. + */ +static inline void ia_css_circbuf_push( + ia_css_circbuf_t *cb, + uint32_t val) +{ + ia_css_circbuf_elem_t elem; + + OP___assert(cb); + + /* set up an element */ + ia_css_circbuf_elem_init(&elem); + ia_css_circbuf_elem_set_val(&elem, val); + + /* write the element into the buffer */ + ia_css_circbuf_write(cb, elem); +} + +/** + * @brief Get the number of free elements. + * + * @param cb The pointer to the circular buffer. + * + * @return: The number of free elements. + */ +static inline uint32_t ia_css_circbuf_get_free_elems( + ia_css_circbuf_t *cb) +{ + OP___assert(cb); + OP___assert(cb->desc); + + return ia_css_circbuf_desc_get_free_elems(cb->desc); +} + +/** + * @brief Peek an element in Circular Buffer. + * + * @param cb The pointer to the circular buffer. + * @param offset Offset to the element. + * + * @return the elements value. + */ +uint32_t ia_css_circbuf_peek( + ia_css_circbuf_t *cb, + int offset); + +/** + * @brief Get an element in Circular Buffer. + * + * @param cb The pointer to the circular buffer. + * @param offset Offset to the element. + * + * @return the elements value. + */ +uint32_t ia_css_circbuf_peek_from_start( + ia_css_circbuf_t *cb, + int offset); + +/** + * @brief Increase Size of a Circular Buffer. + * Use 'CAUTION' before using this function, This was added to + * support / fix issue with increasing size for tagger only + * + * @param cb The pointer to the circular buffer. + * @param sz_delta delta increase for new size + * @param elems (optional) pointers to new additional elements + * cb element array size will not be increased dynamically, + * but new elements should be added at the end to existing + * cb element array which if of max_size >= new size + * + * @return true on successfully increasing the size + * false on failure + */ +bool ia_css_circbuf_increase_size( + ia_css_circbuf_t *cb, + unsigned int sz_delta, + ia_css_circbuf_elem_t *elems); + +#endif /*_IA_CSS_CIRCBUF_H */ diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h new file mode 100644 index 000000000..6fa6da859 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _IA_CSS_CIRCBUF_COMM_H +#define _IA_CSS_CIRCBUF_COMM_H + +#include /* uint8_t, uint32_t */ + +#define IA_CSS_CIRCBUF_PADDING 1 /* The circular buffer is implemented in lock-less manner, wherein + * the head and tail can advance independently without any locks. + * But to achieve this, an extra buffer element is required to detect + * queue full & empty conditions, wherein the tail trails the head for + * full and is equal to head for empty condition. This causes 1 buffer + * not being available for use. + */ + +/**************************************************************** + * + * Portable Data structures + * + ****************************************************************/ +/** + * @brief Data structure for the circular descriptor. + */ +typedef struct ia_css_circbuf_desc_s ia_css_circbuf_desc_t; +struct ia_css_circbuf_desc_s { + u8 size; /* the maximum number of elements*/ + u8 step; /* number of bytes per element */ + u8 start; /* index of the oldest element */ + u8 end; /* index at which to write the new element */ +}; + +#define SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT \ + (4 * sizeof(uint8_t)) + +/** + * @brief Data structure for the circular buffer element. + */ +typedef struct ia_css_circbuf_elem_s ia_css_circbuf_elem_t; +struct ia_css_circbuf_elem_s { + u32 val; /* the value stored in the element */ +}; + +#define SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT \ + (sizeof(uint32_t)) + +#endif /*_IA_CSS_CIRCBUF_COMM_H*/ diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h new file mode 100644 index 000000000..1071813a2 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _IA_CSS_CIRCBUF_DESC_H_ +#define _IA_CSS_CIRCBUF_DESC_H_ + +#include +#include +#include +#include +#include "ia_css_circbuf_comm.h" +/**************************************************************** + * + * Inline functions. + * + ****************************************************************/ +/** + * @brief Test if the circular buffer is empty. + * + * @param cb_desc The pointer to the circular buffer descriptor. + * + * @return + * - true when it is empty. + * - false when it is not empty. + */ +static inline bool ia_css_circbuf_desc_is_empty( + ia_css_circbuf_desc_t *cb_desc) +{ + OP___assert(cb_desc); + return (cb_desc->end == cb_desc->start); +} + +/** + * @brief Test if the circular buffer descriptor is full. + * + * @param cb_desc The pointer to the circular buffer + * descriptor. + * + * @return + * - true when it is full. + * - false when it is not full. + */ +static inline bool ia_css_circbuf_desc_is_full( + ia_css_circbuf_desc_t *cb_desc) +{ + OP___assert(cb_desc); + return (OP_std_modadd(cb_desc->end, 1, cb_desc->size) == cb_desc->start); +} + +/** + * @brief Initialize the circular buffer descriptor + * + * @param cb_desc The pointer circular buffer descriptor + * @param size The size of the circular buffer + */ +static inline void ia_css_circbuf_desc_init( + ia_css_circbuf_desc_t *cb_desc, + int8_t size) +{ + OP___assert(cb_desc); + cb_desc->size = size; +} + +/** + * @brief Get a position in the circular buffer descriptor. + * + * @param cb The pointer to the circular buffer descriptor. + * @param base The base position. + * @param offset The offset. + * + * @return the position in the circular buffer descriptor. + */ +static inline uint8_t ia_css_circbuf_desc_get_pos_at_offset( + ia_css_circbuf_desc_t *cb_desc, + u32 base, + int offset) +{ + u8 dest; + + OP___assert(cb_desc); + OP___assert(cb_desc->size > 0); + + /* step 1: adjust the offset */ + while (offset < 0) { + offset += cb_desc->size; + } + + /* step 2: shift and round by the upper limit */ + dest = OP_std_modadd(base, offset, cb_desc->size); + + return dest; +} + +/** + * @brief Get the offset between two positions in the circular buffer + * descriptor. + * Get the offset from the source position to the terminal position, + * along the direction in which the new elements come in. + * + * @param cb_desc The pointer to the circular buffer descriptor. + * @param src_pos The source position. + * @param dest_pos The terminal position. + * + * @return the offset. + */ +static inline int ia_css_circbuf_desc_get_offset( + ia_css_circbuf_desc_t *cb_desc, + u32 src_pos, + uint32_t dest_pos) +{ + int offset; + + OP___assert(cb_desc); + + offset = (int)(dest_pos - src_pos); + offset += (offset < 0) ? cb_desc->size : 0; + + return offset; +} + +/** + * @brief Get the number of available elements. + * + * @param cb_desc The pointer to the circular buffer. + * + * @return The number of available elements. + */ +static inline uint32_t ia_css_circbuf_desc_get_num_elems( + ia_css_circbuf_desc_t *cb_desc) +{ + int num; + + OP___assert(cb_desc); + + num = ia_css_circbuf_desc_get_offset(cb_desc, + cb_desc->start, + cb_desc->end); + + return (uint32_t)num; +} + +/** + * @brief Get the number of free elements. + * + * @param cb_desc The pointer to the circular buffer descriptor. + * + * @return: The number of free elements. + */ +static inline uint32_t ia_css_circbuf_desc_get_free_elems( + ia_css_circbuf_desc_t *cb_desc) +{ + u32 num; + + OP___assert(cb_desc); + + num = ia_css_circbuf_desc_get_offset(cb_desc, + cb_desc->start, + cb_desc->end); + + return (cb_desc->size - num); +} +#endif /*_IA_CSS_CIRCBUF_DESC_H_ */ diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c b/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c new file mode 100644 index 000000000..d9f7c1437 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "ia_css_circbuf.h" + +#include + +/********************************************************************** + * + * Forward declarations. + * + **********************************************************************/ +/* + * @brief Read the oldest element from the circular buffer. + * Read the oldest element WITHOUT checking whehter the + * circular buffer is empty or not. The oldest element is + * also removed out from the circular buffer. + * + * @param cb The pointer to the circular buffer. + * + * @return the oldest element. + */ +static inline ia_css_circbuf_elem_t +ia_css_circbuf_read(ia_css_circbuf_t *cb); + +/* + * @brief Shift a chunk of elements in the circular buffer. + * A chunk of elements (i.e. the ones from the "start" position + * to the "chunk_src" position) are shifted in the circular buffer, + * along the direction of new elements coming. + * + * @param cb The pointer to the circular buffer. + * @param chunk_src The position at which the first element in the chunk is. + * @param chunk_dest The position to which the first element in the chunk would be shift. + */ +static inline void ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb, + u32 chunk_src, + uint32_t chunk_dest); + +/* + * @brief Get the "val" field in the element. + * + * @param elem The pointer to the element. + * + * @return the "val" field. + */ +static inline uint32_t +ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem); + +/********************************************************************** + * + * Non-inline functions. + * + **********************************************************************/ +/* + * @brief Create the circular buffer. + * Refer to "ia_css_circbuf.h" for details. + */ +void +ia_css_circbuf_create(ia_css_circbuf_t *cb, + ia_css_circbuf_elem_t *elems, + ia_css_circbuf_desc_t *desc) +{ + u32 i; + + OP___assert(desc); + + cb->desc = desc; + /* Initialize to defaults */ + cb->desc->start = 0; + cb->desc->end = 0; + cb->desc->step = 0; + + for (i = 0; i < cb->desc->size; i++) + ia_css_circbuf_elem_init(&elems[i]); + + cb->elems = elems; +} + +/* + * @brief Destroy the circular buffer. + * Refer to "ia_css_circbuf.h" for details. + */ +void ia_css_circbuf_destroy(ia_css_circbuf_t *cb) +{ + cb->desc = NULL; + + cb->elems = NULL; +} + +/* + * @brief Pop a value out of the circular buffer. + * Refer to "ia_css_circbuf.h" for details. + */ +uint32_t ia_css_circbuf_pop(ia_css_circbuf_t *cb) +{ + u32 ret; + ia_css_circbuf_elem_t elem; + + assert(!ia_css_circbuf_is_empty(cb)); + + /* read an element from the buffer */ + elem = ia_css_circbuf_read(cb); + ret = ia_css_circbuf_elem_get_val(&elem); + return ret; +} + +/* + * @brief Extract a value out of the circular buffer. + * Refer to "ia_css_circbuf.h" for details. + */ +uint32_t ia_css_circbuf_extract(ia_css_circbuf_t *cb, int offset) +{ + int max_offset; + u32 val; + u32 pos; + u32 src_pos; + u32 dest_pos; + + /* get the maximum offest */ + max_offset = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end); + max_offset--; + + /* + * Step 1: When the target element is at the "start" position. + */ + if (offset == 0) { + val = ia_css_circbuf_pop(cb); + return val; + } + + /* + * Step 2: When the target element is out of the range. + */ + if (offset > max_offset) { + val = 0; + return val; + } + + /* + * Step 3: When the target element is between the "start" and + * "end" position. + */ + /* get the position of the target element */ + pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset); + + /* get the value from the target element */ + val = ia_css_circbuf_elem_get_val(&cb->elems[pos]); + + /* shift the elements */ + src_pos = ia_css_circbuf_get_pos_at_offset(cb, pos, -1); + dest_pos = pos; + ia_css_circbuf_shift_chunk(cb, src_pos, dest_pos); + + return val; +} + +/* + * @brief Peek an element from the circular buffer. + * Refer to "ia_css_circbuf.h" for details. + */ +uint32_t ia_css_circbuf_peek(ia_css_circbuf_t *cb, int offset) +{ + int pos; + + pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, offset); + + /* get the value at the position */ + return cb->elems[pos].val; +} + +/* + * @brief Get the value of an element from the circular buffer. + * Refer to "ia_css_circbuf.h" for details. + */ +uint32_t ia_css_circbuf_peek_from_start(ia_css_circbuf_t *cb, int offset) +{ + int pos; + + pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset); + + /* get the value at the position */ + return cb->elems[pos].val; +} + +/* @brief increase size of a circular buffer. + * Use 'CAUTION' before using this function. This was added to + * support / fix issue with increasing size for tagger only + * Please refer to "ia_css_circbuf.h" for details. + */ +bool ia_css_circbuf_increase_size( + ia_css_circbuf_t *cb, + unsigned int sz_delta, + ia_css_circbuf_elem_t *elems) +{ + u8 curr_size; + u8 curr_end; + unsigned int i = 0; + + if (!cb || sz_delta == 0) + return false; + + curr_size = cb->desc->size; + curr_end = cb->desc->end; + /* We assume cb was pre defined as global to allow + * increase in size */ + /* FM: are we sure this cannot cause size to become too big? */ + if (((uint8_t)(cb->desc->size + (uint8_t)sz_delta) > cb->desc->size) && + ((uint8_t)sz_delta == sz_delta)) + cb->desc->size += (uint8_t)sz_delta; + else + return false; /* overflow in size */ + + /* If elems are passed update them else we assume its been taken + * care before calling this function */ + if (elems) { + /* cb element array size will not be increased dynamically, + * but pointers to new elements can be added at the end + * of existing pre defined cb element array of + * size >= new size if not already added */ + for (i = curr_size; i < cb->desc->size; i++) + cb->elems[i] = elems[i - curr_size]; + } + /* Fix Start / End */ + if (curr_end < cb->desc->start) { + if (curr_end == 0) { + /* Easily fix End */ + cb->desc->end = curr_size; + } else { + /* Move elements and fix Start*/ + ia_css_circbuf_shift_chunk(cb, + curr_size - 1, + curr_size + sz_delta - 1); + } + } + + return true; +} + +/**************************************************************** + * + * Inline functions. + * + ****************************************************************/ +/* + * @brief Get the "val" field in the element. + * Refer to "Forward declarations" for details. + */ +static inline uint32_t +ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem) +{ + return elem->val; +} + +/* + * @brief Read the oldest element from the circular buffer. + * Refer to "Forward declarations" for details. + */ +static inline ia_css_circbuf_elem_t +ia_css_circbuf_read(ia_css_circbuf_t *cb) +{ + ia_css_circbuf_elem_t elem; + + /* get the element from the target position */ + elem = cb->elems[cb->desc->start]; + + /* clear the target position */ + ia_css_circbuf_elem_init(&cb->elems[cb->desc->start]); + + /* adjust the "start" position */ + cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, 1); + return elem; +} + +/* + * @brief Shift a chunk of elements in the circular buffer. + * Refer to "Forward declarations" for details. + */ +static inline void +ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb, + u32 chunk_src, uint32_t chunk_dest) +{ + int chunk_offset; + int chunk_sz; + int i; + + /* get the chunk offset and size */ + chunk_offset = ia_css_circbuf_get_offset(cb, + chunk_src, chunk_dest); + chunk_sz = ia_css_circbuf_get_offset(cb, cb->desc->start, chunk_src) + 1; + + /* shift each element to its terminal position */ + for (i = 0; i < chunk_sz; i++) { + /* copy the element from the source to the destination */ + ia_css_circbuf_elem_cpy(&cb->elems[chunk_src], + &cb->elems[chunk_dest]); + + /* clear the source position */ + ia_css_circbuf_elem_init(&cb->elems[chunk_src]); + + /* adjust the source/terminal positions */ + chunk_src = ia_css_circbuf_get_pos_at_offset(cb, chunk_src, -1); + chunk_dest = ia_css_circbuf_get_pos_at_offset(cb, chunk_dest, -1); + } + + /* adjust the index "start" */ + cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, + chunk_offset); +} diff --git a/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h b/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h new file mode 100644 index 000000000..78cf0cbfb --- /dev/null +++ b/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _IA_CSS_REFCOUNT_H_ +#define _IA_CSS_REFCOUNT_H_ + +#include +#include +#include +#include + +typedef void (*clear_func)(ia_css_ptr ptr); + +/*! \brief Function for initializing refcount list + * + * \param[in] size Size of the refcount list. + * \return ia_css_err + */ +int ia_css_refcount_init(uint32_t size); + +/*! \brief Function for de-initializing refcount list + * + * \return None + */ +void ia_css_refcount_uninit(void); + +/*! \brief Function for increasing reference by 1. + * + * \param[in] id ID of the object. + * \param[in] ptr Data of the object (ptr). + * \return ia_css_ptr (saved address) + */ +ia_css_ptr ia_css_refcount_increment(s32 id, ia_css_ptr ptr); + +/*! \brief Function for decrease reference by 1. + * + * \param[in] id ID of the object. + * \param[in] ptr Data of the object (ptr). + * + * - true, if it is successful. + * - false, otherwise. + */ +bool ia_css_refcount_decrement(s32 id, ia_css_ptr ptr); + +/*! \brief Function to check if reference count is 1. + * + * \param[in] ptr Data of the object (ptr). + * + * - true, if it is successful. + * - false, otherwise. + */ +bool ia_css_refcount_is_single(ia_css_ptr ptr); + +/*! \brief Function to clear reference list objects. + * + * \param[in] id ID of the object. + * \param[in] clear_func function to be run to free reference objects. + * + * return None + */ +void ia_css_refcount_clear(s32 id, + clear_func clear_func_ptr); + +/*! \brief Function to verify if object is valid + * + * \param[in] ptr Data of the object (ptr) + * + * - true, if valid + * - false, if invalid + */ +bool ia_css_refcount_is_valid(ia_css_ptr ptr); + +#endif /* _IA_CSS_REFCOUNT_H_ */ diff --git a/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c b/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c new file mode 100644 index 000000000..a9c881631 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "hmm.h" + +#include "ia_css_refcount.h" +#include "sh_css_defs.h" + +#include "platform_support.h" + +#include "assert_support.h" + +#include "ia_css_debug.h" + +/* TODO: enable for other memory aswell + now only for ia_css_ptr */ +struct ia_css_refcount_entry { + u32 count; + ia_css_ptr data; + s32 id; +}; + +struct ia_css_refcount_list { + u32 size; + struct ia_css_refcount_entry *items; +}; + +static struct ia_css_refcount_list myrefcount; + +static struct ia_css_refcount_entry *refcount_find_entry(ia_css_ptr ptr, + bool firstfree) +{ + u32 i; + + if (ptr == 0) + return NULL; + if (!myrefcount.items) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, + "%s(): Ref count not initialized!\n", __func__); + return NULL; + } + + for (i = 0; i < myrefcount.size; i++) { + if ((&myrefcount.items[i])->data == 0) { + if (firstfree) { + /* for new entry */ + return &myrefcount.items[i]; + } + } + if ((&myrefcount.items[i])->data == ptr) { + /* found entry */ + return &myrefcount.items[i]; + } + } + return NULL; +} + +int ia_css_refcount_init(uint32_t size) +{ + int err = 0; + + if (size == 0) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s(): Size of 0 for Ref count init!\n", __func__); + return -EINVAL; + } + if (myrefcount.items) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s(): Ref count is already initialized\n", __func__); + return -EINVAL; + } + myrefcount.items = + kvmalloc(sizeof(struct ia_css_refcount_entry) * size, GFP_KERNEL); + if (!myrefcount.items) + err = -ENOMEM; + if (!err) { + memset(myrefcount.items, 0, + sizeof(struct ia_css_refcount_entry) * size); + myrefcount.size = size; + } + return err; +} + +void ia_css_refcount_uninit(void) +{ + struct ia_css_refcount_entry *entry; + u32 i; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s() entry\n", __func__); + for (i = 0; i < myrefcount.size; i++) { + /* driver verifier tool has issues with &arr[i] + and prefers arr + i; as these are actually equivalent + the line below uses + i + */ + entry = myrefcount.items + i; + if (entry->data != mmgr_NULL) { + /* ia_css_debug_dtrace(IA_CSS_DBG_TRACE, + "ia_css_refcount_uninit: freeing (%x)\n", + entry->data);*/ + hmm_free(entry->data); + entry->data = mmgr_NULL; + entry->count = 0; + entry->id = 0; + } + } + kvfree(myrefcount.items); + myrefcount.items = NULL; + myrefcount.size = 0; + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s() leave\n", __func__); +} + +ia_css_ptr ia_css_refcount_increment(s32 id, ia_css_ptr ptr) +{ + struct ia_css_refcount_entry *entry; + + if (ptr == mmgr_NULL) + return ptr; + + entry = refcount_find_entry(ptr, false); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s(%x) 0x%x\n", __func__, id, ptr); + + if (!entry) { + entry = refcount_find_entry(ptr, true); + assert(entry); + if (!entry) + return mmgr_NULL; + entry->id = id; + } + + if (entry->id != id) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, + "%s(): Ref count IDS do not match!\n", __func__); + return mmgr_NULL; + } + + if (entry->data == ptr) + entry->count += 1; + else if (entry->data == mmgr_NULL) { + entry->data = ptr; + entry->count = 1; + } else + return mmgr_NULL; + + return ptr; +} + +bool ia_css_refcount_decrement(s32 id, ia_css_ptr ptr) +{ + struct ia_css_refcount_entry *entry; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s(%x) 0x%x\n", __func__, id, ptr); + + if (ptr == mmgr_NULL) + return false; + + entry = refcount_find_entry(ptr, false); + + if (entry) { + if (entry->id != id) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, + "%s(): Ref count IDS do not match!\n", __func__); + return false; + } + if (entry->count > 0) { + entry->count -= 1; + if (entry->count == 0) { + /* ia_css_debug_dtrace(IA_CSS_DBEUG_TRACE, + "ia_css_refcount_decrement: freeing\n");*/ + hmm_free(ptr); + entry->data = mmgr_NULL; + entry->id = 0; + } + return true; + } + } + + /* SHOULD NOT HAPPEN: ptr not managed by refcount, or not + valid anymore */ + if (entry) + IA_CSS_ERROR("id %x, ptr 0x%x entry %p entry->id %x entry->count %d\n", + id, ptr, entry, entry->id, entry->count); + else + IA_CSS_ERROR("entry NULL\n"); + assert(false); + + return false; +} + +bool ia_css_refcount_is_single(ia_css_ptr ptr) +{ + struct ia_css_refcount_entry *entry; + + if (ptr == mmgr_NULL) + return false; + + entry = refcount_find_entry(ptr, false); + + if (entry) + return (entry->count == 1); + + return true; +} + +void ia_css_refcount_clear(s32 id, clear_func clear_func_ptr) +{ + struct ia_css_refcount_entry *entry; + u32 i; + u32 count = 0; + + assert(clear_func_ptr); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s(%x)\n", + __func__, id); + + for (i = 0; i < myrefcount.size; i++) { + /* driver verifier tool has issues with &arr[i] + and prefers arr + i; as these are actually equivalent + the line below uses + i + */ + entry = myrefcount.items + i; + if ((entry->data != mmgr_NULL) && (entry->id == id)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s: %x: 0x%x\n", __func__, + id, entry->data); + if (clear_func_ptr) { + /* clear using provided function */ + clear_func_ptr(entry->data); + } else { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s: using hmm_free: no clear_func\n", __func__); + hmm_free(entry->data); + } + + if (entry->count != 0) { + IA_CSS_WARNING("Ref count for entry %x is not zero!", entry->id); + } + + assert(entry->count == 0); + + entry->data = mmgr_NULL; + entry->count = 0; + entry->id = 0; + count++; + } + } + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "%s(%x): cleared %d\n", __func__, id, + count); +} + +bool ia_css_refcount_is_valid(ia_css_ptr ptr) +{ + struct ia_css_refcount_entry *entry; + + if (ptr == mmgr_NULL) + return false; + + entry = refcount_find_entry(ptr, false); + + return entry; +} -- cgit v1.2.3