summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarthikeyan Ramasubramanian <kramasub@chromium.org>2019-03-01 16:52:26 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-03-28 14:13:58 -0700
commit316cf2a3afee7f0ebfa39f32d394220974539c67 (patch)
tree74928d16435f9f5c7670aec39b8d7b116600c4c3
parente3e9d6ab178738f354d4615dab7d28af0b139384 (diff)
downloadchrome-ec-316cf2a3afee7f0ebfa39f32d394220974539c67.tar.gz
common/usb_pd_tcpc: Ignore repeat messages
Sometimes messages with the same ID are retransmitted at the physical layer. Under such scenario do not handle the repeat messages. BUG=b:129337537 BRANCH=None TEST=make -j buildall; Ensure that the DUT boots to ChromeOS. Ensure that the servo_v4 boots fine. Ensure that the DUT boots fine in normal mode and recovery mode with and without battery. Ensure that the repeat request messages triggered aritificially are dropped without any side-effects. Ensure that the DUT is detected in CCD with pass-through connected after multiple EC reboots, servo_v4 reboots and USB-C unplug/replug procedure. Change-Id: I850cd3536ff5e62c34f9dabcc0f8f53bb196ce4c Signed-off-by: Karthikeyan Ramasubramanian <kramasub@google.com> Reviewed-on: https://chromium-review.googlesource.com/1513033 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Karthikeyan Ramasubramanian <kramasub@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r--common/usb_pd_protocol.c23
-rw-r--r--common/usb_pd_tcpc.c31
-rw-r--r--include/usb_pd_tcpc.h18
3 files changed, 70 insertions, 2 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index a00b28bd6b..2782dee5ec 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -25,6 +25,7 @@
#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
+#include "usb_pd_tcpc.h"
#include "usbc_ppc.h"
#include "tcpm.h"
#include "version.h"
@@ -746,6 +747,14 @@ static inline void set_state(int port, enum pd_states next_state)
/* Disable TCPC RX */
tcpm_set_rx_enable(port, 0);
+#ifdef CONFIG_USB_PD_TCPC
+ /*
+ * Invalidate message IDs for PD_TCPC only, since off-board
+ * TCPCs will automatically perform message id de-dup logic
+ * without manual intervention.
+ */
+ invalidate_last_message_id(port);
+#endif /* CONFIG_USB_PD_TCPC */
#ifdef CONFIG_COMMON_RUNTIME
/* detect USB PD cc disconnect */
hook_notify(HOOK_USB_PD_DISCONNECT);
@@ -2938,8 +2947,18 @@ void pd_task(void *u)
/* process any potential incoming message */
incoming_packet = tcpm_has_pending_message(port);
if (incoming_packet) {
- tcpm_dequeue_message(port, payload, &head);
- handle_request(port, head, payload);
+ /*
+ * Dequeue and consume duplicate message ID for PD_TCPC
+ * only, since off-board TCPCs will automatically
+ * perform this de-dup logic before notifying the EC.
+ */
+ if (tcpm_dequeue_message(port, payload, &head) ==
+ EC_SUCCESS
+#ifdef CONFIG_USB_PD_TCPC
+ && !consume_repeat_message(port, head)
+#endif
+ )
+ handle_request(port, head, payload);
/* Check if there are any more messages */
if (tcpm_has_pending_message(port))
diff --git a/common/usb_pd_tcpc.c b/common/usb_pd_tcpc.c
index 0feabb5b10..83a1569223 100644
--- a/common/usb_pd_tcpc.c
+++ b/common/usb_pd_tcpc.c
@@ -257,6 +257,7 @@ static struct pd_port_controller {
int rx_head[RX_BUFFER_SIZE+1];
uint32_t rx_payload[RX_BUFFER_SIZE+1][7];
int rx_buf_head, rx_buf_tail;
+ uint8_t msg_id_last;
/* Next transmit */
enum tcpm_transmit_type tx_type;
@@ -265,6 +266,34 @@ static struct pd_port_controller {
const uint32_t *tx_data;
} pd[CONFIG_USB_PD_PORT_COUNT];
+void invalidate_last_message_id(int port)
+{
+ /*
+ * Message id starts from 0 to 7. If msg_id_last is initialized to 0,
+ * it will lead to repetitive message id with first received packet,
+ * so initialize it with an invalid value 0xff.
+ */
+ pd[port].msg_id_last = 0xff;
+}
+
+int consume_repeat_message(int port, uint16_t msg_header)
+{
+ uint8_t msg_id = PD_HEADER_ID(msg_header);
+
+ /* If repeat message ignore, except softreset control request. */
+ if (PD_HEADER_TYPE(msg_header) == PD_CTRL_SOFT_RESET &&
+ PD_HEADER_CNT(msg_header) == 0) {
+ invalidate_last_message_id(port);
+ } else if (pd[port].msg_id_last != msg_id) {
+ pd[port].msg_id_last = msg_id;
+ } else if (pd[port].msg_id_last == msg_id) {
+ CPRINTF("Repeat msg_id[%d] port[%d]\n", msg_id, port);
+ return 1;
+ }
+
+ return 0;
+}
+
static int rx_buf_is_full(int port)
{
/*
@@ -643,6 +672,7 @@ int pd_analyze_rx(int port, uint32_t *payload)
bit = pd_find_preamble(port);
if (bit == PD_RX_ERR_HARD_RESET || bit == PD_RX_ERR_CABLE_RESET) {
/* Hard reset or cable reset */
+ invalidate_last_message_id(port);
return bit;
} else if (bit < 0) {
msg = "Preamble";
@@ -1160,6 +1190,7 @@ void tcpc_init(int port)
/* make sure PD monitoring is disabled initially */
pd[port].rx_enabled = 0;
+ invalidate_last_message_id(port);
/* make initial readings of CC voltages */
for (i = 0; i < 2; i++) {
diff --git a/include/usb_pd_tcpc.h b/include/usb_pd_tcpc.h
index 812a194a85..f5785921a4 100644
--- a/include/usb_pd_tcpc.h
+++ b/include/usb_pd_tcpc.h
@@ -60,4 +60,22 @@ int tcpc_transmit(int port, enum tcpm_transmit_type type, uint16_t header,
int rx_buf_is_empty(int port);
void rx_buf_clear(int port);
+/**
+ * Invalidate last message received at the port when the port gets disconnected
+ * or reset(soft/hard). This is used to identify and handle the duplicate
+ * messages.
+ *
+ * @param port USB PD TCPC port number
+ */
+void invalidate_last_message_id(int port);
+
+/**
+ * Identify and drop any duplicate messages received at the port.
+ *
+ * @param port USB PD TCPC port number
+ * @param msg_header Message Header containing the RX message ID
+ * @return 1 if the received message is a duplicate one, 0 otherwise.
+ */
+int consume_repeat_message(int port, uint16_t msg_header);
+
#endif /* __CROS_EC_USB_PD_TCPC_H */