diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 0e5219a6513f..bed3b64e8310 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -322,11 +322,10 @@ int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr } EXPORT_SYMBOL_GPL(q6apm_alloc_fragments); -static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id, +static int __q6apm_unmap_memory_fixed_region(struct q6apm *apm, unsigned int graph_id, bool is_pos_buf) { struct apm_cmd_shared_mem_unmap_regions *cmd; - struct q6apm *apm = dev_get_drvdata(dev->parent); struct audioreach_graph_info *info; uint32_t mem_map_handle; uint32_t pos_mask = is_pos_buf ? APM_MMAP_TOKEN_MAP_TYPE_POS_BUF : 0; @@ -358,13 +357,15 @@ static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int gr int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id) { - return __q6apm_unmap_memory_fixed_region(dev, graph_id, false); + return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent), + graph_id, false); } EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region); int q6apm_unmap_pos_buffer(struct device *dev, unsigned int graph_id) { - return __q6apm_unmap_memory_fixed_region(dev, graph_id, true); + return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent), + graph_id, true); } EXPORT_SYMBOL_GPL(q6apm_unmap_pos_buffer); @@ -851,6 +852,21 @@ static int q6apm_audio_probe(struct snd_soc_component *component) static void q6apm_audio_remove(struct snd_soc_component *component) { + struct q6apm *apm = dev_get_drvdata(component->dev); + struct audioreach_graph_info *info; + int id; + + /* + * The card core removes components before freeing the PCMs, so + * q6apm-dai's pcm_free() runs after the topology (and graph_info) + * is gone and can no longer unmap. Release the DSP mappings here, + * otherwise the next pcm_new() fails to map the same buffer again. + */ + idr_for_each_entry(&apm->graph_info_idr, info, id) { + __q6apm_unmap_memory_fixed_region(apm, id, false); + __q6apm_unmap_memory_fixed_region(apm, id, true); + } + /* remove topology */ snd_soc_tplg_component_remove(component); }