Commit af8b6270 authored by RD Babiera's avatar RD Babiera Committed by Greg Kroah-Hartman
Browse files

usb: typec: tcpm: add state machine support for SRC_VDM_IDENTITY_REQUEST



Add SRC_VDM_IDENTITY_REQUEST state which first enters after SRC_STARTUP.
The state sends Discover Identity on SOP' and transitions to
SRC_SEND_CAPABILITIES. SRC_SEND_CAPABILITIES will transition back into
SRC_VDM_IDENTITY_REQUEST instead of retrying immediately.

Signed-off-by: default avatarRD Babiera <rdbabiera@google.com>
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20240108191620.987785-23-rdbabiera@google.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fb7ff25a
Loading
Loading
Loading
Loading
+43 −6
Original line number Diff line number Diff line
@@ -146,7 +146,9 @@
	S(PORT_RESET_WAIT_OFF),			\
						\
	S(AMS_START),				\
	S(CHUNK_NOT_SUPP)
	S(CHUNK_NOT_SUPP),			\
						\
	S(SRC_VDM_IDENTITY_REQUEST)

#define FOREACH_AMS(S)				\
	S(NONE_AMS),				\
@@ -1963,6 +1965,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
					ret = tcpm_ams_start(port, VCONN_SWAP);
					if (!ret)
						return 0;
					/* Cannot perform Vconn swap */
					port->upcoming_state = INVALID_STATE;
					port->send_discover_prime = false;
				}
@@ -1994,6 +1997,16 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev,
				 * the svdm_version for the cable moving forward.
				 */
				svdm_consume_identity_sop_prime(port, p, cnt);

				/*
				 * If received in SRC_VDM_IDENTITY_REQUEST, continue
				 * to SRC_SEND_CAPABILITIES
				 */
				if (port->state == SRC_VDM_IDENTITY_REQUEST) {
					tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
					return 0;
				}

				*response_tx_sop_type = TCPC_TX_SOP;
				response[0] = VDO(USB_SID_PD, 1,
						  typec_get_negotiated_svdm_version(typec),
@@ -2288,7 +2301,8 @@ static void vdm_run_state_machine(struct tcpm_port *port)
		 * if there's traffic or we're not in PDO ready state don't send
		 * a VDM.
		 */
		if (port->state != SRC_READY && port->state != SNK_READY) {
		if (port->state != SRC_READY && port->state != SNK_READY &&
		    port->state != SRC_VDM_IDENTITY_REQUEST) {
			port->vdm_sm_running = false;
			break;
		}
@@ -2364,13 +2378,22 @@ static void vdm_run_state_machine(struct tcpm_port *port)
			tcpm_ams_finish(port);
		break;
	case VDM_STATE_ERR_SEND:
		/*
		 * When sending Discover Identity to SOP' before establishing an
		 * explicit contract, do not retry. Instead, weave sending
		 * Source_Capabilities over SOP and Discover Identity over SOP'.
		 */
		if (port->state == SRC_VDM_IDENTITY_REQUEST) {
			tcpm_ams_finish(port);
			port->vdm_state = VDM_STATE_DONE;
			tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
		/*
		 * A partner which does not support USB PD will not reply,
		 * so this is not a fatal error. At the same time, some
		 * devices may not return GoodCRC under some circumstances,
		 * so we need to retry.
		 */
		if (port->vdm_retries < 3) {
		} else if (port->vdm_retries < 3) {
			tcpm_log(port, "VDM Tx error, retry");
			port->vdm_retries++;
			port->vdm_state = VDM_STATE_READY;
@@ -4478,6 +4501,10 @@ static void run_state_machine(struct tcpm_port *port)
		}
		ret = tcpm_pd_send_source_caps(port);
		if (ret < 0) {
			if (tcpm_can_communicate_sop_prime(port) &&
			    IS_ERR_OR_NULL(port->cable))
				tcpm_set_state(port, SRC_VDM_IDENTITY_REQUEST, 0);
			else
				tcpm_set_state(port, SRC_SEND_CAPABILITIES,
					       PD_T_SEND_SOURCE_CAP);
		} else {
@@ -5395,6 +5422,15 @@ static void run_state_machine(struct tcpm_port *port)
		tcpm_pd_send_control(port, PD_CTRL_NOT_SUPP, TCPC_TX_SOP);
		tcpm_set_state(port, port->pwr_role == TYPEC_SOURCE ? SRC_READY : SNK_READY, 0);
		break;

	/* Cable states */
	case SRC_VDM_IDENTITY_REQUEST:
		port->send_discover_prime = true;
		port->tx_sop_type = TCPC_TX_SOP_PRIME;
		mod_send_discover_delayed_work(port, 0);
		port->upcoming_state = SRC_SEND_CAPABILITIES;
		break;

	default:
		WARN(1, "Unexpected port state %d\n", port->state);
		break;
@@ -6120,7 +6156,8 @@ static void tcpm_send_discover_work(struct kthread_work *work)
	}

	/* Retry if the port is not idle */
	if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) {
	if ((port->state != SRC_READY && port->state != SNK_READY &&
	     port->state != SRC_VDM_IDENTITY_REQUEST) || port->vdm_sm_running) {
		mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS);
		goto unlock;
	}