usb: typec: ucsi: rework command execution functions
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Thu, 27 Jun 2024 14:44:43 +0000 (17:44 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jul 2024 14:04:50 +0000 (16:04 +0200)
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@linux.intel.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20240627-ucsi-rework-interface-v4-4-289ddc6874c7@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/ucsi.c

index 17d12c1872f67e1820cb4e184ed953aaa93113e6..10a8fe8933332b916fad2205b863a3cccdfdb1d1 100644 (file)
@@ -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;
 }