From ccfa18feff26211631be53fe1db1b8b0b534cd79 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Thu, 26 Apr 2018 12:59:58 -0700 Subject: [PATCH] cros-ec: Avoid infinitely looping in google_chromeec_pd_get_amode Currently, google_chromeec_pd_get_amode infinitely loops if a TCPC port is connected to a device with alternate mode(s) and the call is made for the mode with the index higher than 0 (e.g. Zinger). Cros EC manages alternative modes entered in an array (amode[]). The command is designed to accept a query for an particular index and a particular SVID. Zinger has a 'Google' mode. It's stored in amode[0]. When AP queries first time for DisplayPort with index=0, EC says 'no' as expected. AP sends the next query with index=1 but EC_CMD_PROTO_VERSION (0x00) is sent instead because cmd_code is cleared by google_chromeec_command. res.svid is supposed to be 0 when EC hits the last index + 1 but res.svid is set to 2 by the EC_CMD_PROTO_VERSION handler because EC_PROTO_VERSION is currently 2. So, the call succeeds and AP goes to the next index and this repeats forever. Any USB-C device with non-DisplayPort alternate mode can cause this hang unless HDMI port is used. This patch resets all the fields of chromeec_command in each iteration in case google_chromeec_command changes them. BUG=b:78630899 BRANCH=none TEST=Verify Fizz boots without monitors on Zinger. Verify the svid enumeration happens as expected. Change-Id: I388ed4bdfac9176d8e690c429e99674ed267004f Signed-off-by: Daisuke Nojiri Reviewed-on: https://review.coreboot.org/25878 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin Reviewed-by: Furquan Shaikh --- src/ec/google/chromeec/ec.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/ec/google/chromeec/ec.c b/src/ec/google/chromeec/ec.c index fb3ffab181..5ce3f68823 100644 --- a/src/ec/google/chromeec/ec.c +++ b/src/ec/google/chromeec/ec.c @@ -963,23 +963,26 @@ int google_chromeec_pd_get_amode(uint16_t svid) for (i = 0; i < r.num_ports; i++) { struct ec_params_usb_pd_get_mode_request p; struct ec_params_usb_pd_get_mode_response res; - - p.port = i; - p.svid_idx = 0; - cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE; - cmd.cmd_version = 0; - cmd.cmd_data_in = &p; - cmd.cmd_size_in = sizeof(p); - cmd.cmd_data_out = &res; - cmd.cmd_size_out = sizeof(res); - cmd.cmd_dev_index = 0; + int svid_idx = 0; do { + /* Reset cmd in each iteration in case + google_chromeec_command changes it. */ + p.port = i; + p.svid_idx = svid_idx; + cmd.cmd_code = EC_CMD_USB_PD_GET_AMODE; + cmd.cmd_version = 0; + cmd.cmd_data_in = &p; + cmd.cmd_size_in = sizeof(p); + cmd.cmd_data_out = &res; + cmd.cmd_size_out = sizeof(res); + cmd.cmd_dev_index = 0; + if (google_chromeec_command(&cmd) < 0) return -1; if (res.svid == svid) return 1; - p.svid_idx++; + svid_idx++; } while (res.svid); }