Linux kernel and device drivers for NXP i.MX platforms
 help / color / mirror / Atom feed
* [PATCH] usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive()
@ 2026-07-03  6:32 Xu Yang
  2026-07-03  6:39 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Xu Yang @ 2026-07-03  6:32 UTC (permalink / raw)
  To: badhri, heikki.krogerus, gregkh; +Cc: linux-usb, linux-kernel, imx, jun.li

From: Xu Yang <xu.yang_2@nxp.com>

Previously, tcpci_irq() always passed TCPC_TX_SOP as the receive type
to tcpm_pd_receive(), ignoring the actual frame type reported by the
TCPC_RX_BUF_FRAME_TYPE register.

Read TCPC_RX_BUF_FRAME_TYPE after receiving a PD message and map it to
the appropriate tcpm_transmit_type:
  - TCPC_RX_BUF_FRAME_TYPE_SOP1 -> TCPC_TX_SOP_PRIME
  - TCPC_RX_BUF_FRAME_TYPE_SOP  -> TCPC_TX_SOP (default)

This allows TCPM to correctly distinguish SOP from SOP' messages, which
is required for proper cable plug communication during PD negotiation.

Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
 drivers/usb/typec/tcpm/tcpci.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index 7ac7000b2d13..c19413f41bcb 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -748,7 +748,8 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
 
 	if (status & TCPC_ALERT_RX_STATUS) {
 		struct pd_message msg;
-		unsigned int cnt, payload_cnt;
+		unsigned int cnt, type, payload_cnt;
+		enum tcpm_transmit_type rx_type;
 		u16 header;
 
 		regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);
@@ -763,6 +764,17 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
 		else
 			payload_cnt = 0;
 
+		regmap_read(tcpci->regmap, TCPC_RX_BUF_FRAME_TYPE, &type);
+		switch (type) {
+		case TCPC_RX_BUF_FRAME_TYPE_SOP1:
+			rx_type = TCPC_TX_SOP_PRIME;
+			break;
+		case TCPC_RX_BUF_FRAME_TYPE_SOP:
+		default:
+			rx_type = TCPC_TX_SOP;
+			break;
+		}
+
 		tcpci_read16(tcpci, TCPC_RX_HDR, &header);
 		msg.header = cpu_to_le16(header);
 
@@ -776,7 +788,7 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
 		/* Read complete, clear RX status alert bit */
 		tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
 
-		tcpm_pd_receive(tcpci->port, &msg, TCPC_TX_SOP);
+		tcpm_pd_receive(tcpci->port, &msg, rx_type);
 	}
 
 	if (tcpci->data->vbus_vsafe0v && (status & TCPC_ALERT_EXTENDED_STATUS)) {
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive()
  2026-07-03  6:32 [PATCH] usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive() Xu Yang
@ 2026-07-03  6:39 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-07-03  6:39 UTC (permalink / raw)
  To: Xu Yang; +Cc: Frank.Li, imx

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] The newly added regmap_read() for TCPC_RX_BUF_FRAME_TYPE ignores its return value, leading to the use of an uninitialized stack variable.

Pre-existing issues:
- [High] Unchecked I2C read failure at the end of the IRQ handler causes an infinite loop and CPU hang.
- [High] Incorrect endianness conversion for 16-bit registers on Big Endian architectures corrupts message headers and status flags.
- [Medium] Missing I2C read error checks lead to the use of uninitialized stack variables for `cnt` and `header`.
--

commit 81a7c680e2fcddf86dbe13e10560745c1e22e61c
Author: Xu Yang <xu.yang_2@nxp.com>

usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive()

This commit reads the frame type from the TCPC_RX_BUF_FRAME_TYPE register
after receiving a PD message. It maps the read value to the appropriate
transmit type and passes it to tcpm_pd_receive() to correctly distinguish
SOP from SOP' messages.

> diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
> index 7ac7000b2d139..c19413f41bcb6 100644
> --- a/drivers/usb/typec/tcpm/tcpci.c
> +++ b/drivers/usb/typec/tcpm/tcpci.c
[ ... ]
> @@ -748,7 +748,8 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
>  
>  	if (status & TCPC_ALERT_RX_STATUS) {
>  		struct pd_message msg;
> -		unsigned int cnt, payload_cnt;
> +		unsigned int cnt, type, payload_cnt;
> +		enum tcpm_transmit_type rx_type;
>  		u16 header;
>  
>  		regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);

[Severity: Medium]
This is a pre-existing issue, but what happens if the I2C read for
TCPC_RX_BYTE_CNT fails?

If regmap_read() returns an error, the local stack variable `cnt` remains
uninitialized. This random stack data would then be used for calculating
`payload_cnt` further down.

>  		/*
>  		 * 'cnt' corresponds to READABLE_BYTE_COUNT in section 4.4.14
[ ... ]
>  		if (cnt > 3)
>  			payload_cnt = cnt - (1 + sizeof(msg.header));
>  		else
>  			payload_cnt = 0;
>  
> +		regmap_read(tcpci->regmap, TCPC_RX_BUF_FRAME_TYPE, &type);
> +		switch (type) {

[Severity: High]
Does this code use an uninitialized value if the I2C read fails?

If regmap_read() returns an error code due to an I2C failure, `type` will be
left uninitialized and contain random stack memory. This garbage value is
then evaluated in the switch statement, which could incorrectly map a normal
SOP message as an SOP' message and disrupt Power Delivery negotiations.

> +		case TCPC_RX_BUF_FRAME_TYPE_SOP1:
> +			rx_type = TCPC_TX_SOP_PRIME;
> +			break;
> +		case TCPC_RX_BUF_FRAME_TYPE_SOP:
> +		default:
> +			rx_type = TCPC_TX_SOP;
> +			break;
> +		}
> +
>  		tcpci_read16(tcpci, TCPC_RX_HDR, &header);

[Severity: Medium]
This is a pre-existing issue, but similar to the TCPC_RX_BYTE_CNT read,
should the return value of tcpci_read16() be checked here?

If the read fails, `header` remains uninitialized before being evaluated
on the next line.

>  		msg.header = cpu_to_le16(header);

[Severity: High]
This is a pre-existing issue, but could this byte swap result in corrupted
message headers on Big Endian architectures?

Looking at tcpci_read16(), it uses regmap_raw_read() to read a 16-bit
register into a host u16 variable. regmap_raw_read() bypasses endianness
formatting, meaning the buffer gets the raw little-endian bytes from the
device.

On a Big Endian CPU, reading this u16 produces a byte-swapped value. When
cpu_to_le16() is then applied, it byte-swaps the value again, resulting in
an incorrect big-endian byte sequence in memory. This breaks the
interpretation of the header in the TCPM core.

>  
[ ... ]
>  		/* Read complete, clear RX status alert bit */
>  		tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
>  
> -		tcpm_pd_receive(tcpci->port, &msg, TCPC_TX_SOP);
> +		tcpm_pd_receive(tcpci->port, &msg, rx_type);
>  	}
>  
>  	if (tcpci->data->vbus_vsafe0v && (status & TCPC_ALERT_EXTENDED_STATUS)) {

[Severity: High]
This is a pre-existing issue, but further down in tcpci_irq(), does the
unchecked I2C read at the end of the IRQ handler cause an infinite loop?

drivers/usb/typec/tcpm/tcpci.c:tcpci_irq() {
    ...
    process_status:
    ...
    tcpci_read16(tcpci, TCPC_ALERT, &status);

    if (status & tcpci->alert_mask)
        goto process_status;
}

If this final I2C read fails, the local `status` variable is unmodified and
retains its previous value. Because the previous value triggered the loop,
this causes an unconditional `goto process_status;`, potentially hanging
the CPU if the I2C bus is wedged.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260703063247.2521524-1-xu.yang_2@oss.nxp.com?part=1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-03  6:39 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-03  6:32 [PATCH] usb: typec: tcpci: pass correct rx_type to tcpm_pd_receive() Xu Yang
2026-07-03  6:39 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox