Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: core: Remove only the registered component in devm functions

The ASoC devm_ functions that register a component
(devm_snd_soc_register_component and devm_snd_dmaengine_pcm_register) will
clean their component by running snd_soc_unregister_component.

snd_soc_unregister_component will then remove all the components for the
device that was used to register the component in the first place.

However, some drivers register several components (such as a DAI and a
dmaengine PCM) on the same device, and if the dmaengine PCM is registered
first, then the DAI will be cleaned up first and
snd_dmaengine_pcm_unregister will be called next.

snd_dmaengine_pcm_unregister will then lookup the dmaengine PCM component
on the device, and if there's one unregister that component and release its
dmaengine channels. That doesn't happen in practice though since the first
call to snd_soc_unregister_component removed all the components, so we
never get the chance to release the dmaengine channels.

In order to fix this, instead of removing all the components for a given
device, we can simply remove the component that was registered in the first
place. We should have the same number of component registration than we
have components, so it should work just fine.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Link: https://lore.kernel.org/r/20200707074237.287171-1-maxime@cerno.tech
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Maxime Ripard and committed by
Mark Brown
58f30150 c0dadd29

+35 -4
+2
include/sound/soc.h
··· 444 444 const struct snd_soc_component_driver *component_driver, 445 445 struct snd_soc_dai_driver *dai_drv, int num_dai); 446 446 void snd_soc_unregister_component(struct device *dev); 447 + void snd_soc_unregister_component_by_driver(struct device *dev, 448 + const struct snd_soc_component_driver *component_driver); 447 449 struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev, 448 450 const char *driver_name); 449 451 struct snd_soc_component *snd_soc_lookup_component(struct device *dev,
+27
sound/soc/soc-core.c
··· 2573 2573 EXPORT_SYMBOL_GPL(snd_soc_register_component); 2574 2574 2575 2575 /** 2576 + * snd_soc_unregister_component_by_driver - Unregister component using a given driver 2577 + * from the ASoC core 2578 + * 2579 + * @dev: The device to unregister 2580 + * @component_driver: The component driver to unregister 2581 + */ 2582 + void snd_soc_unregister_component_by_driver(struct device *dev, 2583 + const struct snd_soc_component_driver *component_driver) 2584 + { 2585 + struct snd_soc_component *component; 2586 + 2587 + if (!component_driver) 2588 + return; 2589 + 2590 + mutex_lock(&client_mutex); 2591 + component = snd_soc_lookup_component_nolocked(dev, component_driver->name); 2592 + if (!component) 2593 + goto out; 2594 + 2595 + snd_soc_del_component_unlocked(component); 2596 + 2597 + out: 2598 + mutex_unlock(&client_mutex); 2599 + } 2600 + EXPORT_SYMBOL_GPL(snd_soc_unregister_component_by_driver); 2601 + 2602 + /** 2576 2603 * snd_soc_unregister_component - Unregister all related component 2577 2604 * from the ASoC core 2578 2605 *
+5 -3
sound/soc/soc-devres.c
··· 48 48 49 49 static void devm_component_release(struct device *dev, void *res) 50 50 { 51 - snd_soc_unregister_component(*(struct device **)res); 51 + const struct snd_soc_component_driver **cmpnt_drv = res; 52 + 53 + snd_soc_unregister_component_by_driver(dev, *cmpnt_drv); 52 54 } 53 55 54 56 /** ··· 67 65 const struct snd_soc_component_driver *cmpnt_drv, 68 66 struct snd_soc_dai_driver *dai_drv, int num_dai) 69 67 { 70 - struct device **ptr; 68 + const struct snd_soc_component_driver **ptr; 71 69 int ret; 72 70 73 71 ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL); ··· 76 74 77 75 ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai); 78 76 if (ret == 0) { 79 - *ptr = dev; 77 + *ptr = cmpnt_drv; 80 78 devres_add(dev, ptr); 81 79 } else { 82 80 devres_free(ptr);
+1 -1
sound/soc/soc-generic-dmaengine-pcm.c
··· 478 478 479 479 pcm = soc_component_to_pcm(component); 480 480 481 - snd_soc_unregister_component(dev); 481 + snd_soc_unregister_component_by_driver(dev, component->driver); 482 482 dmaengine_pcm_release_chan(pcm); 483 483 kfree(pcm); 484 484 }