Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: ucsi: Hold con->lock for the entire duration of ucsi_register_port()

Commit 081da1325d35 ("usb: typec: ucsi: displayport: Fix a potential race
during registration") made the ucsi code hold con->lock in
ucsi_register_displayport(). But we really don't want any interactions
with the connector to run before the port-registration process is fully
complete.

This commit moves the taking of con->lock from ucsi_register_displayport()
into ucsi_register_port() to achieve this.

Cc: stable@vger.kernel.org
Fixes: 081da1325d35 ("usb: typec: ucsi: displayport: Fix a potential race during registration")
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20200809141904.4317-5-hdegoede@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Hans de Goede and committed by
Greg Kroah-Hartman
bed97b30 25794e30

+23 -17
+1 -8
drivers/usb/typec/ucsi/displayport.c
··· 288 288 struct typec_altmode *alt; 289 289 struct ucsi_dp *dp; 290 290 291 - mutex_lock(&con->lock); 292 - 293 291 /* We can't rely on the firmware with the capabilities. */ 294 292 desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE; 295 293 ··· 296 298 desc->vdo |= all_assignments << 16; 297 299 298 300 alt = typec_port_register_altmode(con->port, desc); 299 - if (IS_ERR(alt)) { 300 - mutex_unlock(&con->lock); 301 + if (IS_ERR(alt)) 301 302 return alt; 302 - } 303 303 304 304 dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); 305 305 if (!dp) { 306 306 typec_unregister_altmode(alt); 307 - mutex_unlock(&con->lock); 308 307 return ERR_PTR(-ENOMEM); 309 308 } 310 309 ··· 313 318 314 319 alt->ops = &ucsi_displayport_ops; 315 320 typec_altmode_set_drvdata(alt, dp); 316 - 317 - mutex_unlock(&con->lock); 318 321 319 322 return alt; 320 323 }
+22 -9
drivers/usb/typec/ucsi/ucsi.c
··· 898 898 con->num = index + 1; 899 899 con->ucsi = ucsi; 900 900 901 + /* Delay other interactions with the con until registration is complete */ 902 + mutex_lock(&con->lock); 903 + 901 904 /* Get connector capability */ 902 905 command = UCSI_GET_CONNECTOR_CAPABILITY; 903 906 command |= UCSI_CONNECTOR_NUMBER(con->num); 904 907 ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap)); 905 908 if (ret < 0) 906 - return ret; 909 + goto out; 907 910 908 911 if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP) 909 912 cap->data = TYPEC_PORT_DRD; ··· 938 935 939 936 ret = ucsi_register_port_psy(con); 940 937 if (ret) 941 - return ret; 938 + goto out; 942 939 943 940 /* Register the connector */ 944 941 con->port = typec_register_port(ucsi->dev, cap); 945 - if (IS_ERR(con->port)) 946 - return PTR_ERR(con->port); 942 + if (IS_ERR(con->port)) { 943 + ret = PTR_ERR(con->port); 944 + goto out; 945 + } 947 946 948 947 /* Alternate modes */ 949 948 ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); 950 - if (ret) 949 + if (ret) { 951 950 dev_err(ucsi->dev, "con%d: failed to register alt modes\n", 952 951 con->num); 952 + goto out; 953 + } 953 954 954 955 /* Get the status */ 955 956 command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); 956 957 ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status)); 957 958 if (ret < 0) { 958 959 dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); 959 - return 0; 960 + ret = 0; 961 + goto out; 960 962 } 963 + ret = 0; /* ucsi_send_command() returns length on success */ 961 964 962 965 switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { 963 966 case UCSI_CONSTAT_PARTNER_TYPE_UFP: ··· 988 979 989 980 if (con->partner) { 990 981 ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); 991 - if (ret) 982 + if (ret) { 992 983 dev_err(ucsi->dev, 993 984 "con%d: failed to register alternate modes\n", 994 985 con->num); 995 - else 986 + ret = 0; 987 + } else { 996 988 ucsi_altmode_update_active(con); 989 + } 997 990 } 998 991 999 992 trace_ucsi_register_port(con->num, &con->status); 1000 993 1001 - return 0; 994 + out: 995 + mutex_unlock(&con->lock); 996 + return ret; 1002 997 } 1003 998 1004 999 /**