[SRU][R][PATCH v5 8/8] ASoC: SDCA: Move kcontrol search out of IRQ

Andrei Gherzan andrei.gherzan at canonical.com
Fri Sep 11 12:07:19 UTC 2026


On 26/09/11 04:44PM, Chris Chiu via kernel-team wrote:
> From: Charles Keepax <ckeepax at opensource.cirrus.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/2163215
> 
> Now that the IRQs are always registered after all the ALSA
> controls are created it is possible to search for the control
> at the point the IRQ is requested. Move the control search out
> of the IRQ handler and do it at IRQ request time.
> 
> This also fixes a potential issue when the card was torn down
> and reprobed without destroying the codec device, the kctl
> pointer stored by the IRQ handler would not be updated to the
> new control on the second probe.
> 
> Signed-off-by: Charles Keepax <ckeepax at opensource.cirrus.com>
> Link: https://patch.msgid.link/20260721143636.361814-8-ckeepax@opensource.cirrus.com
> Signed-off-by: Mark Brown <broonie at kernel.org>
> (backported from commit bf1b7821f85383a8804441f8fd5165be148f3ec8)
> [ChrisChiu: Remove duplicated struct members in struct jack_state.
>  Remove dead helper 'type_get_mask' from this series and implement
>  local mapping in sdca_jack_report(). Place sdca_jack_free_state/init
>  before sdca_jack_set_jack and remove unused locals]
> Signed-off-by: Chris Chiu <chris.chiu at canonical.com>
> ---
> v5 change:
>  - Remove dead helper 'type_get_mask' from this series
>  - lace sdca_jack_free_state/init before sdca_jack_set_jack and remove unused locals
> 
>  include/sound/sdca_jack.h        |  3 ++
>  sound/soc/sdca/sdca_interrupts.c | 12 ++++++
>  sound/soc/sdca/sdca_jack.c       | 66 ++++++++++++++++++++------------
>  3 files changed, 56 insertions(+), 25 deletions(-)
> 
> diff --git a/include/sound/sdca_jack.h b/include/sound/sdca_jack.h
> index 8624c51eea26..a55a1bad1904 100644
> --- a/include/sound/sdca_jack.h
> +++ b/include/sound/sdca_jack.h
> @@ -22,9 +22,12 @@ struct snd_soc_jack;
>  struct jack_state {
>  	struct snd_kcontrol *kctl;
>  	struct snd_soc_jack *jack;
> +	/* legacy mask field; wiring of proper masks (cb3c257e0824) is out of scope */
> +	unsigned int mask;
>  };
>  
>  int sdca_jack_alloc_state(struct sdca_interrupt *interrupt);
> +int sdca_jack_init_state(struct sdca_interrupt *interrupt);
>  void sdca_jack_free_state(struct sdca_interrupt *interrupt);
>  
>  int sdca_jack_process(struct sdca_interrupt *interrupt);
> diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c
> index 79a17d827f99..15da7c2aea50 100644
> --- a/sound/soc/sdca/sdca_interrupts.c
> +++ b/sound/soc/sdca/sdca_interrupts.c
> @@ -512,6 +512,8 @@ int sdca_irq_populate(struct sdca_function_data *function,
>  
>  	for (i = 0; i < SDCA_MAX_INTERRUPTS; i++) {
>  		struct sdca_interrupt *interrupt = &info->irqs[i];
> +		struct sdca_control *control = interrupt->control;
> +		struct sdca_entity *entity = interrupt->entity;
>  		int irq;
>  
>  		if (interrupt->function != function || interrupt->irq)
> @@ -519,6 +521,16 @@ int sdca_irq_populate(struct sdca_function_data *function,
>  
>  		interrupt->component = component;
>  
> +		switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
> +		case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
> +			ret = sdca_jack_init_state(interrupt);
> +			if (ret)
> +				return ret;
> +			break;
> +		default:
> +			break;
> +		}
> +
>  		irq = interrupt->control->interrupt_position;
>  		ret = sdca_irq_request_locked(dev, info, irq, interrupt->name,
>  					      interrupt->handler, interrupt);
> diff --git a/sound/soc/sdca/sdca_jack.c b/sound/soc/sdca/sdca_jack.c
> index 2a77e28ba43e..c6b9cb3fcc2f 100644
> --- a/sound/soc/sdca/sdca_jack.c
> +++ b/sound/soc/sdca/sdca_jack.c
> @@ -47,23 +47,6 @@ int sdca_jack_process(struct sdca_interrupt *interrupt)
>  
>  	guard(rwsem_write)(rwsem);
>  
> -	if (!kctl) {
> -		const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s",
> -							   interrupt->entity->label,
> -							   SDCA_CTL_SELECTED_MODE_NAME);
> -
> -		if (!name)
> -			return -ENOMEM;
> -
> -		kctl = snd_soc_component_get_kcontrol(component, name);
> -		if (!kctl) {
> -			dev_err(dev, "control not found: %s\n", name);
> -			return -ENODEV;
> -		}
> -
> -		state->kctl = kctl;
> -	}
> -
>  	reg = SDW_SDCA_CTL(interrupt->function->desc->adr, interrupt->entity->id,
>  			   interrupt->control->sel, 0);
>  
> @@ -143,16 +126,36 @@ EXPORT_SYMBOL_NS_GPL(sdca_jack_alloc_state, "SND_SOC_SDCA");
>   * @interrupt: SDCA interrupt structure.
>   */
>  void sdca_jack_free_state(struct sdca_interrupt *interrupt)

This reverts the implementation of patch 3 back to the uptream's approach. It
introduces a transient defect - between 3 and 8 there is a real leak.

> +{
> +	kfree(interrupt->priv);
> +}
> +EXPORT_SYMBOL_NS_GPL(sdca_jack_free_state, "SND_SOC_SDCA");
> +
> +/**
> + * sdca_jack_init_state - Initialise transient state for a jack interrupt
> + * @interrupt: SDCA interrupt structure.
> + *
> + * Return: Zero on success or a negative error code.
> + */
> +int sdca_jack_init_state(struct sdca_interrupt *interrupt)
>  {
>  	struct jack_state *jack_state = interrupt->priv;
> +	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s %s",
> +						   interrupt->entity->label,
> +						   SDCA_CTL_SELECTED_MODE_NAME);
>  
> -	if (!jack_state)
> -		return;
> +	if (!name)
> +		return -ENOMEM;
> +
> +	jack_state->kctl = snd_soc_component_get_kcontrol(interrupt->component, name);
> +	if (!jack_state->kctl) {
> +		dev_err(interrupt->dev, "control not found: %s\n", name);
> +		return -ENODEV;
> +	}
>  
> -	/* devm allocation: just clear the pointer */
> -	interrupt->priv = NULL;
> +	return 0;
>  }
> -EXPORT_SYMBOL_NS_GPL(sdca_jack_free_state, "SND_SOC_SDCA");
> +EXPORT_SYMBOL_NS_GPL(sdca_jack_init_state, "SND_SOC_SDCA");
>  
>  
>  /**
> @@ -164,7 +167,8 @@ EXPORT_SYMBOL_NS_GPL(sdca_jack_free_state, "SND_SOC_SDCA");
>   */
>  int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *jack)
>  {
> -	int i, ret;
> +	int i, j;
> +	int ret;
>  
>  	guard(mutex)(&info->irq_lock);
>  
> @@ -172,6 +176,7 @@ int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *ja
>  		struct sdca_interrupt *interrupt = &info->irqs[i];
>  		struct sdca_control *control = interrupt->control;
>  		struct sdca_entity *entity = interrupt->entity;
> +		struct sdca_control_range *range;
>  		struct jack_state *jack_state;
>  
>  		if (!interrupt->dev)
> @@ -179,7 +184,14 @@ int sdca_jack_set_jack(struct sdca_interrupt_info *info, struct snd_soc_jack *ja
>  
>  		switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
>  		case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
> +			/* Keep scope small: do not backport cb3c257e0824 which wires
> +			 * type_get_mask into jack_state->mask. Use legacy behaviour
> +			 * and report a full mask (0xFFFF) here.
> +			 */
>  			jack_state = interrupt->priv;
> +
> +			jack_state->mask = 0xFFFF;
> +
>  			jack_state->jack = jack;
>  
>  			/* Report initial state in case IRQ was already handled */
> @@ -201,7 +213,6 @@ int sdca_jack_report(struct sdca_interrupt *interrupt)
>  	struct jack_state *jack_state = interrupt->priv;
>  	struct sdca_control_range *range;
>  	enum sdca_terminal_type type;
> -	unsigned int report = 0;
>  	unsigned int reg, val;
>  	int ret;
>  
> @@ -223,6 +234,11 @@ int sdca_jack_report(struct sdca_interrupt *interrupt)
>  	type = sdca_range_search(range, SDCA_SELECTED_MODE_INDEX,
>  				 val, SDCA_SELECTED_MODE_TERM_TYPE);
>  
> +	/* Map the terminal type to a jack report without relying on the
> +	 * helper that was introduced upstream in cb3c257e0824 (out of scope).
> +	 */
> +	unsigned int report = 0;
> +
>  	switch (type) {
>  	case SDCA_TERM_TYPE_LINEIN_STEREO:
>  	case SDCA_TERM_TYPE_LINEIN_FRONT_LR:
> @@ -251,7 +267,7 @@ int sdca_jack_report(struct sdca_interrupt *interrupt)
>  		break;
>  	}
>  
> -	snd_soc_jack_report(jack_state->jack, report, 0xFFFF);
> +	snd_soc_jack_report(jack_state->jack, report, jack_state->mask);
>  
>  	return 0;
>  }
> -- 
> 2.43.0
> 
> 
> -- 
> kernel-team mailing list
> kernel-team at lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team

-- 
Andrei Gherzan
gpg: rsa4096/D4D94F67AD0E9640
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20260911/232a1352/attachment.sig>


More information about the kernel-team mailing list