diff options
author | Linyu Yuan <quic_linyyuan@quicinc.com> | 2022-04-25 18:18:05 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-04-26 13:44:57 +0200 |
commit | 87d0e2f41b8cc2018499be4e8003fa8c09b6f2fb (patch) | |
tree | 8576bc6fbef62f38225c759bcb9665d58def63b7 /drivers/usb/typec | |
parent | 7a60fa06e80596dba5381fb018f5102ae4897658 (diff) | |
download | linux-87d0e2f41b8cc2018499be4e8003fa8c09b6f2fb.tar.bz2 |
usb: typec: ucsi: add a common function ucsi_unregister_connectors()
In error path of ucsi_init(), it will unregister all valid ucsi connectors,
and similar operation also happen in ucsi_unregister(),
add a common function ucsi_unregister_connectors() for two places,
inside this function, if con->wq is NULL, it will break the loop,
if other kind of error happen after con->wq allocated,
ucsi/typec related API is safe to unregister.
Also in ucsi_init(), it allocate number of (ucsi->cap.num_connectors + 1)
connectors, there is one extra as the ending,
ucsi_unregister_connectors() is safe to unregister all ucsi connectors
according ucsi->cap.num_connectors,
remove the extra one connector to save memory.
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
Link: https://lore.kernel.org/r/1650881886-25530-2-git-send-email-quic_linyyuan@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/typec')
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi.c | 53 |
1 files changed, 29 insertions, 24 deletions
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index f0c2fa19f3e0..a168510675da 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1186,6 +1186,32 @@ out_unlock: return ret; } +static void ucsi_unregister_connectors(struct ucsi *ucsi) +{ + struct ucsi_connector *con; + int i; + + if (!ucsi->connector) + return; + + for (i = 0; i < ucsi->cap.num_connectors; i++) { + con = &ucsi->connector[i]; + + if (!con->wq) + break; + + cancel_work_sync(&con->work); + ucsi_unregister_partner(con); + ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON); + ucsi_unregister_port_psy(con); + destroy_workqueue(con->wq); + typec_unregister_port(con->port); + } + + kfree(ucsi->connector); + ucsi->connector = NULL; +} + /** * ucsi_init - Initialize UCSI interface * @ucsi: UCSI to be initialized @@ -1194,7 +1220,6 @@ out_unlock: */ static int ucsi_init(struct ucsi *ucsi) { - struct ucsi_connector *con; u64 command; int ret; int i; @@ -1225,7 +1250,7 @@ static int ucsi_init(struct ucsi *ucsi) } /* Allocate the connectors. Released in ucsi_unregister() */ - ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1, + ucsi->connector = kcalloc(ucsi->cap.num_connectors, sizeof(*ucsi->connector), GFP_KERNEL); if (!ucsi->connector) { ret = -ENOMEM; @@ -1249,15 +1274,7 @@ static int ucsi_init(struct ucsi *ucsi) return 0; err_unregister: - for (con = ucsi->connector; con->port; con++) { - ucsi_unregister_partner(con); - ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON); - ucsi_unregister_port_psy(con); - if (con->wq) - destroy_workqueue(con->wq); - typec_unregister_port(con->port); - con->port = NULL; - } + ucsi_unregister_connectors(ucsi); err_reset: memset(&ucsi->cap, 0, sizeof(ucsi->cap)); @@ -1363,7 +1380,6 @@ EXPORT_SYMBOL_GPL(ucsi_register); void ucsi_unregister(struct ucsi *ucsi) { u64 cmd = UCSI_SET_NOTIFICATION_ENABLE; - int i; /* Make sure that we are not in the middle of driver initialization */ cancel_work_sync(&ucsi->work); @@ -1371,18 +1387,7 @@ void ucsi_unregister(struct ucsi *ucsi) /* Disable notifications */ ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); - for (i = 0; i < ucsi->cap.num_connectors; i++) { - cancel_work_sync(&ucsi->connector[i].work); - ucsi_unregister_partner(&ucsi->connector[i]); - ucsi_unregister_altmodes(&ucsi->connector[i], - UCSI_RECIPIENT_CON); - ucsi_unregister_port_psy(&ucsi->connector[i]); - if (ucsi->connector[i].wq) - destroy_workqueue(ucsi->connector[i].wq); - typec_unregister_port(ucsi->connector[i].port); - } - - kfree(ucsi->connector); + ucsi_unregister_connectors(ucsi); } EXPORT_SYMBOL_GPL(ucsi_unregister); |