Skip to content

Commit de3d796

Browse files
Heikki Krogerusgregkh
authored andcommitted
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: b9fccfd ("usb: typec: ucsi: Get PD revision for partner") Cc: [email protected] Signed-off-by: Heikki Krogerus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e294092 commit de3d796

File tree

1 file changed

+26
-24
lines changed

1 file changed

+26
-24
lines changed

drivers/usb/typec/ucsi/ucsi.c

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,27 @@ static void ucsi_unregister_cable(struct ucsi_connector *con)
10121012
con->cable = NULL;
10131013
}
10141014

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+
10151036
static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
10161037
{
10171038
switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) {
@@ -1021,6 +1042,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con)
10211042
ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0);
10221043
ucsi_partner_task(con, ucsi_check_altmodes, 30, HZ);
10231044
ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ);
1045+
ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ);
10241046
break;
10251047
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
10261048
con->rdo = 0;
@@ -1064,7 +1086,6 @@ static int ucsi_register_partner(struct ucsi_connector *con)
10641086

10651087
desc.identity = &con->partner_identity;
10661088
desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD;
1067-
desc.pd_revision = UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags);
10681089

10691090
partner = typec_register_partner(con->port, &desc);
10701091
if (IS_ERR(partner)) {
@@ -1141,27 +1162,6 @@ static void ucsi_partner_change(struct ucsi_connector *con)
11411162
con->num, u_role);
11421163
}
11431164

1144-
static int ucsi_check_connector_capability(struct ucsi_connector *con)
1145-
{
1146-
u64 command;
1147-
int ret;
1148-
1149-
if (!con->partner || con->ucsi->version < UCSI_VERSION_2_0)
1150-
return 0;
1151-
1152-
command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num);
1153-
ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap));
1154-
if (ret < 0) {
1155-
dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret);
1156-
return ret;
1157-
}
1158-
1159-
typec_partner_set_pd_revision(con->partner,
1160-
UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags));
1161-
1162-
return ret;
1163-
}
1164-
11651165
static int ucsi_check_connection(struct ucsi_connector *con)
11661166
{
11671167
u8 prev_flags = con->status.flags;
@@ -1283,15 +1283,16 @@ static void ucsi_handle_connector_change(struct work_struct *work)
12831283
if (con->status.flags & UCSI_CONSTAT_CONNECTED) {
12841284
ucsi_register_partner(con);
12851285
ucsi_partner_task(con, ucsi_check_connection, 1, HZ);
1286-
ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ);
12871286
if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE)
12881287
ucsi_partner_task(con, ucsi_get_partner_identity, 1, HZ);
12891288
if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS)
12901289
ucsi_partner_task(con, ucsi_check_cable, 1, HZ);
12911290

12921291
if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) ==
1293-
UCSI_CONSTAT_PWR_OPMODE_PD)
1292+
UCSI_CONSTAT_PWR_OPMODE_PD) {
12941293
ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ);
1294+
ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ);
1295+
}
12951296
} else {
12961297
ucsi_unregister_partner(con);
12971298
}
@@ -1706,6 +1707,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
17061707
ucsi_register_device_pdos(con);
17071708
ucsi_get_src_pdos(con);
17081709
ucsi_check_altmodes(con);
1710+
ucsi_check_connector_capability(con);
17091711
}
17101712

17111713
trace_ucsi_register_port(con->num, &con->status);

0 commit comments

Comments
 (0)