summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl_dsp_pool.c
blob: 637454d9723142b4c102b721645d5037b6d23599 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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);
}