Skip to content

Commit

Permalink
staging: typec: tcpm: Drop duplicate PD messages
Browse files Browse the repository at this point in the history
Per USB PD standard, we have to drop duplicate PD messages.
We can not expect lower protocol layers to drop such messages,
since lower layers don't know if a message was dropped somewhere
else in the stack.

Originally-from: Puma Hsu <puma_hsu@htc.com>
Cc: Yueyao Zhu <yueyao.zhu@gmail.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Guenter Roeck authored and Greg Kroah-Hartman committed May 15, 2017
1 parent aac53ee commit 5fec4b5
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/staging/typec/pd.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ static inline unsigned int pd_header_type_le(__le16 header)
return pd_header_type(le16_to_cpu(header));
}

static inline unsigned int pd_header_msgid(u16 header)
{
return (header >> PD_HEADER_ID_SHIFT) & PD_HEADER_ID_MASK;
}

static inline unsigned int pd_header_msgid_le(__le16 header)
{
return pd_header_msgid(le16_to_cpu(header));
}

#define PD_MAX_PAYLOAD 7

struct pd_message {
Expand Down
29 changes: 29 additions & 0 deletions drivers/staging/typec/tcpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ struct tcpm_port {
unsigned int hard_reset_count;
bool pd_capable;
bool explicit_contract;
unsigned int rx_msgid;

/* Partner capabilities/requests */
u32 sink_request;
Expand Down Expand Up @@ -1415,6 +1416,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
break;
case SOFT_RESET_SEND:
port->message_id = 0;
port->rx_msgid = -1;
if (port->pwr_role == TYPEC_SOURCE)
next_state = SRC_SEND_CAPABILITIES;
else
Expand Down Expand Up @@ -1503,6 +1505,22 @@ static void tcpm_pd_rx_handler(struct work_struct *work)
port->attached);

if (port->attached) {
enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
unsigned int msgid = pd_header_msgid_le(msg->header);

/*
* USB PD standard, 6.6.1.2:
* "... if MessageID value in a received Message is the
* same as the stored value, the receiver shall return a
* GoodCRC Message with that MessageID value and drop
* the Message (this is a retry of an already received
* 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)
goto done;
port->rx_msgid = msgid;

/*
* If both ends believe to be DFP/host, we have a data role
* mismatch.
Expand All @@ -1520,6 +1538,7 @@ static void tcpm_pd_rx_handler(struct work_struct *work)
}
}

done:
mutex_unlock(&port->lock);
kfree(event);
}
Expand Down Expand Up @@ -1957,6 +1976,12 @@ static void tcpm_reset_port(struct tcpm_port *port)
port->attached = false;
port->pd_capable = false;

/*
* First Rx ID should be 0; set this to a sentinel of -1 so that
* we can check tcpm_pd_rx_handler() if we had seen it before.
*/
port->rx_msgid = -1;

port->tcpc->set_pd_rx(port->tcpc, false);
tcpm_init_vbus(port); /* also disables charging */
tcpm_init_vconn(port);
Expand Down Expand Up @@ -2170,6 +2195,7 @@ static void run_state_machine(struct tcpm_port *port)
port->pwr_opmode = TYPEC_PWR_MODE_USB;
port->caps_count = 0;
port->message_id = 0;
port->rx_msgid = -1;
port->explicit_contract = false;
tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
break;
Expand Down Expand Up @@ -2329,6 +2355,7 @@ static void run_state_machine(struct tcpm_port *port)
typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB);
port->pwr_opmode = TYPEC_PWR_MODE_USB;
port->message_id = 0;
port->rx_msgid = -1;
port->explicit_contract = false;
tcpm_set_state(port, SNK_DISCOVERY, 0);
break;
Expand Down Expand Up @@ -2496,6 +2523,7 @@ static void run_state_machine(struct tcpm_port *port)
/* Soft_Reset states */
case SOFT_RESET:
port->message_id = 0;
port->rx_msgid = -1;
tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
if (port->pwr_role == TYPEC_SOURCE)
tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
Expand All @@ -2504,6 +2532,7 @@ static void run_state_machine(struct tcpm_port *port)
break;
case SOFT_RESET_SEND:
port->message_id = 0;
port->rx_msgid = -1;
if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET))
tcpm_set_state_cond(port, hard_reset_state(port), 0);
else
Expand Down

0 comments on commit 5fec4b5

Please sign in to comment.