All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
@ 2019-03-15 14:42 Hans de Goede
  0 siblings, 0 replies; 5+ messages in thread
From: Hans de Goede @ 2019-03-15 14:42 UTC (permalink / raw
  To: Greg Kroah-Hartman, Guenter Roeck, Heikki Krogerus
  Cc: Hans de Goede, linux-usb

PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
simply ignore any src PDOs which the sink does not understand such as PPS
but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
causing contract negotiation to fail.

This commit fixes such sinks not working by re-trying the contract
negotiation with PD-2.0 source-caps messages if we don't have a contract
after PD_N_HARD_RESET_COUNT hard-reset attempts.

The problem fixed by this commit was noticed with a Type-C to VGA dongle.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
The Type-C to VGA dongle on which this encountered looks like this one:
https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
---
 drivers/usb/typec/tcpm/tcpm.c | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index f1c39a3c7534..3f8df845d1a5 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -37,6 +37,7 @@
 	S(SRC_ATTACHED),			\
 	S(SRC_STARTUP),				\
 	S(SRC_SEND_CAPABILITIES),		\
+	S(SRC_SEND_CAP_LOWER_PD_REVISION),	\
 	S(SRC_NEGOTIATE_CAPABILITIES),		\
 	S(SRC_TRANSITION_SUPPLY),		\
 	S(SRC_READY),				\
@@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
 	return SNK_UNATTACHED;
 }
 
+/*
+ * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
+ * simply ignore any src PDOs which the sink does not understand such as PPS
+ * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
+ * causing contract negotiation to fail.
+ *
+ * This function is used by the SRC_SEND_CAPABILITIES state in
+ * run_state_machine() to work around this.
+ *
+ * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
+ * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
+ * this state will fallback to a lower PD revision and then try sending the
+ * src-capabilities again.
+ */
+static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port *port)
+{
+	if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
+		return HARD_RESET_SEND;
+	if (port->negotiated_rev > PD_REV20)
+		return SRC_SEND_CAP_LOWER_PD_REVISION;
+	return hard_reset_state(port);
+}
+
 static inline enum tcpm_state unattached_state(struct tcpm_port *port)
 {
 	if (port->port_type == TYPEC_PORT_DRP) {
@@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
 			/* port->hard_reset_count = 0; */
 			port->caps_count = 0;
 			port->pd_capable = true;
-			tcpm_set_state_cond(port, hard_reset_state(port),
+			tcpm_set_state_cond(port,
+					    src_send_cap_timeout_state(port),
 					    PD_T_SEND_SOURCE_CAP);
 		}
 		break;
+	case SRC_SEND_CAP_LOWER_PD_REVISION:
+		if (WARN_ON(port->negotiated_rev <= PD_REV20))
+			break;
+		port->negotiated_rev--;
+		port->hard_reset_count = 0;
+		tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+		break;
 	case SRC_NEGOTIATE_CAPABILITIES:
 		ret = tcpm_pd_check_request(port);
 		if (ret < 0) {

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

* usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
@ 2019-03-15 14:57 Guenter Roeck
  0 siblings, 0 replies; 5+ messages in thread
From: Guenter Roeck @ 2019-03-15 14:57 UTC (permalink / raw
  To: Hans de Goede; +Cc: Greg Kroah-Hartman, Heikki Krogerus, linux-usb

On Fri, Mar 15, 2019 at 03:42:19PM +0100, Hans de Goede wrote:
> PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
> simply ignore any src PDOs which the sink does not understand such as PPS
> but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
> causing contract negotiation to fail.
> 
> This commit fixes such sinks not working by re-trying the contract
> negotiation with PD-2.0 source-caps messages if we don't have a contract
> after PD_N_HARD_RESET_COUNT hard-reset attempts.
> 
> The problem fixed by this commit was noticed with a Type-C to VGA dongle.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> The Type-C to VGA dongle on which this encountered looks like this one:
> https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
> ---
>  drivers/usb/typec/tcpm/tcpm.c | 34 +++++++++++++++++++++++++++++++++-
>  1 file changed, 33 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index f1c39a3c7534..3f8df845d1a5 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -37,6 +37,7 @@
>  	S(SRC_ATTACHED),			\
>  	S(SRC_STARTUP),				\
>  	S(SRC_SEND_CAPABILITIES),		\
> +	S(SRC_SEND_CAP_LOWER_PD_REVISION),	\
>  	S(SRC_NEGOTIATE_CAPABILITIES),		\
>  	S(SRC_TRANSITION_SUPPLY),		\
>  	S(SRC_READY),				\
> @@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
>  	return SNK_UNATTACHED;
>  }
>  
> +/*
> + * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
> + * simply ignore any src PDOs which the sink does not understand such as PPS
> + * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
> + * causing contract negotiation to fail.
> + *
> + * This function is used by the SRC_SEND_CAPABILITIES state in
> + * run_state_machine() to work around this.
> + *
> + * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
> + * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
> + * this state will fallback to a lower PD revision and then try sending the
> + * src-capabilities again.
> + */
> +static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port *port)
> +{
> +	if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
> +		return HARD_RESET_SEND;
> +	if (port->negotiated_rev > PD_REV20)
> +		return SRC_SEND_CAP_LOWER_PD_REVISION;
> +	return hard_reset_state(port);
> +}
> +
>  static inline enum tcpm_state unattached_state(struct tcpm_port *port)
>  {
>  	if (port->port_type == TYPEC_PORT_DRP) {
> @@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
>  			/* port->hard_reset_count = 0; */
>  			port->caps_count = 0;
>  			port->pd_capable = true;
> -			tcpm_set_state_cond(port, hard_reset_state(port),
> +			tcpm_set_state_cond(port,
> +					    src_send_cap_timeout_state(port),
>  					    PD_T_SEND_SOURCE_CAP);
>  		}
>  		break;
> +	case SRC_SEND_CAP_LOWER_PD_REVISION:
> +		if (WARN_ON(port->negotiated_rev <= PD_REV20))
> +			break;

I really dislike the WARN_ON here. A bad remote can potentially trigger
this, which on systems with crash on warning enabled can result in a
reboot. Just revert to the original behavior here, and maybe add
a tcpm log message.

Guenter

> +		port->negotiated_rev--;
> +		port->hard_reset_count = 0;
> +		tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
> +		break;
>  	case SRC_NEGOTIATE_CAPABILITIES:
>  		ret = tcpm_pd_check_request(port);
>  		if (ret < 0) {
> -- 
> 2.20.1
>

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

* usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
@ 2019-03-15 16:43 Hans de Goede
  0 siblings, 0 replies; 5+ messages in thread
From: Hans de Goede @ 2019-03-15 16:43 UTC (permalink / raw
  To: Guenter Roeck; +Cc: Greg Kroah-Hartman, Heikki Krogerus, linux-usb

Hi,

On 3/15/19 3:57 PM, Guenter Roeck wrote:
> On Fri, Mar 15, 2019 at 03:42:19PM +0100, Hans de Goede wrote:
>> PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
>> simply ignore any src PDOs which the sink does not understand such as PPS
>> but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
>> causing contract negotiation to fail.
>>
>> This commit fixes such sinks not working by re-trying the contract
>> negotiation with PD-2.0 source-caps messages if we don't have a contract
>> after PD_N_HARD_RESET_COUNT hard-reset attempts.
>>
>> The problem fixed by this commit was noticed with a Type-C to VGA dongle.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> The Type-C to VGA dongle on which this encountered looks like this one:
>> https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
>> ---
>>   drivers/usb/typec/tcpm/tcpm.c | 34 +++++++++++++++++++++++++++++++++-
>>   1 file changed, 33 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
>> index f1c39a3c7534..3f8df845d1a5 100644
>> --- a/drivers/usb/typec/tcpm/tcpm.c
>> +++ b/drivers/usb/typec/tcpm/tcpm.c
>> @@ -37,6 +37,7 @@
>>   	S(SRC_ATTACHED),			\
>>   	S(SRC_STARTUP),				\
>>   	S(SRC_SEND_CAPABILITIES),		\
>> +	S(SRC_SEND_CAP_LOWER_PD_REVISION),	\
>>   	S(SRC_NEGOTIATE_CAPABILITIES),		\
>>   	S(SRC_TRANSITION_SUPPLY),		\
>>   	S(SRC_READY),				\
>> @@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
>>   	return SNK_UNATTACHED;
>>   }
>>   
>> +/*
>> + * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
>> + * simply ignore any src PDOs which the sink does not understand such as PPS
>> + * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
>> + * causing contract negotiation to fail.
>> + *
>> + * This function is used by the SRC_SEND_CAPABILITIES state in
>> + * run_state_machine() to work around this.
>> + *
>> + * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
>> + * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
>> + * this state will fallback to a lower PD revision and then try sending the
>> + * src-capabilities again.
>> + */
>> +static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port *port)
>> +{
>> +	if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
>> +		return HARD_RESET_SEND;
>> +	if (port->negotiated_rev > PD_REV20)
>> +		return SRC_SEND_CAP_LOWER_PD_REVISION;
>> +	return hard_reset_state(port);
>> +}
>> +
>>   static inline enum tcpm_state unattached_state(struct tcpm_port *port)
>>   {
>>   	if (port->port_type == TYPEC_PORT_DRP) {
>> @@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
>>   			/* port->hard_reset_count = 0; */
>>   			port->caps_count = 0;
>>   			port->pd_capable = true;
>> -			tcpm_set_state_cond(port, hard_reset_state(port),
>> +			tcpm_set_state_cond(port,
>> +					    src_send_cap_timeout_state(port),
>>   					    PD_T_SEND_SOURCE_CAP);
>>   		}
>>   		break;
>> +	case SRC_SEND_CAP_LOWER_PD_REVISION:
>> +		if (WARN_ON(port->negotiated_rev <= PD_REV20))
>> +			break;
> 
> I really dislike the WARN_ON here. A bad remote can potentially trigger
> this, which on systems with crash on warning enabled can result in a
> reboot. Just revert to the original behavior here, and maybe add
> a tcpm log message.

How would a bad remote trigger this?

We only ever call set_state with SRC_SEND_CAP_LOWER_PD_REVISION in the new
src_send_cap_timeout_state which has:

	if (port->negotiated_rev > PD_REV20)
		return SRC_SEND_CAP_LOWER_PD_REVISION;

So we really should never hit the WARN_ON, of we do hit the WARN_ON
something is seriously wrong.

Regards,

Hans



> 
> Guenter
> 
>> +		port->negotiated_rev--;
>> +		port->hard_reset_count = 0;
>> +		tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
>> +		break;
>>   	case SRC_NEGOTIATE_CAPABILITIES:
>>   		ret = tcpm_pd_check_request(port);
>>   		if (ret < 0) {
>> -- 
>> 2.20.1
>>

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

* usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
@ 2019-03-15 16:53 Guenter Roeck
  0 siblings, 0 replies; 5+ messages in thread
From: Guenter Roeck @ 2019-03-15 16:53 UTC (permalink / raw
  To: Hans de Goede; +Cc: Greg Kroah-Hartman, Heikki Krogerus, linux-usb

On Fri, Mar 15, 2019 at 05:43:05PM +0100, Hans de Goede wrote:
> Hi,
> 
> On 3/15/19 3:57 PM, Guenter Roeck wrote:
> >On Fri, Mar 15, 2019 at 03:42:19PM +0100, Hans de Goede wrote:
> >>PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
> >>simply ignore any src PDOs which the sink does not understand such as PPS
> >>but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
> >>causing contract negotiation to fail.
> >>
> >>This commit fixes such sinks not working by re-trying the contract
> >>negotiation with PD-2.0 source-caps messages if we don't have a contract
> >>after PD_N_HARD_RESET_COUNT hard-reset attempts.
> >>
> >>The problem fixed by this commit was noticed with a Type-C to VGA dongle.
> >>
> >>Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> >>---
> >>The Type-C to VGA dongle on which this encountered looks like this one:
> >>https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
> >>---
> >>  drivers/usb/typec/tcpm/tcpm.c | 34 +++++++++++++++++++++++++++++++++-
> >>  1 file changed, 33 insertions(+), 1 deletion(-)
> >>
> >>diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> >>index f1c39a3c7534..3f8df845d1a5 100644
> >>--- a/drivers/usb/typec/tcpm/tcpm.c
> >>+++ b/drivers/usb/typec/tcpm/tcpm.c
> >>@@ -37,6 +37,7 @@
> >>  	S(SRC_ATTACHED),			\
> >>  	S(SRC_STARTUP),				\
> >>  	S(SRC_SEND_CAPABILITIES),		\
> >>+	S(SRC_SEND_CAP_LOWER_PD_REVISION),	\
> >>  	S(SRC_NEGOTIATE_CAPABILITIES),		\
> >>  	S(SRC_TRANSITION_SUPPLY),		\
> >>  	S(SRC_READY),				\
> >>@@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
> >>  	return SNK_UNATTACHED;
> >>  }
> >>+/*
> >>+ * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
> >>+ * simply ignore any src PDOs which the sink does not understand such as PPS
> >>+ * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
> >>+ * causing contract negotiation to fail.
> >>+ *
> >>+ * This function is used by the SRC_SEND_CAPABILITIES state in
> >>+ * run_state_machine() to work around this.
> >>+ *
> >>+ * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
> >>+ * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
> >>+ * this state will fallback to a lower PD revision and then try sending the
> >>+ * src-capabilities again.
> >>+ */
> >>+static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port *port)
> >>+{
> >>+	if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
> >>+		return HARD_RESET_SEND;
> >>+	if (port->negotiated_rev > PD_REV20)
> >>+		return SRC_SEND_CAP_LOWER_PD_REVISION;
> >>+	return hard_reset_state(port);
> >>+}
> >>+
> >>  static inline enum tcpm_state unattached_state(struct tcpm_port *port)
> >>  {
> >>  	if (port->port_type == TYPEC_PORT_DRP) {
> >>@@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
> >>  			/* port->hard_reset_count = 0; */
> >>  			port->caps_count = 0;
> >>  			port->pd_capable = true;
> >>-			tcpm_set_state_cond(port, hard_reset_state(port),
> >>+			tcpm_set_state_cond(port,
> >>+					    src_send_cap_timeout_state(port),
> >>  					    PD_T_SEND_SOURCE_CAP);
> >>  		}
> >>  		break;
> >>+	case SRC_SEND_CAP_LOWER_PD_REVISION:
> >>+		if (WARN_ON(port->negotiated_rev <= PD_REV20))
> >>+			break;
> >
> >I really dislike the WARN_ON here. A bad remote can potentially trigger
> >this, which on systems with crash on warning enabled can result in a
> >reboot. Just revert to the original behavior here, and maybe add
> >a tcpm log message.
> 
> How would a bad remote trigger this?
> 
> We only ever call set_state with SRC_SEND_CAP_LOWER_PD_REVISION in the new
> src_send_cap_timeout_state which has:
> 
> 	if (port->negotiated_rev > PD_REV20)
> 		return SRC_SEND_CAP_LOWER_PD_REVISION;
> 
> So we really should never hit the WARN_ON, of we do hit the WARN_ON
> something is seriously wrong.
> 

If that situation can't happen, the check should not be there in the first
place. Otherwise you could litter the implementation with WARN_ON all over
the place, and make it all but unreadable. I am not in favor of code like
that.

Guenter

> Regards,
> 
> Hans
> 
> 
> 
> >
> >Guenter
> >
> >>+		port->negotiated_rev--;
> >>+		port->hard_reset_count = 0;
> >>+		tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
> >>+		break;
> >>  	case SRC_NEGOTIATE_CAPABILITIES:
> >>  		ret = tcpm_pd_check_request(port);
> >>  		if (ret < 0) {
> >>-- 
> >>2.20.1
> >>

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

* usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps
@ 2019-03-16 13:58 Hans de Goede
  0 siblings, 0 replies; 5+ messages in thread
From: Hans de Goede @ 2019-03-16 13:58 UTC (permalink / raw
  To: Guenter Roeck; +Cc: Greg Kroah-Hartman, Heikki Krogerus, linux-usb

Hi,

On 15-03-19 17:53, Guenter Roeck wrote:
> On Fri, Mar 15, 2019 at 05:43:05PM +0100, Hans de Goede wrote:
>> Hi,
>>
>> On 3/15/19 3:57 PM, Guenter Roeck wrote:
>>> On Fri, Mar 15, 2019 at 03:42:19PM +0100, Hans de Goede wrote:
>>>> PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
>>>> simply ignore any src PDOs which the sink does not understand such as PPS
>>>> but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
>>>> causing contract negotiation to fail.
>>>>
>>>> This commit fixes such sinks not working by re-trying the contract
>>>> negotiation with PD-2.0 source-caps messages if we don't have a contract
>>>> after PD_N_HARD_RESET_COUNT hard-reset attempts.
>>>>
>>>> The problem fixed by this commit was noticed with a Type-C to VGA dongle.
>>>>
>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>> ---
>>>> The Type-C to VGA dongle on which this encountered looks like this one:
>>>> https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
>>>> ---
>>>>   drivers/usb/typec/tcpm/tcpm.c | 34 +++++++++++++++++++++++++++++++++-
>>>>   1 file changed, 33 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
>>>> index f1c39a3c7534..3f8df845d1a5 100644
>>>> --- a/drivers/usb/typec/tcpm/tcpm.c
>>>> +++ b/drivers/usb/typec/tcpm/tcpm.c
>>>> @@ -37,6 +37,7 @@
>>>>   	S(SRC_ATTACHED),			\
>>>>   	S(SRC_STARTUP),				\
>>>>   	S(SRC_SEND_CAPABILITIES),		\
>>>> +	S(SRC_SEND_CAP_LOWER_PD_REVISION),	\
>>>>   	S(SRC_NEGOTIATE_CAPABILITIES),		\
>>>>   	S(SRC_TRANSITION_SUPPLY),		\
>>>>   	S(SRC_READY),				\
>>>> @@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
>>>>   	return SNK_UNATTACHED;
>>>>   }
>>>> +/*
>>>> + * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
>>>> + * simply ignore any src PDOs which the sink does not understand such as PPS
>>>> + * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
>>>> + * causing contract negotiation to fail.
>>>> + *
>>>> + * This function is used by the SRC_SEND_CAPABILITIES state in
>>>> + * run_state_machine() to work around this.
>>>> + *
>>>> + * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
>>>> + * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
>>>> + * this state will fallback to a lower PD revision and then try sending the
>>>> + * src-capabilities again.
>>>> + */
>>>> +static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port *port)
>>>> +{
>>>> +	if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
>>>> +		return HARD_RESET_SEND;
>>>> +	if (port->negotiated_rev > PD_REV20)
>>>> +		return SRC_SEND_CAP_LOWER_PD_REVISION;
>>>> +	return hard_reset_state(port);
>>>> +}
>>>> +
>>>>   static inline enum tcpm_state unattached_state(struct tcpm_port *port)
>>>>   {
>>>>   	if (port->port_type == TYPEC_PORT_DRP) {
>>>> @@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
>>>>   			/* port->hard_reset_count = 0; */
>>>>   			port->caps_count = 0;
>>>>   			port->pd_capable = true;
>>>> -			tcpm_set_state_cond(port, hard_reset_state(port),
>>>> +			tcpm_set_state_cond(port,
>>>> +					    src_send_cap_timeout_state(port),
>>>>   					    PD_T_SEND_SOURCE_CAP);
>>>>   		}
>>>>   		break;
>>>> +	case SRC_SEND_CAP_LOWER_PD_REVISION:
>>>> +		if (WARN_ON(port->negotiated_rev <= PD_REV20))
>>>> +			break;
>>>
>>> I really dislike the WARN_ON here. A bad remote can potentially trigger
>>> this, which on systems with crash on warning enabled can result in a
>>> reboot. Just revert to the original behavior here, and maybe add
>>> a tcpm log message.
>>
>> How would a bad remote trigger this?
>>
>> We only ever call set_state with SRC_SEND_CAP_LOWER_PD_REVISION in the new
>> src_send_cap_timeout_state which has:
>>
>> 	if (port->negotiated_rev > PD_REV20)
>> 		return SRC_SEND_CAP_LOWER_PD_REVISION;
>>
>> So we really should never hit the WARN_ON, of we do hit the WARN_ON
>> something is seriously wrong.
>>
> 
> If that situation can't happen, the check should not be there in the first
> place. Otherwise you could litter the implementation with WARN_ON all over
> the place, and make it all but unreadable. I am not in favor of code like
> that.

So thinking more about this, the WARN_ON can actually trigger if we
receive a pd packet with a lower revision during the timeout window and
this does not cause the state to change.

This is an obvious time of check vs time of use problem and the fix is
to check if we should try to fallback / check the negotiated_rev after
the timeout, rather then when determining the next state to use after
the timeout, so that both the check and the decrement of negotiated_rev
are done in one go while holding the lock. I will rework the patch
accordingly and submit a new version.

Regards,

Hans



>>>> +		port->negotiated_rev--;
>>>> +		port->hard_reset_count = 0;
>>>> +		tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
>>>> +		break;
>>>>   	case SRC_NEGOTIATE_CAPABILITIES:
>>>>   		ret = tcpm_pd_check_request(port);
>>>>   		if (ret < 0) {
>>>> -- 
>>>> 2.20.1
>>>>

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

end of thread, other threads:[~2019-03-16 13:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-03-15 16:43 usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps Hans de Goede
  -- strict thread matches above, loose matches on Subject: below --
2019-03-16 13:58 Hans de Goede
2019-03-15 16:53 Guenter Roeck
2019-03-15 14:57 Guenter Roeck
2019-03-15 14:42 Hans de Goede

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.