Rework command execution code to remove recursive calls of ucsi_exec_command. This also streamlines the sync_control / read(CCI) read (MESSAGE_IN) sequence, allowing further rework of the command code. Tested-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> Reviewed-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> --- drivers/usb/typec/ucsi/ucsi.c | 138 ++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 17d12c1872f6..10a8fe893333 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -63,27 +63,76 @@ static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack) return ucsi->ops->sync_control(ucsi, ctrl); } -static int ucsi_exec_command(struct ucsi *ucsi, u64 command); +static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size, bool conn_ack) +{ + int ret; + + *cci = 0; + + ret = ucsi->ops->sync_control(ucsi, command); + if (ret) + return ret; + + ret = ucsi->ops->read_cci(ucsi, cci); + if (ret) + return ret; + + if (*cci & UCSI_CCI_BUSY) + return -EBUSY; + + if (!(*cci & UCSI_CCI_COMMAND_COMPLETE)) + return -EIO; + + if (*cci & UCSI_CCI_NOT_SUPPORTED) { + if (ucsi_acknowledge(ucsi, false) < 0) + dev_err(ucsi->dev, + "ACK of unsupported command failed\n"); + return -EOPNOTSUPP; + } + + if (*cci & UCSI_CCI_ERROR) { + /* Acknowledge the command that failed */ + ret = ucsi_acknowledge(ucsi, false); + return ret ? ret : -EIO; + } + + if (data) { + ret = ucsi_read_message_in(ucsi, data, size); + if (ret) + return ret; + } + + ret = ucsi_acknowledge(ucsi, conn_ack); + if (ret) + return ret; + + return 0; +} static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) { u64 command; u16 error; + u32 cci; int ret; command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num); - ret = ucsi_exec_command(ucsi, command); - if (ret < 0) - return ret; + ret = ucsi_run_command(ucsi, command, &cci, + &error, sizeof(error), false); - ret = ucsi_read_message_in(ucsi, &error, sizeof(error)); - if (ret) - return ret; + if (cci & UCSI_CCI_BUSY) { + ret = ucsi_run_command(ucsi, UCSI_CANCEL, &cci, NULL, 0, false); - ret = ucsi_acknowledge(ucsi, false); - if (ret) + return ret ? ret : -EBUSY; + } + + if (ret < 0) return ret; + if (cci & UCSI_CCI_ERROR) + return -EIO; + switch (error) { case UCSI_ERROR_INCOMPATIBLE_PARTNER: return -EOPNOTSUPP; @@ -129,7 +178,8 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) return -EIO; } -static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) +static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, + void *data, size_t size, bool conn_ack) { u8 connector_num; u32 cci; @@ -155,73 +205,17 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) connector_num = 0; } - ret = ucsi->ops->sync_control(ucsi, cmd); - if (ret) - return ret; - - ret = ucsi->ops->read_cci(ucsi, &cci); - if (ret) - return ret; - - if (cmd != UCSI_CANCEL && cci & UCSI_CCI_BUSY) - return ucsi_exec_command(ucsi, UCSI_CANCEL); - - if (!(cci & UCSI_CCI_COMMAND_COMPLETE)) - return -EIO; - - if (cci & UCSI_CCI_NOT_SUPPORTED) { - if (ucsi_acknowledge(ucsi, false) < 0) - dev_err(ucsi->dev, - "ACK of unsupported command failed\n"); - return -EOPNOTSUPP; - } - - if (cci & UCSI_CCI_ERROR) { - /* Acknowledge the command that failed */ - ret = ucsi_acknowledge(ucsi, false); - if (ret) - return ret; - - if (cmd == UCSI_GET_ERROR_STATUS) - return -EIO; - - return ucsi_read_error(ucsi, connector_num); - } - - if (cmd == UCSI_CANCEL && cci & UCSI_CCI_CANCEL_COMPLETE) { - ret = ucsi_acknowledge(ucsi, false); - return ret ? ret : -EBUSY; - } - - return UCSI_CCI_LENGTH(cci); -} - -static int ucsi_send_command_common(struct ucsi *ucsi, u64 command, - void *data, size_t size, bool conn_ack) -{ - u8 length; - int ret; - mutex_lock(&ucsi->ppm_lock); - ret = ucsi_exec_command(ucsi, command); - if (ret < 0) - goto out; - - length = ret; - - if (data) { - ret = ucsi_read_message_in(ucsi, data, size); - if (ret) - goto out; + ret = ucsi_run_command(ucsi, cmd, &cci, data, size, conn_ack); + if (cci & UCSI_CCI_BUSY) { + ret = ucsi_run_command(ucsi, UCSI_CANCEL, &cci, NULL, 0, false); + return ret ? ret : -EBUSY; } - ret = ucsi_acknowledge(ucsi, conn_ack); - if (ret) - goto out; + if (cci & UCSI_CCI_ERROR) + return ucsi_read_error(ucsi, connector_num); - ret = length; -out: mutex_unlock(&ucsi->ppm_lock); return ret; } -- 2.39.2