ASoC: Intel: avs: Dynamic firmware resources management
Wrap elementary DSP-core operations and resource control into more complex handlers. This is done to reduce the number of invocations of wrapped operations throughout the driver as order of operations matters - most flows involve register manipulation and IPCs combined. Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://lore.kernel.org/r/20220311153544.136854-14-cezary.rojewski@intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
committed by
Mark Brown
parent
580a5912d1
commit
215e67b2d2
@@ -89,6 +89,7 @@ struct avs_dev {
|
|||||||
struct mutex modres_mutex;
|
struct mutex modres_mutex;
|
||||||
struct ida ppl_ida;
|
struct ida ppl_ida;
|
||||||
struct list_head fw_list;
|
struct list_head fw_list;
|
||||||
|
int *core_refs; /* reference count per core */
|
||||||
|
|
||||||
struct completion fw_ready;
|
struct completion fw_ready;
|
||||||
};
|
};
|
||||||
@@ -205,4 +206,13 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con
|
|||||||
void avs_release_last_firmware(struct avs_dev *adev);
|
void avs_release_last_firmware(struct avs_dev *adev);
|
||||||
void avs_release_firmwares(struct avs_dev *adev);
|
void avs_release_firmwares(struct avs_dev *adev);
|
||||||
|
|
||||||
|
int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
|
||||||
|
u8 core_id, u8 domain, void *param, u32 param_size,
|
||||||
|
u16 *instance_id);
|
||||||
|
void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
|
||||||
|
u8 ppl_instance_id, u8 core_id);
|
||||||
|
int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
|
||||||
|
bool lp, u16 attributes, u8 *instance_id);
|
||||||
|
int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id);
|
||||||
|
|
||||||
#endif /* __SOUND_SOC_INTEL_AVS_H */
|
#endif /* __SOUND_SOC_INTEL_AVS_H */
|
||||||
|
|||||||
@@ -104,4 +104,173 @@ int avs_dsp_core_disable(struct avs_dev *adev, u32 core_mask)
|
|||||||
return avs_dsp_op(adev, power, core_mask, false);
|
return avs_dsp_op(adev, power, core_mask, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int avs_dsp_enable(struct avs_dev *adev, u32 core_mask)
|
||||||
|
{
|
||||||
|
u32 mask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = avs_dsp_core_enable(adev, core_mask);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mask = core_mask & ~AVS_MAIN_CORE_MASK;
|
||||||
|
if (!mask)
|
||||||
|
/*
|
||||||
|
* without main core, fw is dead anyway
|
||||||
|
* so setting D0 for it is futile.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = avs_ipc_set_dx(adev, mask, true);
|
||||||
|
return AVS_IPC_RET(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avs_dsp_disable(struct avs_dev *adev, u32 core_mask)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = avs_ipc_set_dx(adev, core_mask, false);
|
||||||
|
if (ret)
|
||||||
|
return AVS_IPC_RET(ret);
|
||||||
|
|
||||||
|
return avs_dsp_core_disable(adev, core_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avs_dsp_get_core(struct avs_dev *adev, u32 core_id)
|
||||||
|
{
|
||||||
|
u32 mask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mask = BIT_MASK(core_id);
|
||||||
|
if (mask == AVS_MAIN_CORE_MASK)
|
||||||
|
/* nothing to do for main core */
|
||||||
|
return 0;
|
||||||
|
if (core_id >= adev->hw_cfg.dsp_cores) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
adev->core_refs[core_id]++;
|
||||||
|
if (adev->core_refs[core_id] == 1) {
|
||||||
|
ret = avs_dsp_enable(adev, mask);
|
||||||
|
if (ret)
|
||||||
|
goto err_enable_dsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_enable_dsp:
|
||||||
|
adev->core_refs[core_id]--;
|
||||||
|
err:
|
||||||
|
dev_err(adev->dev, "get core %d failed: %d\n", core_id, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avs_dsp_put_core(struct avs_dev *adev, u32 core_id)
|
||||||
|
{
|
||||||
|
u32 mask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mask = BIT_MASK(core_id);
|
||||||
|
if (mask == AVS_MAIN_CORE_MASK)
|
||||||
|
/* nothing to do for main core */
|
||||||
|
return 0;
|
||||||
|
if (core_id >= adev->hw_cfg.dsp_cores) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
adev->core_refs[core_id]--;
|
||||||
|
if (!adev->core_refs[core_id]) {
|
||||||
|
ret = avs_dsp_disable(adev, mask);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
dev_err(adev->dev, "put core %d failed: %d\n", core_id, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
|
||||||
|
u8 core_id, u8 domain, void *param, u32 param_size,
|
||||||
|
u16 *instance_id)
|
||||||
|
{
|
||||||
|
struct avs_module_entry mentry;
|
||||||
|
int ret, id;
|
||||||
|
|
||||||
|
id = avs_module_id_alloc(adev, module_id);
|
||||||
|
if (id < 0)
|
||||||
|
return id;
|
||||||
|
|
||||||
|
ret = avs_get_module_id_entry(adev, module_id, &mentry);
|
||||||
|
if (ret)
|
||||||
|
goto err_mod_entry;
|
||||||
|
|
||||||
|
ret = avs_dsp_get_core(adev, core_id);
|
||||||
|
if (ret)
|
||||||
|
goto err_mod_entry;
|
||||||
|
|
||||||
|
ret = avs_ipc_init_instance(adev, module_id, id, ppl_instance_id,
|
||||||
|
core_id, domain, param, param_size);
|
||||||
|
if (ret) {
|
||||||
|
ret = AVS_IPC_RET(ret);
|
||||||
|
goto err_ipc;
|
||||||
|
}
|
||||||
|
|
||||||
|
*instance_id = id;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_ipc:
|
||||||
|
avs_dsp_put_core(adev, core_id);
|
||||||
|
err_mod_entry:
|
||||||
|
avs_module_id_free(adev, module_id, id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
|
||||||
|
u8 ppl_instance_id, u8 core_id)
|
||||||
|
{
|
||||||
|
/* Modules not owned by any pipeline need to be freed explicitly. */
|
||||||
|
if (ppl_instance_id == INVALID_PIPELINE_ID)
|
||||||
|
avs_ipc_delete_instance(adev, module_id, instance_id);
|
||||||
|
|
||||||
|
avs_module_id_free(adev, module_id, instance_id);
|
||||||
|
|
||||||
|
avs_dsp_put_core(adev, core_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
|
||||||
|
bool lp, u16 attributes, u8 *instance_id)
|
||||||
|
{
|
||||||
|
struct avs_fw_cfg *fw_cfg = &adev->fw_cfg;
|
||||||
|
int ret, id;
|
||||||
|
|
||||||
|
id = ida_alloc_max(&adev->ppl_ida, fw_cfg->max_ppl_count - 1, GFP_KERNEL);
|
||||||
|
if (id < 0)
|
||||||
|
return id;
|
||||||
|
|
||||||
|
ret = avs_ipc_create_pipeline(adev, req_size, priority, id, lp, attributes);
|
||||||
|
if (ret) {
|
||||||
|
ida_free(&adev->ppl_ida, id);
|
||||||
|
return AVS_IPC_RET(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
*instance_id = id;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avs_dsp_delete_pipeline(struct avs_dev *adev, u8 instance_id)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = avs_ipc_delete_pipeline(adev, instance_id);
|
||||||
|
if (ret)
|
||||||
|
ret = AVS_IPC_RET(ret);
|
||||||
|
|
||||||
|
ida_free(&adev->ppl_ida, instance_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|||||||
Reference in New Issue
Block a user