kernel_samsung_a53x/drivers/soc/samsung/cpif/include/circ_queue.h
2024-06-15 16:02:09 -03:00

282 lines
7.5 KiB
C
Executable file

/* SPDX-License-Identifier: GPL-2.0 */
/*
* @file circ_queue.h
* @brief header file for general circular queue operations
* @date 2014/02/18
* @author Hankook Jang (hankook.jang@samsung.com)
*/
/*
* Copyright (C) 2010 Samsung Electronics.
*
*/
#ifndef __MODEM_CIRCULAR_QUEUE_H__
#define __MODEM_CIRCULAR_QUEUE_H__
#include <linux/spinlock.h>
#include <linux/types.h>
/*
* @brief the structure for a circular queue in a memory-type interface
*/
struct circ_queue {
spinlock_t lock;
/*
* the flag and counter for checking busy status of a circualr queue
*/
atomic_t busy;
/*
* the start address of the data buffer in a circualr queue
*/
void __iomem *buff;
/*
* the size of the data buffer in a circular queue
*/
unsigned int size;
/*
* the pointer to the "HEAD (IN)" variable that contains a byte offset
* from @b @@buff
*/
void __iomem *head;
/*
* the pointer to the "TAIL (OUT)" variable that contains a byte offset
* from @b @@buff
*/
void __iomem *tail;
};
/*
* @brief get the start address of the data buffer in a circular queue
* @param q the pointer to a circular queue
* @return the start address of the data buffer in the @e @@q
*/
static inline char *get_buff(struct circ_queue *q)
{
return q->buff;
}
/*
* @brief get the size of the data buffer in a circular queue
* @param q the pointer to a circular queue
* @return the size of the data buffer in the @e @@q
*/
static inline unsigned int get_size(struct circ_queue *q)
{
return q->size;
}
/*
* @brief get the "HEAD (IN)" pointer value of a circular queue
* @param q the pointer to a circular queue
* @return the "HEAD (IN)" pointer value of the @e @@q
*/
static inline unsigned int get_head(struct circ_queue *q)
{
return ioread32(q->head);
}
/*
* @brief set the "HEAD (IN)" pointer value of a circular queue with @b
* @@in
* @param q the pointer to a circular queue
* @param in the value to be stored into the "HEAD (IN)" pointer
*/
static inline void set_head(struct circ_queue *q, unsigned int in)
{
iowrite32(in, q->head);
}
/*
* @brief get the "TAIL (OUT)" pointer value of a circular queue
* @param q the pointer to a circular queue
* @return the "TAIL (OUT)" pointer value of the @e @@q
*/
static inline unsigned int get_tail(struct circ_queue *q)
{
return ioread32(q->tail);
}
/*
* @brief set the "TAIL (OUT)" pointer value of a circular queue with @e
* @@out
* @param q the pointer to a circular queue
* @param out the value to be stored into the "TAIL (OUT)" pointer
*/
static inline void set_tail(struct circ_queue *q, unsigned int out)
{
iowrite32(out, q->tail);
}
/*
* @brief check whether or not both "IN" and "OUT" pointer values are valid
* @param qsize the size of the data buffer in a circular queue
* @param in the value of the "HEAD (IN)" pointer
* @param out the value of the "TAIL (OUT)" pointer
* @retval "true" if all pointer values are valid
* @retval "false" if either IN or OUT pointer value is NOT valid
*/
static inline bool circ_valid(unsigned int qsize,
unsigned int in,
unsigned int out)
{
if (unlikely(in >= qsize))
return false;
if (unlikely(out >= qsize))
return false;
return true;
}
/*
* @brief check whether or not a circular queue is empty
* @param in the value of the "HEAD (IN)" pointer
* @param out the value of the "TAIL (OUT)" pointer
* @retval "true" if a circular queue is empty
* @retval "false" if a circular queue is NOT empty
*/
static inline bool circ_empty(unsigned int in, unsigned int out)
{
return (in == out);
}
/*
* @brief get the size of free space in a circular queue
* @param qsize the size of the data buffer in a circular queue
* @param in the value of the "HEAD (IN)" pointer
* @param out the value of the "TAIL (OUT)" pointer
* @return the size of free space in a circular queue
*/
static inline unsigned int circ_get_space(unsigned int qsize,
unsigned int in,
unsigned int out)
{
return (in < out) ? (out - in - 1) : (qsize + out - in - 1);
}
static inline bool circ_full(unsigned int qsize, unsigned int in,
unsigned int out)
{
return (circ_get_space(qsize, in, out) == 0);
}
/*
* @brief get the size of data in a circular queue
* @param qsize the size of the data buffer in a circular queue
* @param in the value of the "HEAD (IN)" pointer
* @param out the value of the "TAIL (OUT)" pointer
* @return the size of data in a circular queue
*/
static inline unsigned int circ_get_usage(unsigned int qsize,
unsigned int in,
unsigned int out)
{
return (in >= out) ? (in - out) : (qsize - out + in);
}
/*
* @brief calculate a new pointer value for a circular queue
* @param qsize the size of the data buffer in a circular queue
* @param p the old value of a queue pointer
* @param len the length to be added to the @e @@p pointer value
* @return the new value for the queue pointer
*/
static inline unsigned int circ_new_ptr(unsigned int qsize,
unsigned int p,
unsigned int len)
{
unsigned int np = (p + len);
while (np >= qsize)
np -= qsize;
return np;
}
/*
* @brief calculate a previous pointer value for a circular queue
* @param qsize the size of the data buffer in a circular queue
* @param p the old value of a queue pointer
* @param len the length to be prior to the @e @@p pointer value
* @return the new value for the queue pointer
*/
static inline unsigned int circ_prev_ptr(unsigned int qsize,
unsigned int p,
unsigned int len)
{
int np = ((int)p - len);
while (np < 0)
np += qsize;
return (unsigned int)np;
}
/*
* @brief copy the data in a circular queue to a local buffer
* @param dst the start address of the local buffer
* @param src the start address of the data buffer in a circular queue
* @param qsize the size of the data buffer in a circular queue
* @param out the offset in the data buffer to be read
* @param len the length of data to be read
* @remark This function should be invoked after checking the data length.
*/
static inline void circ_read(u8 *dst, u8 *src, unsigned int qsize,
unsigned int out, unsigned int len)
{
if ((out + len) <= qsize) {
/* ----- (out) (in) ----- */
/* ----- 7f 00 00 7e ----- */
memcpy(dst, (src + out), len);
} else {
unsigned int len1;
/* (in) ----------- (out) */
/* 00 7e ----------- 7f 00 */
/* 1) data start (out) ~ buffer end */
len1 = qsize - out;
memcpy(dst, (src + out), len1);
/* 2) buffer start ~ data end (in?) */
memcpy((dst + len1), src, (len - len1));
}
}
/*
* @brief copy the data in a local buffer to a circular queue
* @param dst the start address of the data buffer in a circular queue
* @param src the start address of the data in a local buffer
* @param qsize the size of the data buffer in a circular queue
* @param in the offset in the data buffer for the data to be stored
* @param len the length of data to be stored
* @remark This function should be invoked after checking the free space.
*/
static inline void circ_write(u8 *dst, u8 *src, unsigned int qsize,
unsigned int in, unsigned int len)
{
if ((in + len) < qsize) {
/* (in) ----------- (out) */
/* 00 7e ----------- 7f 00 */
memcpy((dst + in), src, len);
} else {
unsigned int space;
/* ----- (out) (in) ----- */
/* ----- 7f 00 00 7e ----- */
/* 1) space start (in) ~ buffer end */
space = qsize - in;
memcpy((dst + in), src, ((len > space) ? space : len));
/* 2) buffer start ~ data end */
if (len > space)
memcpy(dst, (src + space), (len - space));
}
}
#endif