aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2017-05-09 12:04:56 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-15 05:23:55 -0400
commit5fec4b54d0bf6c3eeb176b624ce50d6aef4819c0 (patch)
tree88c039c5bbe1f161d1972764793ac85a60fae87a
parentaac53ee4557947d778cb6a255c719e5c70963c42 (diff)
staging: typec: tcpm: Drop duplicate PD messages
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>
-rw-r--r--drivers/staging/typec/pd.h10
-rw-r--r--drivers/staging/typec/tcpm.c29
2 files changed, 39 insertions, 0 deletions
diff --git a/drivers/staging/typec/pd.h b/drivers/staging/typec/pd.h
index 8d97bdb95f23..510ef7279900 100644
--- a/drivers/staging/typec/pd.h
+++ b/drivers/staging/typec/pd.h
@@ -92,6 +92,16 @@ static inline unsigned int pd_header_type_le(__le16 header)
92 return pd_header_type(le16_to_cpu(header)); 92 return pd_header_type(le16_to_cpu(header));
93} 93}
94 94
95static inline unsigned int pd_header_msgid(u16 header)
96{
97 return (header >> PD_HEADER_ID_SHIFT) & PD_HEADER_ID_MASK;
98}
99
100static inline unsigned int pd_header_msgid_le(__le16 header)
101{
102 return pd_header_msgid(le16_to_cpu(header));
103}
104
95#define PD_MAX_PAYLOAD 7 105#define PD_MAX_PAYLOAD 7
96 106
97struct pd_message { 107struct pd_message {
diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c
index abba655ba00a..c5d8b129c4f4 100644
--- a/drivers/staging/typec/tcpm.c
+++ b/drivers/staging/typec/tcpm.c
@@ -238,6 +238,7 @@ struct tcpm_port {
238 unsigned int hard_reset_count; 238 unsigned int hard_reset_count;
239 bool pd_capable; 239 bool pd_capable;
240 bool explicit_contract; 240 bool explicit_contract;
241 unsigned int rx_msgid;
241 242
242 /* Partner capabilities/requests */ 243 /* Partner capabilities/requests */
243 u32 sink_request; 244 u32 sink_request;
@@ -1415,6 +1416,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
1415 break; 1416 break;
1416 case SOFT_RESET_SEND: 1417 case SOFT_RESET_SEND:
1417 port->message_id = 0; 1418 port->message_id = 0;
1419 port->rx_msgid = -1;
1418 if (port->pwr_role == TYPEC_SOURCE) 1420 if (port->pwr_role == TYPEC_SOURCE)
1419 next_state = SRC_SEND_CAPABILITIES; 1421 next_state = SRC_SEND_CAPABILITIES;
1420 else 1422 else
@@ -1503,6 +1505,22 @@ static void tcpm_pd_rx_handler(struct work_struct *work)
1503 port->attached); 1505 port->attached);
1504 1506
1505 if (port->attached) { 1507 if (port->attached) {
1508 enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
1509 unsigned int msgid = pd_header_msgid_le(msg->header);
1510
1511 /*
1512 * USB PD standard, 6.6.1.2:
1513 * "... if MessageID value in a received Message is the
1514 * same as the stored value, the receiver shall return a
1515 * GoodCRC Message with that MessageID value and drop
1516 * the Message (this is a retry of an already received
1517 * Message). Note: this shall not apply to the Soft_Reset
1518 * Message which always has a MessageID value of zero."
1519 */
1520 if (msgid == port->rx_msgid && type != PD_CTRL_SOFT_RESET)
1521 goto done;
1522 port->rx_msgid = msgid;
1523
1506 /* 1524 /*
1507 * If both ends believe to be DFP/host, we have a data role 1525 * If both ends believe to be DFP/host, we have a data role
1508 * mismatch. 1526 * mismatch.
@@ -1520,6 +1538,7 @@ static void tcpm_pd_rx_handler(struct work_struct *work)
1520 } 1538 }
1521 } 1539 }
1522 1540
1541done:
1523 mutex_unlock(&port->lock); 1542 mutex_unlock(&port->lock);
1524 kfree(event); 1543 kfree(event);
1525} 1544}
@@ -1957,6 +1976,12 @@ static void tcpm_reset_port(struct tcpm_port *port)
1957 port->attached = false; 1976 port->attached = false;
1958 port->pd_capable = false; 1977 port->pd_capable = false;
1959 1978
1979 /*
1980 * First Rx ID should be 0; set this to a sentinel of -1 so that
1981 * we can check tcpm_pd_rx_handler() if we had seen it before.
1982 */
1983 port->rx_msgid = -1;
1984
1960 port->tcpc->set_pd_rx(port->tcpc, false); 1985 port->tcpc->set_pd_rx(port->tcpc, false);
1961 tcpm_init_vbus(port); /* also disables charging */ 1986 tcpm_init_vbus(port); /* also disables charging */
1962 tcpm_init_vconn(port); 1987 tcpm_init_vconn(port);
@@ -2170,6 +2195,7 @@ static void run_state_machine(struct tcpm_port *port)
2170 port->pwr_opmode = TYPEC_PWR_MODE_USB; 2195 port->pwr_opmode = TYPEC_PWR_MODE_USB;
2171 port->caps_count = 0; 2196 port->caps_count = 0;
2172 port->message_id = 0; 2197 port->message_id = 0;
2198 port->rx_msgid = -1;
2173 port->explicit_contract = false; 2199 port->explicit_contract = false;
2174 tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); 2200 tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
2175 break; 2201 break;
@@ -2329,6 +2355,7 @@ static void run_state_machine(struct tcpm_port *port)
2329 typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB); 2355 typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB);
2330 port->pwr_opmode = TYPEC_PWR_MODE_USB; 2356 port->pwr_opmode = TYPEC_PWR_MODE_USB;
2331 port->message_id = 0; 2357 port->message_id = 0;
2358 port->rx_msgid = -1;
2332 port->explicit_contract = false; 2359 port->explicit_contract = false;
2333 tcpm_set_state(port, SNK_DISCOVERY, 0); 2360 tcpm_set_state(port, SNK_DISCOVERY, 0);
2334 break; 2361 break;
@@ -2496,6 +2523,7 @@ static void run_state_machine(struct tcpm_port *port)
2496 /* Soft_Reset states */ 2523 /* Soft_Reset states */
2497 case SOFT_RESET: 2524 case SOFT_RESET:
2498 port->message_id = 0; 2525 port->message_id = 0;
2526 port->rx_msgid = -1;
2499 tcpm_pd_send_control(port, PD_CTRL_ACCEPT); 2527 tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
2500 if (port->pwr_role == TYPEC_SOURCE) 2528 if (port->pwr_role == TYPEC_SOURCE)
2501 tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); 2529 tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
@@ -2504,6 +2532,7 @@ static void run_state_machine(struct tcpm_port *port)
2504 break; 2532 break;
2505 case SOFT_RESET_SEND: 2533 case SOFT_RESET_SEND:
2506 port->message_id = 0; 2534 port->message_id = 0;
2535 port->rx_msgid = -1;
2507 if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET)) 2536 if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET))
2508 tcpm_set_state_cond(port, hard_reset_state(port), 0); 2537 tcpm_set_state_cond(port, hard_reset_state(port), 0);
2509 else 2538 else