Linux USB
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Yaohan Li" <shunsheng1218@gmail.com>
Cc: linux-usb@vger.kernel.org
Subject: Re: [PATCH v4] usb: typec: tcpci: acknowledge masked alerts and quiesce the IRQ
Date: Fri, 13 Nov 2026 09:14:30 +0000	[thread overview]
Message-ID: <sashiko-outbox-212527@kernel.org> (raw)
In-Reply-To: <20261113084928.211885-1-shunsheng1218@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] usb: typec: tcpci: race in tcpci_irq() with
  tcpci_quiesce_alerts() skips alert ack
--

commit b4f078603381d8a805defdf53c50acdc29717943
Author: Yaohan Li <shunsheng1218@gmail.com>

usb: typec: tcpci: acknowledge masked alerts and quiesce the IRQ

This commit acknowledges all non-RX_STATUS alert bits before filtering
against the software alert_mask, and quiesces and synchronizes the IRQ
during teardown and probe error cleanup before unregistering the TCPM
port.

> diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
> index c6165466c54b6..b11c30e67055f 100644
> --- a/drivers/usb/typec/tcpm/tcpci.c
> +++ b/drivers/usb/typec/tcpm/tcpci.c

[ ... ]

> @@ -648,10 +650,21 @@ static bool tcpci_attempt_vconn_swap_discovery(struct tcpc_dev *tcpc)
>  	return false;
>  }
>  
> +static void tcpci_quiesce_alerts(struct tcpci *tcpci)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&tcpci->alert_mask_lock, flags);
> +	tcpci->alerts_quiesced = true;
> +	WRITE_ONCE(tcpci->alert_mask, 0);
> +	spin_unlock_irqrestore(&tcpci->alert_mask_lock, flags);
> +}

[ ... ]

> @@ -710,29 +723,60 @@ static int tcpci_init(struct tcpc_dev *tcpc)

[ ... ]

>  irqreturn_t tcpci_irq(struct tcpci *tcpci)
>  {
> -	u16 status;
> +	u16 status = 0;
>  	int ret;
> -	int irq_ret;
> +	int irq_ret = 0;
>  	unsigned int raw;
>  
> -	tcpci_read16(tcpci, TCPC_ALERT, &status);
> -	irq_ret = status & tcpci->alert_mask;
> +	/*
> +	 * During teardown, acknowledge a latched alert without dispatching
> +	 * it to TCPM.  A level-triggered Alert# must not keep retriggering
> +	 * after the software mask was cleared or the hardware mask write
> +	 * failed; the port may already be going away.
> +	 */
> +	if (READ_ONCE(tcpci->alerts_quiesced)) {
> +		ret = tcpci_read16(tcpci, TCPC_ALERT, &status);
> +		if (ret < 0)
> +			return IRQ_NONE;
> +		if (status) {
> +			ret = tcpci_write16(tcpci, TCPC_ALERT, status);
> +			if (ret < 0)
> +				return IRQ_HANDLED;
> +			irq_ret = 1;
> +		}
> +		return IRQ_RETVAL(irq_ret);
> +	}
> +
> +	if (!READ_ONCE(tcpci->alert_mask))
> +		return IRQ_NONE;
>  
> -process_status:
>  	/*
> -	 * Clear alert status for everything except RX_STATUS, which shouldn't
> -	 * be cleared until we have successfully retrieved message.
> +	 * Acknowledge every non-RX_STATUS bit from the raw alert value, not
> +	 * only the bits enabled in the software mask.  Some controllers
> +	 * enable additional alerts in TCPC_ALERT_MASK (for example RT1711H
> +	 * enables FAULT and RX_BUF_OVF); dropping those bits before the
> +	 * write would leave a level-triggered Alert# asserted.  RX_STATUS is
> +	 * cleared only after the message has been read successfully.
>  	 */
> +	tcpci_read16(tcpci, TCPC_ALERT, &status);
>  	if (status & ~TCPC_ALERT_RX_STATUS)
>  		tcpci_write16(tcpci, TCPC_ALERT,
>  			      status & ~TCPC_ALERT_RX_STATUS);
> +	irq_ret = status;
> +
> +	status &= READ_ONCE(tcpci->alert_mask);
> +
> +process_status:

[ ... ]

> @@ -806,8 +850,13 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
>  		tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED);
>  
>  	tcpci_read16(tcpci, TCPC_ALERT, &status);
> +	if (status & ~TCPC_ALERT_RX_STATUS)
> +		tcpci_write16(tcpci, TCPC_ALERT,
> +			      status & ~TCPC_ALERT_RX_STATUS);
> +	irq_ret |= status;
>  
> -	if (status & tcpci->alert_mask)
> +	status &= READ_ONCE(tcpci->alert_mask);
> +	if (status)
>  		goto process_status;
>  
>  	return IRQ_RETVAL(irq_ret);

[Severity: Medium]
Can tcpci_irq() race with tcpci_quiesce_alerts() and return without
acknowledging TCPC_ALERT?

CPU0                              CPU1
tcpci_irq()
  READ_ONCE(tcpci->alerts_quiesced)
    -> false
                                  tcpci_remove()
                                    tcpci_quiesce_alerts()
                                      tcpci->alerts_quiesced = true;
                                      WRITE_ONCE(tcpci->alert_mask, 0);
  if (!READ_ONCE(tcpci->alert_mask))
    return IRQ_NONE;              <-- skips TCPC_ALERT read and ack

Because tcpci_irq() reads tcpci->alerts_quiesced and tcpci->alert_mask
in separate unlocked steps, a concurrent tcpci_quiesce_alerts() can zero
tcpci->alert_mask after the quiesced check has already passed.

A second window exists just below and in the loop tail before jumping to
process_status: if tcpci_irq() reads TCPC_ALERT with TCPC_ALERT_RX_STATUS
set, the upfront write clears only status & ~TCPC_ALERT_RX_STATUS, and if
tcpci_quiesce_alerts() zeroes tcpci->alert_mask before
status &= READ_ONCE(tcpci->alert_mask), TCPC_ALERT_RX_STATUS is masked
out and never cleared in the RX handler.  Similarly, if tcpci_init()
fails before publishing tcpci->alert_mask (tcpm_init() ignores the
return value of port->tcpc->init()), tcpci->alert_mask remains 0 and
tcpci_irq() returns IRQ_NONE without acknowledging hardware alerts on
subdrivers such as tcpci_rt1711h that program TCPC_ALERT_MASK
independently.  In all of these cases, a latched alert can keep a
level-triggered Alert# line asserted and cause an interrupt storm or
spurious IRQ disablement.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261113084928.211885-1-shunsheng1218@gmail.com?part=1

      reply	other threads:[~2026-11-13  9:14 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-13  8:49 [PATCH v4] usb: typec: tcpci: acknowledge masked alerts and quiesce the IRQ Yaohan Li
2026-11-13  9:14 ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-212527@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=shunsheng1218@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox