372 lines
11 KiB
C
372 lines
11 KiB
C
/*******************************************************************************
|
|
** This file is provided under a dual BSD/GPLv2 license. When using or
|
|
** redistributing this file, you may do so under either license.
|
|
**
|
|
** GPL LICENSE SUMMARY
|
|
**
|
|
** Copyright (c) 2013 Intel Corporation All Rights Reserved
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify it under
|
|
** the terms of version 2 of the GNU General Public License as published by the
|
|
** Free Software Foundation.
|
|
**
|
|
** This program is distributed in the hope that 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.
|
|
**
|
|
** You should have received a copy of the GNU General Public License along with
|
|
** this program; if not, write to the Free Software Foundation, Inc.,
|
|
** 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
** The full GNU General Public License is included in this distribution in the
|
|
** file called LICENSE.GPL.
|
|
**
|
|
** BSD LICENSE
|
|
**
|
|
** Copyright (c) 2013 Intel Corporation All Rights Reserved
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions are met:
|
|
**
|
|
** * Redistributions of source code must retain the above copyright notice, this
|
|
** list of conditions and the following disclaimer.
|
|
** * Redistributions in binary form must reproduce the above copyright notice,
|
|
** this list of conditions and the following disclaimer in the documentation
|
|
** and/or other materials provided with the distribution.
|
|
** * Neither the name of Intel Corporation nor the names of its contributors may
|
|
** be used to endorse or promote products derived from this software without
|
|
** specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
** POSSIBILITY OF SUCH DAMAGE.
|
|
**
|
|
*******************************************************************************/
|
|
|
|
#include "esif_queue.h"
|
|
|
|
#ifdef ESIF_ATTR_OS_WINDOWS
|
|
/*
|
|
*
|
|
* The Windows banned-API check header must be included after all other headers,
|
|
* or issues can be identified
|
|
* against Windows SDK/DDK included headers which we have no control over.
|
|
*
|
|
*/
|
|
#define _SDL_BANNED_RECOMMENDED
|
|
#include "win\banned.h"
|
|
#endif
|
|
|
|
#ifdef ESIF_ATTR_KERNEL
|
|
|
|
#define INIT_DEBUG 0
|
|
#define Q_DEBUG 1
|
|
#define PULL_DEBUG 2
|
|
#define SEM_DEBUG 3
|
|
|
|
#define ESIF_TRACE_DYN_INIT(format, ...) \
|
|
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_QUEUE, INIT_DEBUG, format, ##__VA_ARGS__)
|
|
#define ESIF_TRACE_DYN_Q(format, ...) \
|
|
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_QUEUE, Q_DEBUG, format, ##__VA_ARGS__)
|
|
#define ESIF_TRACE_DYN_PULL(format, ...) \
|
|
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_QUEUE, PULL_DEBUG, format, ##__VA_ARGS__)
|
|
#define ESIF_TRACE_DYN_SEM(format, ...) \
|
|
ESIF_TRACE_DYN(ESIF_DEBUG_MOD_QUEUE, SEM_DEBUG, format, ##__VA_ARGS__)
|
|
|
|
#else /* ESIF_ATTR_KERNEL */
|
|
|
|
/*
|
|
* TODO: User mode does not currently use the queue code.
|
|
* Need to update when user mode unified debug infrastructre
|
|
* is in place.
|
|
*/
|
|
#define ESIF_TRACE_DYN_INIT NO_ESIF_DEBUG
|
|
#define ESIF_TRACE_DYN_Q NO_ESIF_DEBUG
|
|
#define ESIF_TRACE_DYN_PULL NO_ESIF_DEBUG
|
|
#define ESIF_TRACE_DYN_SEM NO_ESIF_DEBUG
|
|
|
|
#endif /* ESIF_ATTR_USER */
|
|
|
|
/* Queue Node */
|
|
struct esif_queue_node {
|
|
struct esif_queue_node *next_ptr; /* Next Item In The Queue */
|
|
struct esif_ipc *ipc_ptr; /* Queued IPC/Event */
|
|
};
|
|
|
|
/* Queue Create */
|
|
struct esif_queue_instance *esif_queue_create(
|
|
u32 depth,
|
|
char *name_ptr
|
|
)
|
|
{
|
|
struct esif_queue_instance *queue_ptr = (struct esif_queue_instance *)
|
|
esif_ccb_malloc(sizeof(*queue_ptr));
|
|
if (NULL == queue_ptr)
|
|
return NULL;
|
|
|
|
esif_ccb_lock_init(&queue_ptr->lock);
|
|
esif_ccb_sem_init(&queue_ptr->semaphore);
|
|
queue_ptr->max_size = depth;
|
|
queue_ptr->us_timeout = 1000000;/* Second */
|
|
queue_ptr->name_ptr = name_ptr;
|
|
|
|
ESIF_TRACE_DYN_Q("%s: Create %s Queue %p depth = %d\n",
|
|
ESIF_FUNC,
|
|
name_ptr,
|
|
queue_ptr,
|
|
depth);
|
|
return queue_ptr;
|
|
}
|
|
|
|
|
|
/* Queue Destroy */
|
|
void esif_queue_destroy(struct esif_queue_instance *queue_ptr)
|
|
{
|
|
struct esif_queue_node *current_ptr = queue_ptr->head_ptr;
|
|
|
|
esif_ccb_write_lock(&queue_ptr->lock);
|
|
for (current_ptr = queue_ptr->head_ptr;
|
|
current_ptr != queue_ptr->tail_ptr;
|
|
current_ptr = queue_ptr->head_ptr) {
|
|
queue_ptr->head_ptr = current_ptr->next_ptr;
|
|
|
|
ESIF_TRACE_DYN_Q("%s: %s Queue Clean ipc %p\n",
|
|
ESIF_FUNC, queue_ptr->name_ptr, current_ptr);
|
|
|
|
esif_ipc_free(current_ptr->ipc_ptr);
|
|
esif_ccb_mempool_free(ESIF_MEMPOOL_TYPE_QUEUE, current_ptr);
|
|
}
|
|
|
|
if (current_ptr != NULL) {
|
|
ESIF_TRACE_DYN_Q("%s: %s Queue Clean ipc %p\n",
|
|
ESIF_FUNC, queue_ptr->name_ptr, current_ptr);
|
|
|
|
esif_ipc_free(current_ptr->ipc_ptr);
|
|
|
|
esif_ccb_mempool_free(ESIF_MEMPOOL_TYPE_QUEUE, current_ptr);
|
|
}
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
esif_ccb_lock_uninit(&queue->lock);
|
|
esif_ccb_sem_uninit(&queue->semaphore);
|
|
ESIF_TRACE_DYN_Q("%s: %s Destroy Queue %p\n",
|
|
ESIF_FUNC,
|
|
queue_ptr->name_ptr,
|
|
queue_ptr);
|
|
esif_ccb_free(queue_ptr);
|
|
}
|
|
|
|
|
|
/* Queue Config */
|
|
enum esif_rc esif_queue_config(
|
|
struct esif_queue_instance *queue_ptr,
|
|
u32 us_timeout,
|
|
u32 max_size
|
|
)
|
|
{
|
|
esif_ccb_write_lock(&queue_ptr->lock);
|
|
queue_ptr->us_timeout = us_timeout;
|
|
queue_ptr->max_size = max_size;
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
return ESIF_OK;
|
|
}
|
|
|
|
|
|
/* Queue Push (Puts in back of linked list)*/
|
|
enum esif_rc esif_queue_push(
|
|
struct esif_queue_instance *queue_ptr,
|
|
struct esif_ipc *ipc_ptr
|
|
)
|
|
{
|
|
struct esif_queue_node *node_ptr = NULL;
|
|
|
|
if (queue_ptr->current_size >= queue_ptr->max_size) {
|
|
ESIF_TRACE_DYN_Q("%s: No queue space, max size = %d\n",
|
|
ESIF_FUNC,
|
|
queue_ptr->max_size);
|
|
return ESIF_E_NO_MEMORY;
|
|
}
|
|
|
|
node_ptr = esif_ccb_mempool_zalloc(ESIF_MEMPOOL_TYPE_QUEUE);
|
|
if (NULL == node_ptr)
|
|
return ESIF_E_NO_MEMORY;
|
|
|
|
node_ptr->ipc_ptr = ipc_ptr;
|
|
|
|
esif_ccb_write_lock(&queue_ptr->lock);
|
|
node_ptr->next_ptr = NULL;
|
|
if (NULL == queue_ptr->head_ptr) {
|
|
queue_ptr->head_ptr = node_ptr;
|
|
queue_ptr->tail_ptr = node_ptr;
|
|
} else {
|
|
queue_ptr->tail_ptr->next_ptr = node_ptr;
|
|
queue_ptr->tail_ptr = node_ptr;
|
|
}
|
|
queue_ptr->current_size++;
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
|
|
/* Wakeup */
|
|
ESIF_TRACE_DYN_Q("%s: %s Queue Push q %p ipc %p SEM UP\n",
|
|
ESIF_FUNC, queue_ptr->name_ptr, queue_ptr, ipc_ptr);
|
|
|
|
esif_ccb_sem_up(&queue_ptr->semaphore);
|
|
return ESIF_OK;
|
|
}
|
|
|
|
|
|
/* Queue Push (Put at front of linked list, used for returning item to queue) */
|
|
enum esif_rc esif_queue_requeue(
|
|
struct esif_queue_instance *queue_ptr,
|
|
struct esif_ipc *ipc_ptr
|
|
)
|
|
{
|
|
struct esif_queue_node *node_ptr = NULL;
|
|
|
|
if (queue_ptr->current_size >= queue_ptr->max_size) {
|
|
ESIF_TRACE_DYN_Q("%s: No queue space, max size = %d\n",
|
|
ESIF_FUNC,
|
|
queue_ptr->max_size);
|
|
return ESIF_E_NO_MEMORY;
|
|
}
|
|
|
|
node_ptr = esif_ccb_mempool_zalloc(ESIF_MEMPOOL_TYPE_QUEUE);
|
|
if (NULL == node_ptr)
|
|
return ESIF_E_NO_MEMORY;
|
|
|
|
node_ptr->ipc_ptr = ipc_ptr;
|
|
|
|
esif_ccb_write_lock(&queue_ptr->lock);
|
|
node_ptr->next_ptr = NULL;
|
|
if (NULL == queue_ptr->head_ptr) {
|
|
queue_ptr->head_ptr = node_ptr;
|
|
queue_ptr->tail_ptr = node_ptr;
|
|
} else {
|
|
node_ptr->next_ptr = queue_ptr->head_ptr;
|
|
queue_ptr->head_ptr = node_ptr;
|
|
}
|
|
queue_ptr->current_size++;
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
|
|
/* Wakeup */
|
|
ESIF_TRACE_DYN_Q("%s: %s Queue Push q %p ipc %p SEM UP\n",
|
|
ESIF_FUNC, queue_ptr->name_ptr, queue_ptr, ipc_ptr);
|
|
|
|
esif_ccb_sem_up(&queue_ptr->semaphore);
|
|
return ESIF_OK;
|
|
}
|
|
|
|
|
|
/* Queue Pull */
|
|
struct esif_ipc *esif_queue_pull(struct esif_queue_instance *queue_ptr)
|
|
{
|
|
struct esif_queue_node *node_ptr = NULL;
|
|
struct esif_ipc *ipc_ptr = NULL;
|
|
|
|
ESIF_TRACE_DYN_SEM("%s: semophore timeout %d\n",
|
|
ESIF_FUNC,
|
|
queue_ptr->us_timeout);
|
|
|
|
/* Wait Forever */
|
|
if (0 == queue_ptr->us_timeout) {
|
|
esif_ccb_sem_down(&queue_ptr->semaphore);
|
|
|
|
/* Wait For N Usecs and If No Queue Entry Availabe Return False */
|
|
} else if (esif_ccb_sem_try_down(&queue_ptr->semaphore,
|
|
queue_ptr->us_timeout) != 0) {
|
|
return NULL;
|
|
}
|
|
|
|
esif_ccb_write_lock(&queue_ptr->lock);
|
|
if (NULL == queue_ptr->head_ptr) {
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
return NULL; /* Could happen if a flush occurs after semaphore*/
|
|
}
|
|
node_ptr = queue_ptr->head_ptr;
|
|
ipc_ptr = node_ptr->ipc_ptr;
|
|
|
|
queue_ptr->head_ptr = node_ptr->next_ptr;
|
|
|
|
if (NULL == queue_ptr->head_ptr)
|
|
queue_ptr->tail_ptr = NULL;
|
|
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
queue_ptr->current_size--;
|
|
|
|
esif_ccb_mempool_free(ESIF_MEMPOOL_TYPE_QUEUE, node_ptr);
|
|
|
|
ESIF_TRACE_DYN_Q("%s: %s Queue Pull q %p ipc %p\n",
|
|
ESIF_FUNC, queue_ptr->name_ptr, queue_ptr, ipc_ptr);
|
|
|
|
return ipc_ptr;
|
|
}
|
|
|
|
|
|
/* Queue Size */
|
|
u32 esif_queue_size(struct esif_queue_instance *queue_ptr)
|
|
{
|
|
ESIF_TRACE_DYN_PULL("%s: %s Queue Size %d\n",
|
|
ESIF_FUNC,
|
|
queue_ptr->name_ptr,
|
|
queue_ptr->current_size);
|
|
return queue_ptr->current_size;
|
|
}
|
|
|
|
|
|
/* Queue Flush */
|
|
void esif_queue_flush(struct esif_queue_instance *queue_ptr)
|
|
{
|
|
struct esif_queue_node *node_ptr = NULL;
|
|
|
|
esif_ccb_write_lock(&queue_ptr->lock);
|
|
node_ptr = queue_ptr->head_ptr;
|
|
while (node_ptr != NULL) {
|
|
queue_ptr->head_ptr = node_ptr->next_ptr;
|
|
esif_ipc_free(node_ptr->ipc_ptr);
|
|
|
|
esif_ccb_mempool_free(ESIF_MEMPOOL_TYPE_QUEUE, node_ptr);
|
|
|
|
node_ptr = queue_ptr->head_ptr;
|
|
}
|
|
queue_ptr->current_size = 0;
|
|
queue_ptr->head_ptr = NULL;
|
|
queue_ptr->tail_ptr = NULL;
|
|
esif_ccb_write_unlock(&queue_ptr->lock);
|
|
}
|
|
|
|
|
|
/* Init */
|
|
enum esif_rc esif_queue_init(void)
|
|
{
|
|
struct esif_ccb_mempool *mempool_ptr = NULL;
|
|
ESIF_TRACE_DYN_INIT("%s: Initialize Queue Manager\n", ESIF_FUNC);
|
|
|
|
mempool_ptr =
|
|
esif_ccb_mempool_create(ESIF_MEMPOOL_TYPE_QUEUE,
|
|
ESIF_MEMPOOL_FW_QUEUE,
|
|
sizeof(struct esif_queue_node));
|
|
if (NULL == mempool_ptr)
|
|
return ESIF_E_NO_MEMORY;
|
|
|
|
return ESIF_OK;
|
|
}
|
|
|
|
|
|
/* Exit */
|
|
void esif_queue_exit(void)
|
|
{
|
|
ESIF_TRACE_DYN_INIT("%s: Exit Queue Manager\n", ESIF_FUNC);
|
|
}
|
|
|
|
|
|
/******************************************************************************/
|
|
/******************************************************************************/
|
|
/******************************************************************************/
|
|
|