All of lore.kernel.org
 help / color / mirror / Atom feed
From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
To: RD Babiera <rdbabiera@google.com>
Cc: linux@roeck-us.net, gregkh@linuxfoundation.org,
	linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
	badhri@google.com, bryan.odonoghue@linaro.org, agross@kernel.org,
	andersson@kernel.org, konrad.dybcio@linaro.org
Subject: Re: [PATCH v3 05/12] usb: typec: tcpm: process receive and transmission of sop' messages
Date: Mon, 15 Jan 2024 11:13:55 +0200	[thread overview]
Message-ID: <ZaT2Q5vV060SA949@kuha.fi.intel.com> (raw)
In-Reply-To: <20240108191620.987785-19-rdbabiera@google.com>

On Mon, Jan 08, 2024 at 07:16:18PM +0000, RD Babiera wrote:
> Add negotiated revision and tx/rx message ids to tcpm_port specific to
> SOP'. tx_sop_type is added to the tcpm_port to determine whether the
> current constructed message will be sent over SOP or SOP' if not
> sent immediately.
> 
> tcpm_pd_rx_handler updates the received message ids. SOP* messages are not
> processed afterwards. The handler also calls tcpm_can_communicate_sop_prime
> to determine if a SOP' message is directed towards the port, and drops SOP'
> messages it should not respond to.
> 
> tcpm_can_communicate_sop_prime is added as a helper to determine whether
> the port is capable of communicating over SOP' at a given moment. Being
> the Vconn source is a requirement in Power Delivery 3.0 but only a
> recommendation in Power Delviery 2.0. Because the port should ensure that
> the cable is powered before communication, always enforce the port is the
> Vconn source regardless of revision.
> 
> Signed-off-by: RD Babiera <rdbabiera@google.com>

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
> Changes since v2:
> * Fixed style errors, switch statements with TCPC_TX_SOP now combine
> with default case.
> ---
>  drivers/usb/typec/tcpm/tcpm.c | 145 +++++++++++++++++++++++++++++++---
>  1 file changed, 134 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index ff0fcf560c88..d2ca85c8fec6 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -505,6 +505,35 @@ struct tcpm_port {
>  	 * transitions.
>  	 */
>  	bool potential_contaminant;
> +
> +	/* SOP* Related Fields */
> +	/*
> +	 * tx_sop_type determines which SOP* a message is being sent on.
> +	 * For messages that are queued and not sent immediately such as in
> +	 * tcpm_queue_message or messages that send after state changes,
> +	 * the tx_sop_type is set accordingly.
> +	 */
> +	enum tcpm_transmit_type tx_sop_type;
> +	/*
> +	 * Prior to discovering the port partner's Specification Revision, the
> +	 * Vconn source and cable plug will use the lower of their two revisions.
> +	 *
> +	 * When the port partner's Specification Revision is discovered, the following
> +	 * rules are put in place.
> +	 *	1. If the cable revision (1) is lower than the revision negotiated
> +	 * between the port and partner (2), the port and partner will communicate
> +	 * on revision (2), but the port and cable will communicate on revision (1).
> +	 *	2. If the cable revision (1) is higher than the revision negotiated
> +	 * between the port and partner (2), the port and partner will communicate
> +	 * on revision (2), and the port and cable will communicate on revision (2)
> +	 * as well.
> +	 */
> +	unsigned int negotiated_rev_prime;
> +	/*
> +	 * Each SOP* type must maintain their own tx and rx message IDs
> +	 */
> +	unsigned int message_id_prime;
> +	unsigned int rx_msgid_prime;
>  #ifdef CONFIG_DEBUG_FS
>  	struct dentry *dentry;
>  	struct mutex logbuffer_lock;	/* log buffer access lock */
> @@ -894,19 +923,30 @@ static void tcpm_ams_finish(struct tcpm_port *port)
>  }
>  
>  static int tcpm_pd_transmit(struct tcpm_port *port,
> -			    enum tcpm_transmit_type type,
> +			    enum tcpm_transmit_type tx_sop_type,
>  			    const struct pd_message *msg)
>  {
>  	unsigned long timeout;
>  	int ret;
> +	unsigned int negotiated_rev;
> +
> +	switch (tx_sop_type) {
> +	case TCPC_TX_SOP_PRIME:
> +		negotiated_rev = port->negotiated_rev_prime;
> +		break;
> +	case TCPC_TX_SOP:
> +	default:
> +		negotiated_rev = port->negotiated_rev;
> +		break;
> +	}
>  
>  	if (msg)
>  		tcpm_log(port, "PD TX, header: %#x", le16_to_cpu(msg->header));
>  	else
> -		tcpm_log(port, "PD TX, type: %#x", type);
> +		tcpm_log(port, "PD TX, type: %#x", tx_sop_type);
>  
>  	reinit_completion(&port->tx_complete);
> -	ret = port->tcpc->pd_transmit(port->tcpc, type, msg, port->negotiated_rev);
> +	ret = port->tcpc->pd_transmit(port->tcpc, tx_sop_type, msg, negotiated_rev);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -919,7 +959,17 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
>  
>  	switch (port->tx_status) {
>  	case TCPC_TX_SUCCESS:
> -		port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK;
> +		switch (tx_sop_type) {
> +		case TCPC_TX_SOP_PRIME:
> +			port->message_id_prime = (port->message_id_prime + 1) &
> +						 PD_HEADER_ID_MASK;
> +			break;
> +		case TCPC_TX_SOP:
> +		default:
> +			port->message_id = (port->message_id + 1) &
> +					   PD_HEADER_ID_MASK;
> +			break;
> +		}
>  		/*
>  		 * USB PD rev 2.0, 8.3.2.2.1:
>  		 * USB PD rev 3.0, 8.3.2.1.3:
> @@ -1604,6 +1654,57 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port)
>  
>  #define supports_modal(port)	PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
>  
> +/*
> + * Helper to determine whether the port is capable of SOP' communication at the
> + * current point in time.
> + */
> +static bool tcpm_can_communicate_sop_prime(struct tcpm_port *port)
> +{
> +	/* Check to see if tcpc supports SOP' communication */
> +	if (!port->tcpc->cable_comm_capable || !port->tcpc->cable_comm_capable(port->tcpc))
> +		return false;
> +	/*
> +	 * Power Delivery 2.0 Section 6.3.11
> +	 * Before communicating with a Cable Plug a Port Should ensure that it
> +	 * is the Vconn Source and that the Cable Plugs are powered by
> +	 * performing a Vconn swap if necessary. Since it cannot be guaranteed
> +	 * that the present Vconn Source is supplying Vconn, the only means to
> +	 * ensure that the Cable Plugs are powered is for a Port wishing to
> +	 * communicate with a Cable Plug is to become the Vconn Source.
> +	 *
> +	 * Power Delivery 3.0 Section 6.3.11
> +	 * Before communicating with a Cable Plug a Port Shall ensure that it
> +	 * is the Vconn source.
> +	 */
> +	if (port->vconn_role != TYPEC_SOURCE)
> +		return false;
> +	/*
> +	 * Power Delivery 2.0 Section 2.4.4
> +	 * When no Contract or an Implicit Contract is in place the Source can
> +	 * communicate with a Cable Plug using SOP' packets in order to discover
> +	 * its characteristics.
> +	 *
> +	 * Power Delivery 3.0 Section 2.4.4
> +	 * When no Contract or an Implicit Contract is in place only the Source
> +	 * port that is supplying Vconn is allowed to send packets to a Cable
> +	 * Plug and is allowed to respond to packets from the Cable Plug.
> +	 */
> +	if (!port->explicit_contract)
> +		return port->pwr_role == TYPEC_SOURCE;
> +	if (port->negotiated_rev == PD_REV30)
> +		return true;
> +	/*
> +	 * Power Delivery 2.0 Section 2.4.4
> +	 *
> +	 * When an Explicit Contract is in place the DFP (either the Source or
> +	 * the Sink) can communicate with the Cable Plug(s) using SOP’/SOP”
> +	 * Packets (see Figure 2-3).
> +	 */
> +	if (port->negotiated_rev == PD_REV20)
> +		return port->data_role == TYPEC_HOST;
> +	return false;
> +}
> +
>  static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
>  			const u32 *p, int cnt, u32 *response,
>  			enum adev_actions *adev_action)
> @@ -2989,14 +3090,18 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
>  	tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header),
>  		 port->attached);
>  
> -	/* Ignore SOP' for now */
> -	if (rx_sop_type == TCPC_TX_SOP_PRIME)
> -		goto done;
> -
>  	if (port->attached) {
>  		enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
>  		unsigned int msgid = pd_header_msgid_le(msg->header);
>  
> +		/*
> +		 * Drop SOP' messages if cannot receive via
> +		 * tcpm_can_communicate_sop_prime
> +		 */
> +		if (rx_sop_type == TCPC_TX_SOP_PRIME &&
> +		    !tcpm_can_communicate_sop_prime(port))
> +			goto done;
> +
>  		/*
>  		 * USB PD standard, 6.6.1.2:
>  		 * "... if MessageID value in a received Message is the
> @@ -3006,16 +3111,27 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
>  		 * Message). Note: this shall not apply to the Soft_Reset
>  		 * Message which always has a MessageID value of zero."
>  		 */
> -		if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET)
> +		switch (rx_sop_type) {
> +		case TCPC_TX_SOP_PRIME:
> +			if (msgid == port->rx_msgid_prime)
> +				goto done;
> +			port->rx_msgid_prime = msgid;
> +			/* Ignore SOP' for now */
>  			goto done;
> -		port->rx_msgid = msgid;
> +		case TCPC_TX_SOP:
> +		default:
> +			if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET)
> +				goto done;
> +			port->rx_msgid = msgid;
> +			break;
> +		}
>  
>  		/*
>  		 * If both ends believe to be DFP/host, we have a data role
>  		 * mismatch.
>  		 */
>  		if (!!(le16_to_cpu(msg->header) & PD_HEADER_DATA_ROLE) ==
> -		    (port->data_role == TYPEC_HOST)) {
> +		    (port->data_role == TYPEC_HOST) && rx_sop_type == TCPC_TX_SOP) {
>  			tcpm_log(port,
>  				 "Data role mismatch, initiating error recovery");
>  			tcpm_set_state(port, ERROR_RECOVERY, 0);
> @@ -3720,6 +3836,7 @@ static void tcpm_reset_port(struct tcpm_port *port)
>  	 * we can check tcpm_pd_rx_handler() if we had seen it before.
>  	 */
>  	port->rx_msgid = -1;
> +	port->rx_msgid_prime = -1;
>  
>  	port->tcpc->set_pd_rx(port->tcpc, false);
>  	tcpm_init_vbus(port);	/* also disables charging */
> @@ -4034,8 +4151,11 @@ static void run_state_machine(struct tcpm_port *port)
>  		port->pwr_opmode = TYPEC_PWR_MODE_USB;
>  		port->caps_count = 0;
>  		port->negotiated_rev = PD_MAX_REV;
> +		port->negotiated_rev_prime = PD_MAX_REV;
>  		port->message_id = 0;
> +		port->message_id_prime = 0;
>  		port->rx_msgid = -1;
> +		port->rx_msgid_prime = -1;
>  		port->explicit_contract = false;
>  		/* SNK -> SRC POWER/FAST_ROLE_SWAP finished */
>  		if (port->ams == POWER_ROLE_SWAP ||
> @@ -4275,8 +4395,11 @@ static void run_state_machine(struct tcpm_port *port)
>  		typec_set_pwr_opmode(port->typec_port, opmode);
>  		port->pwr_opmode = TYPEC_PWR_MODE_USB;
>  		port->negotiated_rev = PD_MAX_REV;
> +		port->negotiated_rev_prime = PD_MAX_REV;
>  		port->message_id = 0;
> +		port->message_id_prime = 0;
>  		port->rx_msgid = -1;
> +		port->rx_msgid_prime = -1;
>  		port->explicit_contract = false;
>  
>  		if (port->ams == POWER_ROLE_SWAP ||
> -- 
> 2.43.0.472.g3155946c3a-goog

-- 
heikki

  reply	other threads:[~2024-01-15  9:14 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-08 19:16 [PATCH v3 00/12] usb: typec: add SOP' support to the tcpm and alt mode drivers RD Babiera
2024-01-08 19:16 ` [PATCH v3 01/12] usb: typec: altmodes: add typec_cable_ops to typec_altmode RD Babiera
2024-01-15  9:07   ` Heikki Krogerus
2024-01-08 19:16 ` [PATCH v3 02/12] usb: typec: altmodes: add svdm version info for typec cables RD Babiera
2024-01-08 19:16 ` [PATCH v3 03/12] usb: typec: tcpci: add cable_comm_capable attribute RD Babiera
2024-01-08 19:16 ` [PATCH v3 04/12] usb: typec: tcpci: add tcpm_transmit_type to tcpm_pd_receive RD Babiera
2024-01-08 19:16 ` [PATCH v3 05/12] usb: typec: tcpm: process receive and transmission of sop' messages RD Babiera
2024-01-15  9:13   ` Heikki Krogerus [this message]
2024-01-08 19:16 ` [PATCH v3 06/12] usb: typec: tcpm: add control message support to sop' RD Babiera
2024-01-08 19:16 ` [PATCH v3 07/12] usb: typec: tcpci: add attempt_vconn_swap_discovery callback RD Babiera
2024-01-08 19:16 ` [PATCH v3 08/12] usb: typec: tcpm: add discover identity support for SOP' RD Babiera
2024-01-08 19:16 ` [PATCH v3 09/12] usb: typec: tcpm: add state machine support for SRC_VDM_IDENTITY_REQUEST RD Babiera
2024-01-08 19:16 ` [PATCH v3 10/12] usb: typec: tcpm: add discover svids and discover modes support for sop' RD Babiera
2024-01-15  9:14   ` Heikki Krogerus
2024-01-08 19:16 ` [PATCH v3 11/12] usb: typec: tcpm: add alt mode enter/exit/vdm " RD Babiera
2024-01-15  9:15   ` Heikki Krogerus
2024-01-08 19:16 ` [PATCH v3 12/12] usb: typec: altmodes/displayport: add SOP' support RD Babiera

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=ZaT2Q5vV060SA949@kuha.fi.intel.com \
    --to=heikki.krogerus@linux.intel.com \
    --cc=agross@kernel.org \
    --cc=andersson@kernel.org \
    --cc=badhri@google.com \
    --cc=bryan.odonoghue@linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=konrad.dybcio@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=rdbabiera@google.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.