1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
4 *
5 * @File	ctresource.c
6 *
7 * @Brief
8 * This file contains the implementation of some generic helper functions.
9 *
10 * @Author	Liu Chun
11 * @Date 	May 15 2008
12 */
13
14#include "ctresource.h"
15#include "cthardware.h"
16#include <linux/err.h>
17#include <linux/slab.h>
18
19#define AUDIO_SLOT_BLOCK_NUM 	256
20
21/* Resource allocation based on bit-map management mechanism */
22static int
23get_resource(u8 *rscs, unsigned int amount,
24	     unsigned int multi, unsigned int *ridx)
25{
26	int i, j, k, n;
27
28	/* Check whether there are sufficient resources to meet request. */
29	for (i = 0, n = multi; i < amount; i++) {
30		j = i / 8;
31		k = i % 8;
32		if (rscs[j] & ((u8)1 << k)) {
33			n = multi;
34			continue;
35		}
36		if (!(--n))
37			break; /* found sufficient contiguous resources */
38	}
39
40	if (i >= amount) {
41		/* Can not find sufficient contiguous resources */
42		return -ENOENT;
43	}
44
45	/* Mark the contiguous bits in resource bit-map as used */
46	for (n = multi; n > 0; n--) {
47		j = i / 8;
48		k = i % 8;
49		rscs[j] |= ((u8)1 << k);
50		i--;
51	}
52
53	*ridx = i + 1;
54
55	return 0;
56}
57
58static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
59{
60	unsigned int i, j, k, n;
61
62	/* Mark the contiguous bits in resource bit-map as used */
63	for (n = multi, i = idx; n > 0; n--) {
64		j = i / 8;
65		k = i % 8;
66		rscs[j] &= ~((u8)1 << k);
67		i++;
68	}
69
70	return 0;
71}
72
73int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
74{
75	int err;
76
77	if (n > mgr->avail)
78		return -ENOENT;
79
80	err = get_resource(mgr->rscs, mgr->amount, n, ridx);
81	if (!err)
82		mgr->avail -= n;
83
84	return err;
85}
86
87int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
88{
89	put_resource(mgr->rscs, n, idx);
90	mgr->avail += n;
91
92	return 0;
93}
94
95static const unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
96	/* SRC channel is at Audio Ring slot 1 every 16 slots. */
97	[SRC]		= 0x1,
98	[AMIXER]	= 0x4,
99	[SUM]		= 0xc,
100};
101
102static int rsc_index(const struct rsc *rsc)
103{
104    return rsc->conj;
105}
106
107static int audio_ring_slot(const struct rsc *rsc)
108{
109    return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
110}
111
112static void rsc_next_conj(struct rsc *rsc)
113{
114	unsigned int i;
115	for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
116		i++;
117	rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
118}
119
120static void rsc_master(struct rsc *rsc)
121{
122	rsc->conj = rsc->idx;
123}
124
125static const struct rsc_ops rsc_generic_ops = {
126	.index		= rsc_index,
127	.output_slot	= audio_ring_slot,
128	.master		= rsc_master,
129	.next_conj	= rsc_next_conj,
130};
131
132int
133rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw)
134{
135	int err = 0;
136
137	rsc->idx = idx;
138	rsc->conj = idx;
139	rsc->type = type;
140	rsc->msr = msr;
141	rsc->hw = hw;
142	rsc->ops = &rsc_generic_ops;
143	if (!hw) {
144		rsc->ctrl_blk = NULL;
145		return 0;
146	}
147
148	switch (type) {
149	case SRC:
150		err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
151		break;
152	case AMIXER:
153		err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
154		break;
155	case SRCIMP:
156	case SUM:
157	case DAIO:
158		break;
159	default:
160		dev_err(((struct hw *)hw)->card->dev,
161			"Invalid resource type value %d!\n", type);
162		return -EINVAL;
163	}
164
165	if (err) {
166		dev_err(((struct hw *)hw)->card->dev,
167			"Failed to get resource control block!\n");
168		return err;
169	}
170
171	return 0;
172}
173
174int rsc_uninit(struct rsc *rsc)
175{
176	if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
177		switch (rsc->type) {
178		case SRC:
179			rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk);
180			break;
181		case AMIXER:
182			rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
183			break;
184		case SUM:
185		case DAIO:
186			break;
187		default:
188			dev_err(((struct hw *)rsc->hw)->card->dev,
189				"Invalid resource type value %d!\n",
190				rsc->type);
191			break;
192		}
193
194		rsc->hw = rsc->ctrl_blk = NULL;
195	}
196
197	rsc->idx = rsc->conj = 0;
198	rsc->type = NUM_RSCTYP;
199	rsc->msr = 0;
200
201	return 0;
202}
203
204int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
205		 unsigned int amount, struct hw *hw)
206{
207	int err = 0;
208
209	mgr->type = NUM_RSCTYP;
210
211	mgr->rscs = kzalloc(DIV_ROUND_UP(amount, 8), GFP_KERNEL);
212	if (!mgr->rscs)
213		return -ENOMEM;
214
215	switch (type) {
216	case SRC:
217		err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
218		break;
219	case SRCIMP:
220		err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
221		break;
222	case AMIXER:
223		err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
224		break;
225	case DAIO:
226		err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
227		break;
228	case SUM:
229		break;
230	default:
231		dev_err(hw->card->dev,
232			"Invalid resource type value %d!\n", type);
233		err = -EINVAL;
234		goto error;
235	}
236
237	if (err) {
238		dev_err(hw->card->dev,
239			"Failed to get manager control block!\n");
240		goto error;
241	}
242
243	mgr->type = type;
244	mgr->avail = mgr->amount = amount;
245	mgr->hw = hw;
246
247	return 0;
248
249error:
250	kfree(mgr->rscs);
251	return err;
252}
253
254int rsc_mgr_uninit(struct rsc_mgr *mgr)
255{
256	kfree(mgr->rscs);
257	mgr->rscs = NULL;
258
259	if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
260		switch (mgr->type) {
261		case SRC:
262			mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk);
263			break;
264		case SRCIMP:
265			mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
266			break;
267		case AMIXER:
268			mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
269			break;
270		case DAIO:
271			mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
272			break;
273		case SUM:
274			break;
275		default:
276			dev_err(((struct hw *)mgr->hw)->card->dev,
277				"Invalid resource type value %d!\n",
278				mgr->type);
279			break;
280		}
281
282		mgr->hw = mgr->ctrl_blk = NULL;
283	}
284
285	mgr->type = NUM_RSCTYP;
286	mgr->avail = mgr->amount = 0;
287
288	return 0;
289}
290