151 lines
3.6 KiB
C
151 lines
3.6 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
//
|
|
// Xtensa buffer pool API
|
|
//
|
|
// Copyright 2018 NXP
|
|
// Copyright (c) 2012-2013 by Tensilica Inc.
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include "fsl_dsp_pool.h"
|
|
#include "fsl_dsp.h"
|
|
|
|
/* ...allocate buffer pool */
|
|
int xf_pool_alloc(struct xf_client *client, struct xf_proxy *proxy,
|
|
u32 number, u32 length, xf_pool_type_t type,
|
|
struct xf_pool **pool)
|
|
{
|
|
struct xf_pool *p;
|
|
struct xf_buffer *b;
|
|
void *data;
|
|
struct xf_message msg;
|
|
struct xf_message *rmsg;
|
|
|
|
/* ...basic sanity checks; number of buffers is positive */
|
|
if (number <=0)
|
|
return -EINVAL;
|
|
|
|
/* ...get properly aligned buffer length */
|
|
length = ALIGN(length, XF_PROXY_ALIGNMENT);
|
|
|
|
p = kzalloc(offsetof(struct xf_pool, buffer) +
|
|
number * sizeof(struct xf_buffer), GFP_KERNEL);
|
|
if(!p)
|
|
return -ENOMEM;
|
|
|
|
/* ...prepare command parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0));
|
|
msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id);
|
|
msg.opcode = XF_ALLOC;
|
|
msg.length = length * number;
|
|
msg.buffer = NULL;
|
|
msg.ret = 0;
|
|
|
|
/* ...execute command synchronously */
|
|
rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode,
|
|
msg.buffer, msg.length, &client->work,
|
|
&client->compr_complete);
|
|
if (IS_ERR(rmsg)) {
|
|
kfree(p);
|
|
return PTR_ERR(rmsg);
|
|
}
|
|
|
|
p->p = rmsg->buffer;
|
|
/* TODO: review cleanup */
|
|
/* xf_msg_free(proxy, rmsg);
|
|
* xf_unlock(&proxy->lock); */
|
|
|
|
/* ...if operation is failed, do cleanup */
|
|
/* ...set pool parameters */
|
|
p->number = number, p->length = length;
|
|
p->proxy = proxy;
|
|
|
|
/* ...create individual buffers and link them into free list */
|
|
for (p->free = b = &p->buffer[0], data = p->p; number > 0;
|
|
number--, b++) {
|
|
/* ...set address of the buffer (no length there) */
|
|
b->address = data;
|
|
|
|
/* ...file buffer into the free list */
|
|
b->link.next = b + 1;
|
|
|
|
/* ...advance data pointer in contiguous buffer */
|
|
data += length;
|
|
}
|
|
|
|
/* ...terminate list of buffers (not too good - tbd) */
|
|
b[-1].link.next = NULL;
|
|
|
|
/* ...return buffer pointer */
|
|
*pool = p;
|
|
|
|
return 0;
|
|
}
|
|
/* ...buffer pool destruction */
|
|
int xf_pool_free(struct xf_client *client, struct xf_pool *pool)
|
|
{
|
|
struct xf_proxy *proxy;
|
|
struct xf_message msg;
|
|
struct xf_message *rmsg;
|
|
|
|
/* ...basic sanity checks; pool is positive */
|
|
if (pool == NULL)
|
|
return -EINVAL;
|
|
|
|
/* ...get proxy pointer */
|
|
if ((proxy = pool->proxy) == NULL)
|
|
return -EINVAL;
|
|
|
|
/* ...prepare command parameters */
|
|
msg.id = __XF_MSG_ID(__XF_AP_PROXY(0), __XF_DSP_PROXY(0));
|
|
msg.id = XF_MSG_AP_FROM_USER(msg.id, client->id);
|
|
msg.opcode = XF_FREE;
|
|
msg.length = pool->length * pool->number;
|
|
msg.buffer = pool->p;
|
|
msg.ret = 0;
|
|
|
|
/* ...execute command synchronously */
|
|
rmsg = xf_cmd_send_recv_complete(client, proxy, msg.id, msg.opcode,
|
|
msg.buffer, msg.length, &client->work,
|
|
&client->compr_complete);
|
|
kfree(pool);
|
|
if (IS_ERR(rmsg))
|
|
return PTR_ERR(rmsg);
|
|
|
|
/* TODO: review cleanup */
|
|
/* xf_msg_free(proxy, rmsg);
|
|
* xf_unlock(&proxy->lock); */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ...get new buffer from a pool */
|
|
struct xf_buffer *xf_buffer_get(struct xf_pool *pool)
|
|
{
|
|
struct xf_buffer *b;
|
|
|
|
xf_lock(&pool->proxy->lock);
|
|
/* ...take buffer from a head of the free list */
|
|
b = pool->free;
|
|
if (b) {
|
|
/* ...advance free list head */
|
|
pool->free = b->link.next, b->link.pool = pool;
|
|
}
|
|
|
|
xf_unlock(&pool->proxy->lock);
|
|
return b;
|
|
}
|
|
|
|
/* ...return buffer back to pool */
|
|
void xf_buffer_put(struct xf_buffer *buffer)
|
|
{
|
|
struct xf_pool *pool = buffer->link.pool;
|
|
|
|
xf_lock(&pool->proxy->lock);
|
|
/* ...use global proxy lock for pool operations protection */
|
|
/* ...put buffer back to a pool */
|
|
buffer->link.next = pool->free, pool->free = buffer;
|
|
|
|
xf_unlock(&pool->proxy->lock);
|
|
}
|