xref: /openbmc/linux/sound/pci/ctxfi/ctresource.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
15765e78eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a08b9f2fSAditya Srivastava /*
38cc72361SWai Yew CHAY  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
48cc72361SWai Yew CHAY  *
58cc72361SWai Yew CHAY  * @File	ctresource.c
68cc72361SWai Yew CHAY  *
78cc72361SWai Yew CHAY  * @Brief
88cc72361SWai Yew CHAY  * This file contains the implementation of some generic helper functions.
98cc72361SWai Yew CHAY  *
108cc72361SWai Yew CHAY  * @Author	Liu Chun
118cc72361SWai Yew CHAY  * @Date 	May 15 2008
128cc72361SWai Yew CHAY  */
138cc72361SWai Yew CHAY 
148cc72361SWai Yew CHAY #include "ctresource.h"
158cc72361SWai Yew CHAY #include "cthardware.h"
168cc72361SWai Yew CHAY #include <linux/err.h>
178cc72361SWai Yew CHAY #include <linux/slab.h>
188cc72361SWai Yew CHAY 
198cc72361SWai Yew CHAY #define AUDIO_SLOT_BLOCK_NUM 	256
208cc72361SWai Yew CHAY 
218cc72361SWai Yew CHAY /* Resource allocation based on bit-map management mechanism */
228cc72361SWai Yew CHAY static int
get_resource(u8 * rscs,unsigned int amount,unsigned int multi,unsigned int * ridx)238cc72361SWai Yew CHAY get_resource(u8 *rscs, unsigned int amount,
248cc72361SWai Yew CHAY 	     unsigned int multi, unsigned int *ridx)
258cc72361SWai Yew CHAY {
26514eef9cSTakashi Iwai 	int i, j, k, n;
278cc72361SWai Yew CHAY 
288cc72361SWai Yew CHAY 	/* Check whether there are sufficient resources to meet request. */
298cc72361SWai Yew CHAY 	for (i = 0, n = multi; i < amount; i++) {
308cc72361SWai Yew CHAY 		j = i / 8;
318cc72361SWai Yew CHAY 		k = i % 8;
328cc72361SWai Yew CHAY 		if (rscs[j] & ((u8)1 << k)) {
338cc72361SWai Yew CHAY 			n = multi;
348cc72361SWai Yew CHAY 			continue;
358cc72361SWai Yew CHAY 		}
368cc72361SWai Yew CHAY 		if (!(--n))
378cc72361SWai Yew CHAY 			break; /* found sufficient contiguous resources */
388cc72361SWai Yew CHAY 	}
398cc72361SWai Yew CHAY 
408cc72361SWai Yew CHAY 	if (i >= amount) {
418cc72361SWai Yew CHAY 		/* Can not find sufficient contiguous resources */
428cc72361SWai Yew CHAY 		return -ENOENT;
438cc72361SWai Yew CHAY 	}
448cc72361SWai Yew CHAY 
458cc72361SWai Yew CHAY 	/* Mark the contiguous bits in resource bit-map as used */
468cc72361SWai Yew CHAY 	for (n = multi; n > 0; n--) {
478cc72361SWai Yew CHAY 		j = i / 8;
488cc72361SWai Yew CHAY 		k = i % 8;
498cc72361SWai Yew CHAY 		rscs[j] |= ((u8)1 << k);
508cc72361SWai Yew CHAY 		i--;
518cc72361SWai Yew CHAY 	}
528cc72361SWai Yew CHAY 
538cc72361SWai Yew CHAY 	*ridx = i + 1;
548cc72361SWai Yew CHAY 
558cc72361SWai Yew CHAY 	return 0;
568cc72361SWai Yew CHAY }
578cc72361SWai Yew CHAY 
put_resource(u8 * rscs,unsigned int multi,unsigned int idx)588cc72361SWai Yew CHAY static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)
598cc72361SWai Yew CHAY {
60514eef9cSTakashi Iwai 	unsigned int i, j, k, n;
618cc72361SWai Yew CHAY 
628cc72361SWai Yew CHAY 	/* Mark the contiguous bits in resource bit-map as used */
638cc72361SWai Yew CHAY 	for (n = multi, i = idx; n > 0; n--) {
648cc72361SWai Yew CHAY 		j = i / 8;
658cc72361SWai Yew CHAY 		k = i % 8;
668cc72361SWai Yew CHAY 		rscs[j] &= ~((u8)1 << k);
678cc72361SWai Yew CHAY 		i++;
688cc72361SWai Yew CHAY 	}
698cc72361SWai Yew CHAY 
708cc72361SWai Yew CHAY 	return 0;
718cc72361SWai Yew CHAY }
728cc72361SWai Yew CHAY 
mgr_get_resource(struct rsc_mgr * mgr,unsigned int n,unsigned int * ridx)738cc72361SWai Yew CHAY int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)
748cc72361SWai Yew CHAY {
75514eef9cSTakashi Iwai 	int err;
768cc72361SWai Yew CHAY 
778cc72361SWai Yew CHAY 	if (n > mgr->avail)
788cc72361SWai Yew CHAY 		return -ENOENT;
798cc72361SWai Yew CHAY 
808cc72361SWai Yew CHAY 	err = get_resource(mgr->rscs, mgr->amount, n, ridx);
818cc72361SWai Yew CHAY 	if (!err)
828cc72361SWai Yew CHAY 		mgr->avail -= n;
838cc72361SWai Yew CHAY 
848cc72361SWai Yew CHAY 	return err;
858cc72361SWai Yew CHAY }
868cc72361SWai Yew CHAY 
mgr_put_resource(struct rsc_mgr * mgr,unsigned int n,unsigned int idx)878cc72361SWai Yew CHAY int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)
888cc72361SWai Yew CHAY {
898cc72361SWai Yew CHAY 	put_resource(mgr->rscs, n, idx);
908cc72361SWai Yew CHAY 	mgr->avail += n;
918cc72361SWai Yew CHAY 
928cc72361SWai Yew CHAY 	return 0;
938cc72361SWai Yew CHAY }
948cc72361SWai Yew CHAY 
956e0e75d9STakashi Iwai static const unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {
968cc72361SWai Yew CHAY 	/* SRC channel is at Audio Ring slot 1 every 16 slots. */
978cc72361SWai Yew CHAY 	[SRC]		= 0x1,
988cc72361SWai Yew CHAY 	[AMIXER]	= 0x4,
998cc72361SWai Yew CHAY 	[SUM]		= 0xc,
1008cc72361SWai Yew CHAY };
1018cc72361SWai Yew CHAY 
rsc_index(const struct rsc * rsc)1028cc72361SWai Yew CHAY static int rsc_index(const struct rsc *rsc)
1038cc72361SWai Yew CHAY {
1048cc72361SWai Yew CHAY     return rsc->conj;
1058cc72361SWai Yew CHAY }
1068cc72361SWai Yew CHAY 
audio_ring_slot(const struct rsc * rsc)1078cc72361SWai Yew CHAY static int audio_ring_slot(const struct rsc *rsc)
1088cc72361SWai Yew CHAY {
1098cc72361SWai Yew CHAY     return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
1108cc72361SWai Yew CHAY }
1118cc72361SWai Yew CHAY 
rsc_next_conj(struct rsc * rsc)112*76c47183STakashi Iwai static void rsc_next_conj(struct rsc *rsc)
1138cc72361SWai Yew CHAY {
1148cc72361SWai Yew CHAY 	unsigned int i;
1158cc72361SWai Yew CHAY 	for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
1168cc72361SWai Yew CHAY 		i++;
1178cc72361SWai Yew CHAY 	rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
1188cc72361SWai Yew CHAY }
1198cc72361SWai Yew CHAY 
rsc_master(struct rsc * rsc)120*76c47183STakashi Iwai static void rsc_master(struct rsc *rsc)
1218cc72361SWai Yew CHAY {
122*76c47183STakashi Iwai 	rsc->conj = rsc->idx;
1238cc72361SWai Yew CHAY }
1248cc72361SWai Yew CHAY 
12543f2cdebSJulia Lawall static const struct rsc_ops rsc_generic_ops = {
1268cc72361SWai Yew CHAY 	.index		= rsc_index,
1278cc72361SWai Yew CHAY 	.output_slot	= audio_ring_slot,
1288cc72361SWai Yew CHAY 	.master		= rsc_master,
1298cc72361SWai Yew CHAY 	.next_conj	= rsc_next_conj,
1308cc72361SWai Yew CHAY };
1318cc72361SWai Yew CHAY 
13266640898SSudip Mukherjee int
rsc_init(struct rsc * rsc,u32 idx,enum RSCTYP type,u32 msr,struct hw * hw)13366640898SSudip Mukherjee rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw)
1348cc72361SWai Yew CHAY {
1358cc72361SWai Yew CHAY 	int err = 0;
1368cc72361SWai Yew CHAY 
1378cc72361SWai Yew CHAY 	rsc->idx = idx;
1388cc72361SWai Yew CHAY 	rsc->conj = idx;
1398cc72361SWai Yew CHAY 	rsc->type = type;
1408cc72361SWai Yew CHAY 	rsc->msr = msr;
1418cc72361SWai Yew CHAY 	rsc->hw = hw;
1428cc72361SWai Yew CHAY 	rsc->ops = &rsc_generic_ops;
14335ebf6e7STakashi Iwai 	if (!hw) {
1448cc72361SWai Yew CHAY 		rsc->ctrl_blk = NULL;
1458cc72361SWai Yew CHAY 		return 0;
1468cc72361SWai Yew CHAY 	}
1478cc72361SWai Yew CHAY 
1488cc72361SWai Yew CHAY 	switch (type) {
1498cc72361SWai Yew CHAY 	case SRC:
150b6bfe86fSSudip Mukherjee 		err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);
1518cc72361SWai Yew CHAY 		break;
1528cc72361SWai Yew CHAY 	case AMIXER:
153b6bfe86fSSudip Mukherjee 		err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);
1548cc72361SWai Yew CHAY 		break;
1558cc72361SWai Yew CHAY 	case SRCIMP:
1568cc72361SWai Yew CHAY 	case SUM:
1578cc72361SWai Yew CHAY 	case DAIO:
1588cc72361SWai Yew CHAY 		break;
1598cc72361SWai Yew CHAY 	default:
1600cae90a9SSudip Mukherjee 		dev_err(((struct hw *)hw)->card->dev,
1610cae90a9SSudip Mukherjee 			"Invalid resource type value %d!\n", type);
1628cc72361SWai Yew CHAY 		return -EINVAL;
1638cc72361SWai Yew CHAY 	}
1648cc72361SWai Yew CHAY 
1658cc72361SWai Yew CHAY 	if (err) {
1660cae90a9SSudip Mukherjee 		dev_err(((struct hw *)hw)->card->dev,
1670cae90a9SSudip Mukherjee 			"Failed to get resource control block!\n");
1688cc72361SWai Yew CHAY 		return err;
1698cc72361SWai Yew CHAY 	}
1708cc72361SWai Yew CHAY 
1718cc72361SWai Yew CHAY 	return 0;
1728cc72361SWai Yew CHAY }
1738cc72361SWai Yew CHAY 
rsc_uninit(struct rsc * rsc)1748cc72361SWai Yew CHAY int rsc_uninit(struct rsc *rsc)
1758cc72361SWai Yew CHAY {
1768cc72361SWai Yew CHAY 	if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {
1778cc72361SWai Yew CHAY 		switch (rsc->type) {
1788cc72361SWai Yew CHAY 		case SRC:
179b6bfe86fSSudip Mukherjee 			rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk);
1808cc72361SWai Yew CHAY 			break;
1818cc72361SWai Yew CHAY 		case AMIXER:
182b6bfe86fSSudip Mukherjee 			rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);
1838cc72361SWai Yew CHAY 			break;
1848cc72361SWai Yew CHAY 		case SUM:
1858cc72361SWai Yew CHAY 		case DAIO:
1868cc72361SWai Yew CHAY 			break;
1878cc72361SWai Yew CHAY 		default:
1880cae90a9SSudip Mukherjee 			dev_err(((struct hw *)rsc->hw)->card->dev,
1890cae90a9SSudip Mukherjee 				"Invalid resource type value %d!\n",
19062afa853SSudip Mukherjee 				rsc->type);
1918cc72361SWai Yew CHAY 			break;
1928cc72361SWai Yew CHAY 		}
1938cc72361SWai Yew CHAY 
1948cc72361SWai Yew CHAY 		rsc->hw = rsc->ctrl_blk = NULL;
1958cc72361SWai Yew CHAY 	}
1968cc72361SWai Yew CHAY 
1978cc72361SWai Yew CHAY 	rsc->idx = rsc->conj = 0;
1988cc72361SWai Yew CHAY 	rsc->type = NUM_RSCTYP;
1998cc72361SWai Yew CHAY 	rsc->msr = 0;
2008cc72361SWai Yew CHAY 
2018cc72361SWai Yew CHAY 	return 0;
2028cc72361SWai Yew CHAY }
2038cc72361SWai Yew CHAY 
rsc_mgr_init(struct rsc_mgr * mgr,enum RSCTYP type,unsigned int amount,struct hw * hw)2048cc72361SWai Yew CHAY int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,
205b6bfe86fSSudip Mukherjee 		 unsigned int amount, struct hw *hw)
2068cc72361SWai Yew CHAY {
2078cc72361SWai Yew CHAY 	int err = 0;
2088cc72361SWai Yew CHAY 
2098cc72361SWai Yew CHAY 	mgr->type = NUM_RSCTYP;
2108cc72361SWai Yew CHAY 
2117ca4282aSLars-Peter Clausen 	mgr->rscs = kzalloc(DIV_ROUND_UP(amount, 8), GFP_KERNEL);
21235ebf6e7STakashi Iwai 	if (!mgr->rscs)
2138cc72361SWai Yew CHAY 		return -ENOMEM;
2148cc72361SWai Yew CHAY 
2158cc72361SWai Yew CHAY 	switch (type) {
2168cc72361SWai Yew CHAY 	case SRC:
2178cc72361SWai Yew CHAY 		err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);
2188cc72361SWai Yew CHAY 		break;
2198cc72361SWai Yew CHAY 	case SRCIMP:
2208cc72361SWai Yew CHAY 		err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);
2218cc72361SWai Yew CHAY 		break;
2228cc72361SWai Yew CHAY 	case AMIXER:
2238cc72361SWai Yew CHAY 		err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);
2248cc72361SWai Yew CHAY 		break;
2258cc72361SWai Yew CHAY 	case DAIO:
2268cc72361SWai Yew CHAY 		err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);
2278cc72361SWai Yew CHAY 		break;
2288cc72361SWai Yew CHAY 	case SUM:
2298cc72361SWai Yew CHAY 		break;
2308cc72361SWai Yew CHAY 	default:
2310cae90a9SSudip Mukherjee 		dev_err(hw->card->dev,
2320cae90a9SSudip Mukherjee 			"Invalid resource type value %d!\n", type);
2338cc72361SWai Yew CHAY 		err = -EINVAL;
2348cc72361SWai Yew CHAY 		goto error;
2358cc72361SWai Yew CHAY 	}
2368cc72361SWai Yew CHAY 
2378cc72361SWai Yew CHAY 	if (err) {
2380cae90a9SSudip Mukherjee 		dev_err(hw->card->dev,
2390cae90a9SSudip Mukherjee 			"Failed to get manager control block!\n");
2408cc72361SWai Yew CHAY 		goto error;
2418cc72361SWai Yew CHAY 	}
2428cc72361SWai Yew CHAY 
2438cc72361SWai Yew CHAY 	mgr->type = type;
2448cc72361SWai Yew CHAY 	mgr->avail = mgr->amount = amount;
2458cc72361SWai Yew CHAY 	mgr->hw = hw;
2468cc72361SWai Yew CHAY 
2478cc72361SWai Yew CHAY 	return 0;
2488cc72361SWai Yew CHAY 
2498cc72361SWai Yew CHAY error:
2508cc72361SWai Yew CHAY 	kfree(mgr->rscs);
2518cc72361SWai Yew CHAY 	return err;
2528cc72361SWai Yew CHAY }
2538cc72361SWai Yew CHAY 
rsc_mgr_uninit(struct rsc_mgr * mgr)2548cc72361SWai Yew CHAY int rsc_mgr_uninit(struct rsc_mgr *mgr)
2558cc72361SWai Yew CHAY {
2568cc72361SWai Yew CHAY 	kfree(mgr->rscs);
2578cc72361SWai Yew CHAY 	mgr->rscs = NULL;
2588cc72361SWai Yew CHAY 
2598cc72361SWai Yew CHAY 	if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {
2608cc72361SWai Yew CHAY 		switch (mgr->type) {
2618cc72361SWai Yew CHAY 		case SRC:
262b6bfe86fSSudip Mukherjee 			mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk);
2638cc72361SWai Yew CHAY 			break;
2648cc72361SWai Yew CHAY 		case SRCIMP:
265b6bfe86fSSudip Mukherjee 			mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);
2668cc72361SWai Yew CHAY 			break;
2678cc72361SWai Yew CHAY 		case AMIXER:
268b6bfe86fSSudip Mukherjee 			mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);
2698cc72361SWai Yew CHAY 			break;
2708cc72361SWai Yew CHAY 		case DAIO:
271b6bfe86fSSudip Mukherjee 			mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk);
2728cc72361SWai Yew CHAY 			break;
2738cc72361SWai Yew CHAY 		case SUM:
2748cc72361SWai Yew CHAY 			break;
2758cc72361SWai Yew CHAY 		default:
2760cae90a9SSudip Mukherjee 			dev_err(((struct hw *)mgr->hw)->card->dev,
2770cae90a9SSudip Mukherjee 				"Invalid resource type value %d!\n",
27862afa853SSudip Mukherjee 				mgr->type);
2798cc72361SWai Yew CHAY 			break;
2808cc72361SWai Yew CHAY 		}
2818cc72361SWai Yew CHAY 
2828cc72361SWai Yew CHAY 		mgr->hw = mgr->ctrl_blk = NULL;
2838cc72361SWai Yew CHAY 	}
2848cc72361SWai Yew CHAY 
2858cc72361SWai Yew CHAY 	mgr->type = NUM_RSCTYP;
2868cc72361SWai Yew CHAY 	mgr->avail = mgr->amount = 0;
2878cc72361SWai Yew CHAY 
2888cc72361SWai Yew CHAY 	return 0;
2898cc72361SWai Yew CHAY }
290