blob: 3bedeed9b592bcc24a7ccc583e62304893b87345 [file] [log] [blame]
/******************************************************************************
*
* Copyright (c) 2019 Intel.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*******************************************************************************/
#ifdef __KERNEL__
#include <linux/slab.h>
#include <linux/kernel.h>
#else
#include <stdio.h>
#include <string.h>
#endif
#include "syslib.h"
#include "wls.h"
#ifdef __KERNEL__
#ifdef _DEBUG_
#define PRINT_DEBUG(format, args...) \
do { \
printk(KERN_INFO "wls debug: " format,##args); \
}while(0)
#else
#define PRINT_DEBUG(x, args...) do { } while(0)
#endif
#else
#ifdef _DEBUG_
#define PRINT_DEBUG(x, args...) printf("wls_lib debug: "x, ## args);
#else
#define PRINT_DEBUG(x, args...) do { } while(0)
#endif
#endif
#define SFL_memcpy memcpy
/******************************************************************************
* *
* Generic fast queue that operates with pointers (derived from ICC) *
* *
******************************************************************************/
int SFL_WlsEnqueue(PFASTQUEUE pq, U64 pData, wls_us_addr_conv change_addr, void* hWls)
{
U32 put = pq->put;
U32 new_put = put + 1;
PRINT_DEBUG("off %lx put %d get %d size %d storage %lx\n",(unsigned long)pq - (unsigned long) hWls, pq->put, pq->get, pq->size, pq->pStorage);
if (new_put >= pq->size)
new_put = 0;
if (new_put != pq->get)
{ // the queue is not full
U64* pLocalStorage = (U64*) pq->pStorage; // kernel VA
if (change_addr)
pLocalStorage = (U64*)change_addr(hWls, (U64)pq->pStorage); // user VA
PRINT_DEBUG("pLocalStorage %lx\n", (U64)pLocalStorage);
pLocalStorage[put] = pData;
DSB();
pq->put = new_put;
return TRUE;
}
return FALSE;
}
U64 SFL_WlsDequeue(PFASTQUEUE pq,
wls_us_addr_conv change_addr,
void *hWls)
{
U64 p;
U32 get = pq->get;
if ((pq->put - get) != 0)
{
U64* pLocalStorage = (U64*) pq->pStorage; // kernel VA
DSB();
if (change_addr)
pLocalStorage = (U64 *)change_addr(hWls, (U64)pLocalStorage); //convert to user VA
p = pLocalStorage[get++];
if (get >= pq->size)
get = 0;
pq->get = get;
return p;
}
return 0;
}
/*
int SFL_Enqueue_NoSync(PFASTQUEUE pq, PVOID pData)
{
U32 put = pq->put;
U32 new_put = put + 1;
if (new_put >= pq->size)
new_put = 0;
if (new_put != pq->get)
{ // the queue is not full
pq->pStorage[ put ] = pData;
pq->put = new_put;
return TRUE;
}
return FALSE;
}*/
/*
PVOID SFL_Dequeue_NoSync(PFASTQUEUE pq)
{
PVOID p;
U32 get = pq->get;
if ((pq->put - get) != 0)
{
p = pq->pStorage[get++];
if (get >= pq->size)
get = 0;
pq->get = get;
return p;
}
return NULL;
}*/
void SFL_DefQueue(PFASTQUEUE pq, void *pStorage, int StorageSize)
{
memset( (void*) pq, 0x00, sizeof( FASTQUEUE) );
// always define storage as U64 []
pq->size = StorageSize >> 3;
pq->pStorage = (U64)pStorage;
PRINT_DEBUG("put %d get %d size %d pq->pStorage %lx\n",pq->put, pq->get, pq->size, pq->pStorage);
}
static U32 sfl_SafeQueueLevel(U32 put, U32 get, U32 size)
{
U32 nItems;
if (put >= get)
nItems = put - get;
else
nItems = size + put - get;
return nItems;
}
U32 WLS_GetNumItemsInTheQueue(PWLS_MSG_QUEUE fpq)
{
return sfl_SafeQueueLevel(fpq->put, fpq->get, fpq->size);
}
U32 SFL_GetNumItemsInTheQueue(FASTQUEUE *fpq)
{
return sfl_SafeQueueLevel(fpq->put, fpq->get, fpq->size);
}
/*
U32 SFL_Queue_BatchRead( PFASTQUEUE pq, unsigned long *pDestArr, U32 Count)
{
if (Count)
{
U32 write_index = 0;
U32 nReads = 0;
//U32 iMask = SFL_IDisable();
U32 put = pq->put; // fetch the put atomicly (as app may change it!)
U32 get = pq->get; // cache the volatile "get index"
//printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
if ( (nReads = sfl_SafeQueueLevel(put, get, pq->size)) < Count )
Count = nReads;
else
nReads = Count;
if (Count >= pq->size - get)
{
U32 n = pq->size - get;
SFL_memcpy( pDestArr, &pq->pStorage[get], sizeof(pDestArr[0]) * n);
get = 0;
Count -= n;
write_index += n;
}
if (Count)
{
SFL_memcpy( &pDestArr[write_index], &pq->pStorage[get], sizeof(pDestArr[0]) * Count);
get += Count;
}
DSB();
pq->get = get;
//printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
//SFL_IControl(iMask);
return nReads;
}
return FALSE;
}
// the routine does not keep the fifo order (it is used to take items away from the queue)
U32 SFL_Queue_BatchUnload(PFASTQUEUE pq, unsigned long* pDestArr, U32 Count)
{
if (Count)
{
U32 write_index = 0;
U32 nReads = 0;
//U32 iMask = SFL_IDisable();
U32 put = pq->put; // lets cache the volatile "put index"
U32 get = pq->get; // fetch the get index atomicly (as app may change it)
//printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
nReads = sfl_SafeQueueLevel(put, get, pq->size);
if (nReads)
nReads -= 1; // decrement is used to cover the case when a reader already started reading from head
if ( nReads < Count )
Count = nReads;
else
nReads = Count;
if (!put)
put = pq->size;
if (Count >= put)
{
U32 n = put;
SFL_memcpy( pDestArr, &pq->pStorage[0], sizeof(pDestArr[0]) * n);
put = pq->size;
Count -= n;
write_index += n;
}
if (Count)
{
put -= Count;
SFL_memcpy( &pDestArr[write_index], &pq->pStorage[put], sizeof(pDestArr[0]) * Count);
}
if (put >= pq->size)
put = 0;
DSB();
pq->put = put;
//printf("nItems_%d ", SFL_GetNumItemsInTheQueue(pq));
//SFL_IControl(iMask);
return nReads;
}
return FALSE;
}
U32 SFL_Queue_BatchWrite( PFASTQUEUE pq, unsigned long *pSrcArr, U32 Count)
{
U32 nWrites = Count;
if (Count)
{
U32 read_index = 0;
U32 put = pq->put;
//U32 iMask = SFL_IDisable();
if (pq->size - put <= Count)
{
U32 n = pq->size - put;
SFL_memcpy( &pq->pStorage[put], pSrcArr, sizeof(pSrcArr[0]) * n);
put = 0;
Count -= n;
read_index += n;
}
if (Count)
{
SFL_memcpy( &pq->pStorage[put], &pSrcArr[read_index], sizeof(pSrcArr[0]) * Count);
put += Count;
}
DSB();
pq->put = put;
//SFL_IControl(iMask);
return nWrites;
}
return 0;
}
*/
void WLS_MsgDefineQueue(
PWLS_MSG_QUEUE pq,
PWLS_MSG_HANDLE pStorage,
U32 size,
U32 sema)
{
memset( pq, 0x00, sizeof(WLS_MSG_QUEUE));
pq->pStorage = (U64) pStorage;
pq->get = 0;
pq->put = 0;
pq->size = size; // number of items
pq->sema = sema;
}
U32 WLS_MsgEnqueue(
PWLS_MSG_QUEUE pq,
U64 pIaPaMsg,
U32 MsgSize,
U16 TypeID,
U16 flags,
wls_us_addr_conv change_addr,
void *hWls)
{
U32 rc = 0;
// below is protected section.
U32 put = pq->put;
U32 put_new = put + 1;
if (put_new >= pq->size)
put_new = 0;
if (put_new != pq->get)
{
PWLS_MSG_HANDLE pLocalStorage = (PWLS_MSG_HANDLE)pq->pStorage; // kernel VA
PWLS_MSG_HANDLE pItem;
PRINT_DEBUG("Kernel VA pq->pStorage %lx put [%d] %d %d\n", pq->pStorage, put_new, pq->get, pq->size);
if (change_addr)
pLocalStorage = (PWLS_MSG_HANDLE)change_addr(hWls, (U64)pq->pStorage);
pItem = &pLocalStorage[put];
pItem->pIaPaMsg = pIaPaMsg;
pItem->MsgSize = MsgSize;
pItem->TypeID = TypeID;
pItem->flags = flags;
DSB();
pq->put = put_new;
rc = 1;
}
return rc;
}
int WLS_MsgDequeue(
PWLS_MSG_QUEUE pq,
PWLS_MSG_HANDLE pDestItem,
wls_us_addr_conv change_addr,
void *hWls)
{
int retval = FALSE;
U32 get = pq->get;
PWLS_MSG_HANDLE pLocalStorage;
if (!pDestItem)
return retval;
if (get >= pq->size)
{
PRINT_DEBUG("error WLS_MsgDequeue get %d size %d\n", get, pq->size);
return retval;
}
pLocalStorage = (PWLS_MSG_HANDLE) pq->pStorage; // kernel VA
PRINT_DEBUG("WLS_MsgDequeue with pq->pStorage %lX\n",pq->pStorage);
if (pq->put != get)
{
DSB();
if (change_addr)
pLocalStorage = (PWLS_MSG_HANDLE)change_addr(hWls, (U64) pq->pStorage); //convert to user VA
*pDestItem = pLocalStorage[get];
if (++get == pq->size)
get = 0;
pq->get = get;
retval = TRUE;
}
return retval;
}