]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
i3c: mipi-i3c-hci: Consolidate common xfer processing logic
authorAdrian Hunter <adrian.hunter@intel.com>
Fri, 6 Mar 2026 07:24:48 +0000 (09:24 +0200)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Wed, 11 Mar 2026 21:10:02 +0000 (22:10 +0100)
Several parts of the MIPI I3C HCI driver duplicate the same sequence for
queuing a transfer, waiting for completion, and handling timeouts. This
logic appears in five separate locations and will be affected by an
upcoming fix.

Refactor the repeated code into a new helper, i3c_hci_process_xfer(), and
store the timeout value in the hci_xfer structure so that callers do not
need to pass it as a separate parameter.

Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260306072451.11131-12-adrian.hunter@intel.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
drivers/i3c/master/mipi-i3c-hci/core.c
drivers/i3c/master/mipi-i3c-hci/hci.h

index 831a261f6c5675a8b05e4fc6835d4771da5bab79..75d452d7f6af88964247f7ca25aed35bc5142a07 100644 (file)
@@ -331,12 +331,10 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
                        CMD_A0_ROC | CMD_A0_TOC;
                xfer->cmd_desc[1] = 0;
                xfer->completion = &done;
-               hci->io->queue_xfer(hci, xfer, 1);
-               if (!wait_for_completion_timeout(&done, HZ) &&
-                   hci->io->dequeue_xfer(hci, xfer, 1)) {
-                       ret = -ETIMEDOUT;
+               xfer->timeout = HZ;
+               ret = i3c_hci_process_xfer(hci, xfer, 1);
+               if (ret)
                        break;
-               }
                if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
                     RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
                    RESP_DATA_LENGTH(xfer->response) == 1) {
index 054beee36da52af3b76133e89348e814490cb23a..39eec26a363c7b6bb2ad52ff16efc4f0c5707e7a 100644 (file)
@@ -253,6 +253,7 @@ static int hci_cmd_v2_daa(struct i3c_hci *hci)
        xfer[0].rnw = true;
        xfer[0].cmd_desc[1] = CMD_A1_DATA_LENGTH(8);
        xfer[1].completion = &done;
+       xfer[1].timeout = HZ;
 
        for (;;) {
                ret = i3c_master_get_free_addr(&hci->master, next_addr);
@@ -272,12 +273,9 @@ static int hci_cmd_v2_daa(struct i3c_hci *hci)
                        CMD_A0_ASSIGN_ADDRESS(next_addr) |
                        CMD_A0_ROC |
                        CMD_A0_TOC;
-               hci->io->queue_xfer(hci, xfer, 2);
-               if (!wait_for_completion_timeout(&done, HZ) &&
-                   hci->io->dequeue_xfer(hci, xfer, 2)) {
-                       ret = -ETIMEDOUT;
+               ret = i3c_hci_process_xfer(hci, xfer, 2);
+               if (ret)
                        break;
-               }
                if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
                        ret = 0;  /* no more devices to be assigned */
                        break;
index adf35b7fa498d44a692312b9ee05e85657badc00..4a80671536f0a3bd0fa85a93f4d7f86a041fa2a8 100644 (file)
@@ -213,6 +213,25 @@ void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci)
        reg_write(DCT_SECTION, FIELD_PREP(DCT_TABLE_INDEX, 0));
 }
 
+int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
+{
+       struct completion *done = xfer[n - 1].completion;
+       unsigned long timeout = xfer[n - 1].timeout;
+       int ret;
+
+       ret = hci->io->queue_xfer(hci, xfer, n);
+       if (ret)
+               return ret;
+
+       if (!wait_for_completion_timeout(done, timeout) &&
+           hci->io->dequeue_xfer(hci, xfer, n)) {
+               dev_err(&hci->master.dev, "%s: timeout error\n", __func__);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
                                struct i3c_ccc_cmd *ccc)
 {
@@ -253,18 +272,14 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
        last = i - 1;
        xfer[last].cmd_desc[0] |= CMD_0_TOC;
        xfer[last].completion = &done;
+       xfer[last].timeout = HZ;
 
        if (prefixed)
                xfer--;
 
-       ret = hci->io->queue_xfer(hci, xfer, nxfers);
+       ret = i3c_hci_process_xfer(hci, xfer, nxfers);
        if (ret)
                goto out;
-       if (!wait_for_completion_timeout(&done, HZ) &&
-           hci->io->dequeue_xfer(hci, xfer, nxfers)) {
-               ret = -ETIMEDOUT;
-               goto out;
-       }
        for (i = prefixed; i < nxfers; i++) {
                if (ccc->rnw)
                        ccc->dests[i - prefixed].payload.len =
@@ -335,15 +350,11 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
        last = i - 1;
        xfer[last].cmd_desc[0] |= CMD_0_TOC;
        xfer[last].completion = &done;
+       xfer[last].timeout = HZ;
 
-       ret = hci->io->queue_xfer(hci, xfer, nxfers);
+       ret = i3c_hci_process_xfer(hci, xfer, nxfers);
        if (ret)
                goto out;
-       if (!wait_for_completion_timeout(&done, HZ) &&
-           hci->io->dequeue_xfer(hci, xfer, nxfers)) {
-               ret = -ETIMEDOUT;
-               goto out;
-       }
        for (i = 0; i < nxfers; i++) {
                if (i3c_xfers[i].rnw)
                        i3c_xfers[i].len = RESP_DATA_LENGTH(xfer[i].response);
@@ -383,15 +394,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
        last = i - 1;
        xfer[last].cmd_desc[0] |= CMD_0_TOC;
        xfer[last].completion = &done;
+       xfer[last].timeout = m->i2c.timeout;
 
-       ret = hci->io->queue_xfer(hci, xfer, nxfers);
+       ret = i3c_hci_process_xfer(hci, xfer, nxfers);
        if (ret)
                goto out;
-       if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
-           hci->io->dequeue_xfer(hci, xfer, nxfers)) {
-               ret = -ETIMEDOUT;
-               goto out;
-       }
        for (i = 0; i < nxfers; i++) {
                if (RESP_STATUS(xfer[i].response) != RESP_SUCCESS) {
                        ret = -EIO;
index 9c63d80f7fc447a5f7ccbba1a6d81b2e6c443e3f..850016e3d4fe019d06559472febad9c2eb0aa07d 100644 (file)
@@ -89,6 +89,7 @@ struct hci_xfer {
        unsigned int data_len;
        unsigned int cmd_tid;
        struct completion *completion;
+       unsigned long timeout;
        union {
                struct {
                        /* PIO specific */
@@ -156,5 +157,6 @@ void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci);
 void amd_set_od_pp_timing(struct i3c_hci *hci);
 void amd_set_resp_buf_thld(struct i3c_hci *hci);
 void i3c_hci_sync_irq_inactive(struct i3c_hci *hci);
+int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
 
 #endif