aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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