usb: typec: ucsi: Fix the partner PD revision

The Partner PD Revision field in GET_CONNECTOR_CAPABILITY
data structure was introduced in UCSI v2.1. In
ucsi_check_connector_capability() the version was assumed to
be 2.0, and in ucsi_register_partner() the field is accessed
completely unconditionally.

Fixing the version in ucsi_check_connector_capability(), and
replacing the unconditional pd_revision assignment with a
direct call to ucsi_check_connector_capability() in
ucsi_register_port(). After this the revision is also
checked only if there is a PD contract.

Fixes: b9fccfdb4ebb ("usb: typec: ucsi: Get PD revision for partner")
Cc: stable@vger.kernel.org
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20240830111645.2134301-1-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by Heikki Krogerus and committed by Greg Kroah-Hartman de3d7969 e2940928

+26 -24
+26 -24
drivers/usb/typec/ucsi/ucsi.c
··· 1012 con->cable = NULL; 1013 } 1014 1015 static void ucsi_pwr_opmode_change(struct ucsi_connector *con) 1016 { 1017 switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { ··· 1042 ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0); 1043 ucsi_partner_task(con, ucsi_check_altmodes, 30, HZ); 1044 ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); 1045 break; 1046 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 1047 con->rdo = 0; ··· 1086 1087 desc.identity = &con->partner_identity; 1088 desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; 1089 - desc.pd_revision = UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags); 1090 1091 partner = typec_register_partner(con->port, &desc); 1092 if (IS_ERR(partner)) { ··· 1160 if (ret) 1161 dev_err(con->ucsi->dev, "con:%d: failed to set usb role:%d\n", 1162 con->num, u_role); 1163 - } 1164 - 1165 - static int ucsi_check_connector_capability(struct ucsi_connector *con) 1166 - { 1167 - u64 command; 1168 - int ret; 1169 - 1170 - if (!con->partner || con->ucsi->version < UCSI_VERSION_2_0) 1171 - return 0; 1172 - 1173 - command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); 1174 - ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap)); 1175 - if (ret < 0) { 1176 - dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); 1177 - return ret; 1178 - } 1179 - 1180 - typec_partner_set_pd_revision(con->partner, 1181 - UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags)); 1182 - 1183 - return ret; 1184 } 1185 1186 static int ucsi_check_connection(struct ucsi_connector *con) ··· 1283 if (con->status.flags & UCSI_CONSTAT_CONNECTED) { 1284 ucsi_register_partner(con); 1285 ucsi_partner_task(con, ucsi_check_connection, 1, HZ); 1286 - ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); 1287 if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) 1288 ucsi_partner_task(con, ucsi_get_partner_identity, 1, HZ); 1289 if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) 1290 ucsi_partner_task(con, ucsi_check_cable, 1, HZ); 1291 1292 if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == 1293 - UCSI_CONSTAT_PWR_OPMODE_PD) 1294 ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); 1295 } else { 1296 ucsi_unregister_partner(con); 1297 } ··· 1707 ucsi_register_device_pdos(con); 1708 ucsi_get_src_pdos(con); 1709 ucsi_check_altmodes(con); 1710 } 1711 1712 trace_ucsi_register_port(con->num, &con->status);
··· 1012 con->cable = NULL; 1013 } 1014 1015 + static int ucsi_check_connector_capability(struct ucsi_connector *con) 1016 + { 1017 + u64 command; 1018 + int ret; 1019 + 1020 + if (!con->partner || con->ucsi->version < UCSI_VERSION_2_1) 1021 + return 0; 1022 + 1023 + command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); 1024 + ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap)); 1025 + if (ret < 0) { 1026 + dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); 1027 + return ret; 1028 + } 1029 + 1030 + typec_partner_set_pd_revision(con->partner, 1031 + UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags)); 1032 + 1033 + return ret; 1034 + } 1035 + 1036 static void ucsi_pwr_opmode_change(struct ucsi_connector *con) 1037 { 1038 switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { ··· 1021 ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0); 1022 ucsi_partner_task(con, ucsi_check_altmodes, 30, HZ); 1023 ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); 1024 + ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); 1025 break; 1026 case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5: 1027 con->rdo = 0; ··· 1064 1065 desc.identity = &con->partner_identity; 1066 desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; 1067 1068 partner = typec_register_partner(con->port, &desc); 1069 if (IS_ERR(partner)) { ··· 1139 if (ret) 1140 dev_err(con->ucsi->dev, "con:%d: failed to set usb role:%d\n", 1141 con->num, u_role); 1142 } 1143 1144 static int ucsi_check_connection(struct ucsi_connector *con) ··· 1283 if (con->status.flags & UCSI_CONSTAT_CONNECTED) { 1284 ucsi_register_partner(con); 1285 ucsi_partner_task(con, ucsi_check_connection, 1, HZ); 1286 if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) 1287 ucsi_partner_task(con, ucsi_get_partner_identity, 1, HZ); 1288 if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) 1289 ucsi_partner_task(con, ucsi_check_cable, 1, HZ); 1290 1291 if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == 1292 + UCSI_CONSTAT_PWR_OPMODE_PD) { 1293 ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); 1294 + ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); 1295 + } 1296 } else { 1297 ucsi_unregister_partner(con); 1298 } ··· 1706 ucsi_register_device_pdos(con); 1707 ucsi_get_src_pdos(con); 1708 ucsi_check_altmodes(con); 1709 + ucsi_check_connector_capability(con); 1710 } 1711 1712 trace_ucsi_register_port(con->num, &con->status);