> From: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > Sent: Wednesday, April 13, 2022 8:09 PM > To: Linyu Yuan (QUIC) <quic_linyyuan@xxxxxxxxxxx> > Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>; linux- > usb@xxxxxxxxxxxxxxx; Jack Pham (QUIC) <quic_jackp@xxxxxxxxxxx> > Subject: Re: [PATCH v3 2/4] usb: typec: ucsi: add a common function > ucsi_unregister_connectors() > > On Wed, Apr 13, 2022 at 05:58:09PM +0800, Linyu Yuan wrote: > > In error path of ucsi_init(), it will unregister all valid ucsi connector, > > and samiliar operation also happen in ucsi_unregister(), > > Sorry but I have to confirm this: with "samiliar" you mean "the same", > right? Only one small difference for original code which is no cancel_work_sync() of each connector in ucsi _init(), But in ucsi_register_port(), we get role switch after connector work initialized, So I think it is safe to call cancel_work_sync() to connector work if role switch return -EPROBE_DEFER. > > > add a common function for two places. > > > > Signed-off-by: Linyu Yuan <quic_linyyuan@xxxxxxxxxxx> > > --- > > v2: improve ucsi_connector_clean(), check total number of connector. > > v3: rename to ucsi_unregister_connectors(), suggest by maintainer > > > > drivers/usb/typec/ucsi/ucsi.c | 51 ++++++++++++++++++++++++----------- > -------- > > 1 file changed, 28 insertions(+), 23 deletions(-) > > > > diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c > > index 77ac0b7..af9a2a1 100644 > > --- a/drivers/usb/typec/ucsi/ucsi.c > > +++ b/drivers/usb/typec/ucsi/ucsi.c > > @@ -1187,6 +1187,32 @@ static int ucsi_register_port(struct ucsi *ucsi, int > index) > > return ret; > > } > > > > +static void ucsi_unregister_connectors(struct ucsi *ucsi) > > +{ > > + struct ucsi_connector *con; > > + int i; > > + > > + if (!ucsi->connector) > > + return; > > Can that actually ever happen? Consider a case, ucsi_init() failed, we will call ucsi_unregister_connectors() to free all connectors, After that the UCSI implementation like ucsi_acpi call ucsi_unregister() again, It should not unregister connectors again. > > > + for (i = 0; i < ucsi->cap.num_connectors; i++) { > > + con = &ucsi->connector[i]; > > + if (!con->port) > > + break; > > + > > + cancel_work_sync(&con->work); > > + 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); > > + } > > + > > + kfree(ucsi->connector); > > + ucsi->connector = NULL; > > +} > > Another way of doing this would be to just remove a single connector > in the function, and leave the loops to the callers. > > static void ucsi_unregister_connector(struct ucsi_connector *con) > { > cancel_work_sync(&con->work); > 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); > } > > I wonder would it actually be a bit more clearer to do it like that... > I'll leave the decision to you. I will keep it, There will be no duplicate loop entry in two function, a little lazy. > > > /** > > * ucsi_init - Initialize UCSI interface > > * @ucsi: UCSI to be initialized > > @@ -1195,7 +1221,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int > index) > > */ > > static int ucsi_init(struct ucsi *ucsi) > > { > > - struct ucsi_connector *con; > > u64 command; > > int ret; > > int i; > > @@ -1250,15 +1275,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)); > > @@ -1364,7 +1381,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); > > @@ -1372,18 +1388,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); > > thanks, > > -- > heikki