// SPDX-License-Identifier: GPL-2.0+ // // Xtensa buffer pool API // // Copyright 2018 NXP // Copyright (c) 2012-2013 by Tensilica Inc. #include #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); }