]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Mar 2026 14:54:11 +0000 (15:54 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Mar 2026 14:54:11 +0000 (15:54 +0100)
added patches:
i3c-mipi-i3c-hci-add-missing-tid-field-to-no-op-command-descriptor.patch
i3c-mipi-i3c-hci-consolidate-spinlocks.patch
i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in-dma-dequeue.patch
i3c-mipi-i3c-hci-factor-out-dma-mapping-from-queuing-path.patch
i3c-mipi-i3c-hci-fix-race-in-dma-ring-dequeue.patch
i3c-mipi-i3c-hci-restart-dma-ring-correctly-after-dequeue-abort.patch
i3c-mipi-i3c-hci-use-etimedout-instead-of-etime-for-timeout-errors.patch

queue-6.19/i3c-mipi-i3c-hci-add-missing-tid-field-to-no-op-command-descriptor.patch [new file with mode: 0644]
queue-6.19/i3c-mipi-i3c-hci-consolidate-spinlocks.patch [new file with mode: 0644]
queue-6.19/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in-dma-dequeue.patch [new file with mode: 0644]
queue-6.19/i3c-mipi-i3c-hci-factor-out-dma-mapping-from-queuing-path.patch [new file with mode: 0644]
queue-6.19/i3c-mipi-i3c-hci-fix-race-in-dma-ring-dequeue.patch [new file with mode: 0644]
queue-6.19/i3c-mipi-i3c-hci-restart-dma-ring-correctly-after-dequeue-abort.patch [new file with mode: 0644]
queue-6.19/i3c-mipi-i3c-hci-use-etimedout-instead-of-etime-for-timeout-errors.patch [new file with mode: 0644]
queue-6.19/series

diff --git a/queue-6.19/i3c-mipi-i3c-hci-add-missing-tid-field-to-no-op-command-descriptor.patch b/queue-6.19/i3c-mipi-i3c-hci-add-missing-tid-field-to-no-op-command-descriptor.patch
new file mode 100644 (file)
index 0000000..afa85c3
--- /dev/null
@@ -0,0 +1,54 @@
+From ec3cfd835f7c4bbd23bc9ad909d2fdc772a578bb Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:46 +0200
+Subject: i3c: mipi-i3c-hci: Add missing TID field to no-op command descriptor
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit ec3cfd835f7c4bbd23bc9ad909d2fdc772a578bb upstream.
+
+The internal control command descriptor used for no-op commands includes a
+Transaction ID (TID) field, but the no-op command constructed in
+hci_dma_dequeue_xfer() omitted it.  As a result, the hardware receives a
+no-op descriptor without the expected TID.
+
+This bug has gone unnoticed because the TID is currently not validated in
+the no-op completion path, but the descriptor format requires it to be
+present.
+
+Add the missing TID field when generating a no-op descriptor so that its
+layout matches the defined command structure.
+
+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-10-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/cmd.h |    1 +
+ drivers/i3c/master/mipi-i3c-hci/dma.c |    2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/cmd.h
++++ b/drivers/i3c/master/mipi-i3c-hci/cmd.h
+@@ -17,6 +17,7 @@
+ #define CMD_0_TOC                     W0_BIT_(31)
+ #define CMD_0_ROC                     W0_BIT_(30)
+ #define CMD_0_ATTR                    W0_MASK(2, 0)
++#define CMD_0_TID                     W0_MASK(6, 3)
+ /*
+  * Response Descriptor Structure
+--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
+@@ -510,7 +510,7 @@ static bool hci_dma_dequeue_xfer(struct
+                       u32 *ring_data = rh->xfer + rh->xfer_struct_sz * idx;
+                       /* store no-op cmd descriptor */
+-                      *ring_data++ = FIELD_PREP(CMD_0_ATTR, 0x7);
++                      *ring_data++ = FIELD_PREP(CMD_0_ATTR, 0x7) | FIELD_PREP(CMD_0_TID, xfer->cmd_tid);
+                       *ring_data++ = 0;
+                       if (hci->cmd == &mipi_i3c_hci_cmd_v2) {
+                               *ring_data++ = 0;
diff --git a/queue-6.19/i3c-mipi-i3c-hci-consolidate-spinlocks.patch b/queue-6.19/i3c-mipi-i3c-hci-consolidate-spinlocks.patch
new file mode 100644 (file)
index 0000000..b4ca93f
--- /dev/null
@@ -0,0 +1,196 @@
+From fa12bb903bc3ed1826e355d267fe134bde95e23c Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:41 +0200
+Subject: i3c: mipi-i3c-hci: Consolidate spinlocks
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit fa12bb903bc3ed1826e355d267fe134bde95e23c upstream.
+
+The MIPI I3C HCI driver currently uses separate spinlocks for different
+contexts (PIO vs. DMA rings).  This split is unnecessary and complicates
+upcoming fixes.  The driver does not support concurrent PIO and DMA
+operation, and it only supports a single DMA ring, so a single lock is
+sufficient for all paths.
+
+Introduce a unified spinlock in struct i3c_hci, switch both PIO and DMA
+code to use it, and remove the per-context locks.
+
+No functional change is intended in this patch.
+
+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-5-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/core.c |    2 ++
+ drivers/i3c/master/mipi-i3c-hci/dma.c  |   14 ++++++--------
+ drivers/i3c/master/mipi-i3c-hci/hci.h  |    1 +
+ drivers/i3c/master/mipi-i3c-hci/pio.c  |   16 +++++++---------
+ 4 files changed, 16 insertions(+), 17 deletions(-)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/core.c
++++ b/drivers/i3c/master/mipi-i3c-hci/core.c
+@@ -631,6 +631,8 @@ static int i3c_hci_init(struct i3c_hci *
+       if (ret)
+               return ret;
++      spin_lock_init(&hci->lock);
++
+       /*
+        * Now let's reset the hardware.
+        * SOFT_RST must be clear before we write to it.
+--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
+@@ -133,7 +133,6 @@ struct hci_rh_data {
+       unsigned int xfer_struct_sz, resp_struct_sz, ibi_status_sz, ibi_chunk_sz;
+       unsigned int done_ptr, ibi_chunk_ptr;
+       struct hci_xfer **src_xfers;
+-      spinlock_t lock;
+       struct completion op_done;
+ };
+@@ -240,7 +239,6 @@ static int hci_dma_init(struct i3c_hci *
+                       goto err_out;
+               rh = &rings->headers[i];
+               rh->regs = hci->base_regs + offset;
+-              spin_lock_init(&rh->lock);
+               init_completion(&rh->op_done);
+               rh->xfer_entries = XFER_RING_ENTRIES;
+@@ -470,12 +468,12 @@ static int hci_dma_queue_xfer(struct i3c
+       }
+       /* take care to update the hardware enqueue pointer atomically */
+-      spin_lock_irq(&rh->lock);
++      spin_lock_irq(&hci->lock);
+       op1_val = rh_reg_read(RING_OPERATION1);
+       op1_val &= ~RING_OP1_CR_ENQ_PTR;
+       op1_val |= FIELD_PREP(RING_OP1_CR_ENQ_PTR, enqueue_ptr);
+       rh_reg_write(RING_OPERATION1, op1_val);
+-      spin_unlock_irq(&rh->lock);
++      spin_unlock_irq(&hci->lock);
+       return 0;
+ }
+@@ -573,12 +571,12 @@ static void hci_dma_xfer_done(struct i3c
+       }
+       /* take care to update the software dequeue pointer atomically */
+-      spin_lock(&rh->lock);
++      spin_lock(&hci->lock);
+       op1_val = rh_reg_read(RING_OPERATION1);
+       op1_val &= ~RING_OP1_CR_SW_DEQ_PTR;
+       op1_val |= FIELD_PREP(RING_OP1_CR_SW_DEQ_PTR, done_ptr);
+       rh_reg_write(RING_OPERATION1, op1_val);
+-      spin_unlock(&rh->lock);
++      spin_unlock(&hci->lock);
+ }
+ static int hci_dma_request_ibi(struct i3c_hci *hci, struct i3c_dev_desc *dev,
+@@ -759,12 +757,12 @@ static void hci_dma_process_ibi(struct i
+ done:
+       /* take care to update the ibi dequeue pointer atomically */
+-      spin_lock(&rh->lock);
++      spin_lock(&hci->lock);
+       op1_val = rh_reg_read(RING_OPERATION1);
+       op1_val &= ~RING_OP1_IBI_DEQ_PTR;
+       op1_val |= FIELD_PREP(RING_OP1_IBI_DEQ_PTR, deq_ptr);
+       rh_reg_write(RING_OPERATION1, op1_val);
+-      spin_unlock(&rh->lock);
++      spin_unlock(&hci->lock);
+       /* update the chunk pointer */
+       rh->ibi_chunk_ptr += ibi_chunks;
+--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
++++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
+@@ -45,6 +45,7 @@ struct i3c_hci {
+       const struct hci_io_ops *io;
+       void *io_data;
+       const struct hci_cmd_ops *cmd;
++      spinlock_t lock;
+       atomic_t next_cmd_tid;
+       u32 caps;
+       unsigned int quirks;
+--- a/drivers/i3c/master/mipi-i3c-hci/pio.c
++++ b/drivers/i3c/master/mipi-i3c-hci/pio.c
+@@ -124,7 +124,6 @@ struct hci_pio_ibi_data {
+ };
+ struct hci_pio_data {
+-      spinlock_t lock;
+       struct hci_xfer *curr_xfer, *xfer_queue;
+       struct hci_xfer *curr_rx, *rx_queue;
+       struct hci_xfer *curr_tx, *tx_queue;
+@@ -146,7 +145,6 @@ static int hci_pio_init(struct i3c_hci *
+               return -ENOMEM;
+       hci->io_data = pio;
+-      spin_lock_init(&pio->lock);
+       size_val = pio_reg_read(QUEUE_SIZE);
+       dev_info(&hci->master.dev, "CMD/RESP FIFO = %ld entries\n",
+@@ -609,7 +607,7 @@ static int hci_pio_queue_xfer(struct i3c
+               xfer[i].data_left = xfer[i].data_len;
+       }
+-      spin_lock_irq(&pio->lock);
++      spin_lock_irq(&hci->lock);
+       prev_queue_tail = pio->xfer_queue;
+       pio->xfer_queue = &xfer[n - 1];
+       if (pio->curr_xfer) {
+@@ -623,7 +621,7 @@ static int hci_pio_queue_xfer(struct i3c
+                       pio_reg_read(INTR_STATUS),
+                       pio_reg_read(INTR_SIGNAL_ENABLE));
+       }
+-      spin_unlock_irq(&pio->lock);
++      spin_unlock_irq(&hci->lock);
+       return 0;
+ }
+@@ -694,14 +692,14 @@ static bool hci_pio_dequeue_xfer(struct
+       struct hci_pio_data *pio = hci->io_data;
+       int ret;
+-      spin_lock_irq(&pio->lock);
++      spin_lock_irq(&hci->lock);
+       dev_dbg(&hci->master.dev, "n=%d status=%#x/%#x", n,
+               pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
+       dev_dbg(&hci->master.dev, "main_status = %#x/%#x",
+               readl(hci->base_regs + 0x20), readl(hci->base_regs + 0x28));
+       ret = hci_pio_dequeue_xfer_common(hci, pio, xfer, n);
+-      spin_unlock_irq(&pio->lock);
++      spin_unlock_irq(&hci->lock);
+       return ret;
+ }
+@@ -994,13 +992,13 @@ static bool hci_pio_irq_handler(struct i
+       struct hci_pio_data *pio = hci->io_data;
+       u32 status;
+-      spin_lock(&pio->lock);
++      spin_lock(&hci->lock);
+       status = pio_reg_read(INTR_STATUS);
+       dev_dbg(&hci->master.dev, "PIO_INTR_STATUS %#x/%#x",
+               status, pio->enabled_irqs);
+       status &= pio->enabled_irqs | STAT_LATENCY_WARNINGS;
+       if (!status) {
+-              spin_unlock(&pio->lock);
++              spin_unlock(&hci->lock);
+               return false;
+       }
+@@ -1036,7 +1034,7 @@ static bool hci_pio_irq_handler(struct i
+       pio_reg_write(INTR_SIGNAL_ENABLE, pio->enabled_irqs);
+       dev_dbg(&hci->master.dev, "PIO_INTR_STATUS %#x/%#x",
+               pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));
+-      spin_unlock(&pio->lock);
++      spin_unlock(&hci->lock);
+       return true;
+ }
diff --git a/queue-6.19/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in-dma-dequeue.patch b/queue-6.19/i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in-dma-dequeue.patch
new file mode 100644 (file)
index 0000000..2c93389
--- /dev/null
@@ -0,0 +1,73 @@
+From b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:45 +0200
+Subject: i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit b795e68bf3073d67bebbb5a44d93f49efc5b8cc7 upstream.
+
+The logic used to abort the DMA ring contains several flaws:
+
+ 1. The driver unconditionally issues a ring abort even when the ring has
+    already stopped.
+ 2. The completion used to wait for abort completion is never
+    re-initialized, resulting in incorrect wait behavior.
+ 3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which
+    resets hardware ring pointers and disrupts the controller state.
+ 4. If the ring is already stopped, the abort operation should be
+    considered successful without attempting further action.
+
+Fix the abort handling by checking whether the ring is running before
+issuing an abort, re-initializing the completion when needed, ensuring that
+RING_CTRL_ENABLE remains asserted during abort, and treating an already
+stopped ring as a successful condition.
+
+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-9-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/dma.c |   25 ++++++++++++++++---------
+ 1 file changed, 16 insertions(+), 9 deletions(-)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
+@@ -485,18 +485,25 @@ static bool hci_dma_dequeue_xfer(struct
+       struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number];
+       unsigned int i;
+       bool did_unqueue = false;
++      u32 ring_status;
+       guard(mutex)(&hci->control_mutex);
+-      /* stop the ring */
+-      rh_reg_write(RING_CONTROL, RING_CTRL_ABORT);
+-      if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) {
+-              /*
+-               * We're deep in it if ever this condition is ever met.
+-               * Hardware might still be writing to memory, etc.
+-               */
+-              dev_crit(&hci->master.dev, "unable to abort the ring\n");
+-              WARN_ON(1);
++      ring_status = rh_reg_read(RING_STATUS);
++      if (ring_status & RING_STATUS_RUNNING) {
++              /* stop the ring */
++              reinit_completion(&rh->op_done);
++              rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT);
++              wait_for_completion_timeout(&rh->op_done, HZ);
++              ring_status = rh_reg_read(RING_STATUS);
++              if (ring_status & RING_STATUS_RUNNING) {
++                      /*
++                       * We're deep in it if ever this condition is ever met.
++                       * Hardware might still be writing to memory, etc.
++                       */
++                      dev_crit(&hci->master.dev, "unable to abort the ring\n");
++                      WARN_ON(1);
++              }
+       }
+       for (i = 0; i < n; i++) {
diff --git a/queue-6.19/i3c-mipi-i3c-hci-factor-out-dma-mapping-from-queuing-path.patch b/queue-6.19/i3c-mipi-i3c-hci-factor-out-dma-mapping-from-queuing-path.patch
new file mode 100644 (file)
index 0000000..adb64a8
--- /dev/null
@@ -0,0 +1,116 @@
+From f3bcbfe1b8b0b836b772927f75f8cb6e759eb00a Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:40 +0200
+Subject: i3c: mipi-i3c-hci: Factor out DMA mapping from queuing path
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit f3bcbfe1b8b0b836b772927f75f8cb6e759eb00a upstream.
+
+Prepare for fixing a race in the DMA ring enqueue path when handling
+parallel transfers.  Move all DMA mapping out of hci_dma_queue_xfer()
+and into a new helper that performs the mapping up front.
+
+This refactoring allows the upcoming fix to extend the spinlock coverage
+around the enqueue operation without performing DMA mapping under the
+spinlock.
+
+No functional change is intended in this patch.
+
+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-4-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/dma.c |   49 ++++++++++++++++++++++------------
+ 1 file changed, 33 insertions(+), 16 deletions(-)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
+@@ -375,6 +375,33 @@ static void hci_dma_unmap_xfer(struct i3
+       }
+ }
++static struct i3c_dma *hci_dma_map_xfer(struct device *dev, struct hci_xfer *xfer)
++{
++      enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++      bool need_bounce = device_iommu_mapped(dev) && xfer->rnw && (xfer->data_len & 3);
++
++      return i3c_master_dma_map_single(dev, xfer->data, xfer->data_len, need_bounce, dir);
++}
++
++static int hci_dma_map_xfer_list(struct i3c_hci *hci, struct device *dev,
++                               struct hci_xfer *xfer_list, int n)
++{
++      for (int i = 0; i < n; i++) {
++              struct hci_xfer *xfer = xfer_list + i;
++
++              if (!xfer->data)
++                      continue;
++
++              xfer->dma = hci_dma_map_xfer(dev, xfer);
++              if (!xfer->dma) {
++                      hci_dma_unmap_xfer(hci, xfer_list, i);
++                      return -ENOMEM;
++              }
++      }
++
++      return 0;
++}
++
+ static int hci_dma_queue_xfer(struct i3c_hci *hci,
+                             struct hci_xfer *xfer_list, int n)
+ {
+@@ -382,6 +409,11 @@ static int hci_dma_queue_xfer(struct i3c
+       struct hci_rh_data *rh;
+       unsigned int i, ring, enqueue_ptr;
+       u32 op1_val, op2_val;
++      int ret;
++
++      ret = hci_dma_map_xfer_list(hci, rings->sysdev, xfer_list, n);
++      if (ret)
++              return ret;
+       /* For now we only use ring 0 */
+       ring = 0;
+@@ -392,9 +424,6 @@ static int hci_dma_queue_xfer(struct i3c
+       for (i = 0; i < n; i++) {
+               struct hci_xfer *xfer = xfer_list + i;
+               u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr;
+-              enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE :
+-                                                        DMA_TO_DEVICE;
+-              bool need_bounce;
+               /* store cmd descriptor */
+               *ring_data++ = xfer->cmd_desc[0];
+@@ -413,18 +442,6 @@ static int hci_dma_queue_xfer(struct i3c
+               /* 2nd and 3rd words of Data Buffer Descriptor Structure */
+               if (xfer->data) {
+-                      need_bounce = device_iommu_mapped(rings->sysdev) &&
+-                                    xfer->rnw &&
+-                                    xfer->data_len != ALIGN(xfer->data_len, 4);
+-                      xfer->dma = i3c_master_dma_map_single(rings->sysdev,
+-                                                            xfer->data,
+-                                                            xfer->data_len,
+-                                                            need_bounce,
+-                                                            dir);
+-                      if (!xfer->dma) {
+-                              hci_dma_unmap_xfer(hci, xfer_list, i);
+-                              return -ENOMEM;
+-                      }
+                       *ring_data++ = lower_32_bits(xfer->dma->addr);
+                       *ring_data++ = upper_32_bits(xfer->dma->addr);
+               } else {
+@@ -447,7 +464,7 @@ static int hci_dma_queue_xfer(struct i3c
+               op2_val = rh_reg_read(RING_OPERATION2);
+               if (enqueue_ptr == FIELD_GET(RING_OP2_CR_DEQ_PTR, op2_val)) {
+                       /* the ring is full */
+-                      hci_dma_unmap_xfer(hci, xfer_list, i + 1);
++                      hci_dma_unmap_xfer(hci, xfer_list, n);
+                       return -EBUSY;
+               }
+       }
diff --git a/queue-6.19/i3c-mipi-i3c-hci-fix-race-in-dma-ring-dequeue.patch b/queue-6.19/i3c-mipi-i3c-hci-fix-race-in-dma-ring-dequeue.patch
new file mode 100644 (file)
index 0000000..86252ba
--- /dev/null
@@ -0,0 +1,66 @@
+From 1dca8aee80eea76d2aae21265de5dd64f6ba0f09 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:43 +0200
+Subject: i3c: mipi-i3c-hci: Fix race in DMA ring dequeue
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit 1dca8aee80eea76d2aae21265de5dd64f6ba0f09 upstream.
+
+The HCI DMA dequeue path (hci_dma_dequeue_xfer()) may be invoked for
+multiple transfers that timeout around the same time.  However, the
+function is not serialized and can race with itself.
+
+When a timeout occurs, hci_dma_dequeue_xfer() stops the ring, processes
+incomplete transfers, and then restarts the ring.  If another timeout
+triggers a parallel call into the same function, the two instances may
+interfere with each other - stopping or restarting the ring at unexpected
+times.
+
+Add a mutex so that hci_dma_dequeue_xfer() is serialized with respect to
+itself.
+
+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-7-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/core.c |    1 +
+ drivers/i3c/master/mipi-i3c-hci/dma.c  |    2 ++
+ drivers/i3c/master/mipi-i3c-hci/hci.h  |    1 +
+ 3 files changed, 4 insertions(+)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/core.c
++++ b/drivers/i3c/master/mipi-i3c-hci/core.c
+@@ -632,6 +632,7 @@ static int i3c_hci_init(struct i3c_hci *
+               return ret;
+       spin_lock_init(&hci->lock);
++      mutex_init(&hci->control_mutex);
+       /*
+        * Now let's reset the hardware.
+--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
+@@ -486,6 +486,8 @@ static bool hci_dma_dequeue_xfer(struct
+       unsigned int i;
+       bool did_unqueue = false;
++      guard(mutex)(&hci->control_mutex);
++
+       /* stop the ring */
+       rh_reg_write(RING_CONTROL, RING_CTRL_ABORT);
+       if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) {
+--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
++++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
+@@ -46,6 +46,7 @@ struct i3c_hci {
+       void *io_data;
+       const struct hci_cmd_ops *cmd;
+       spinlock_t lock;
++      struct mutex control_mutex;
+       atomic_t next_cmd_tid;
+       u32 caps;
+       unsigned int quirks;
diff --git a/queue-6.19/i3c-mipi-i3c-hci-restart-dma-ring-correctly-after-dequeue-abort.patch b/queue-6.19/i3c-mipi-i3c-hci-restart-dma-ring-correctly-after-dequeue-abort.patch
new file mode 100644 (file)
index 0000000..575162c
--- /dev/null
@@ -0,0 +1,41 @@
+From b6d586431ae20d5157ee468d0ef62ad26798ef13 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:47 +0200
+Subject: i3c: mipi-i3c-hci: Restart DMA ring correctly after dequeue abort
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit b6d586431ae20d5157ee468d0ef62ad26798ef13 upstream.
+
+The DMA dequeue path attempts to restart the ring after aborting an
+in-flight transfer, but the current sequence is incomplete. The controller
+must be brought out of the aborted state and the ring control registers
+must be programmed in the correct order: first clearing ABORT, then
+re-enabling the ring and asserting RUN_STOP to resume operation.
+
+Add the missing controller resume step and update the ring control writes
+so that the ring is restarted using the proper sequence.
+
+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-11-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/dma.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
++++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
+@@ -528,7 +528,9 @@ static bool hci_dma_dequeue_xfer(struct
+       }
+       /* restart the ring */
++      mipi_i3c_hci_resume(hci);
+       rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE);
++      rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_RUN_STOP);
+       return did_unqueue;
+ }
diff --git a/queue-6.19/i3c-mipi-i3c-hci-use-etimedout-instead-of-etime-for-timeout-errors.patch b/queue-6.19/i3c-mipi-i3c-hci-use-etimedout-instead-of-etime-for-timeout-errors.patch
new file mode 100644 (file)
index 0000000..3d834e1
--- /dev/null
@@ -0,0 +1,78 @@
+From 4167b8914463132654e01e16259847d097f8a7f7 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Fri, 6 Mar 2026 09:24:38 +0200
+Subject: i3c: mipi-i3c-hci: Use ETIMEDOUT instead of ETIME for timeout errors
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit 4167b8914463132654e01e16259847d097f8a7f7 upstream.
+
+The MIPI I3C HCI driver currently returns -ETIME for various timeout
+conditions, while other I3C master drivers consistently use -ETIMEDOUT
+for the same class of errors.  Align the HCI driver with the rest of the
+subsystem by replacing all uses of -ETIME with -ETIMEDOUT.
+
+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-2-adrian.hunter@intel.com
+Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/i3c/master/mipi-i3c-hci/cmd_v1.c |    2 +-
+ drivers/i3c/master/mipi-i3c-hci/cmd_v2.c |    2 +-
+ drivers/i3c/master/mipi-i3c-hci/core.c   |    6 +++---
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
++++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
+@@ -336,7 +336,7 @@ static int hci_cmd_v1_daa(struct i3c_hci
+               hci->io->queue_xfer(hci, xfer, 1);
+               if (!wait_for_completion_timeout(&done, HZ) &&
+                   hci->io->dequeue_xfer(hci, xfer, 1)) {
+-                      ret = -ETIME;
++                      ret = -ETIMEDOUT;
+                       break;
+               }
+               if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
+--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
++++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
+@@ -277,7 +277,7 @@ static int hci_cmd_v2_daa(struct i3c_hci
+               hci->io->queue_xfer(hci, xfer, 2);
+               if (!wait_for_completion_timeout(&done, HZ) &&
+                   hci->io->dequeue_xfer(hci, xfer, 2)) {
+-                      ret = -ETIME;
++                      ret = -ETIMEDOUT;
+                       break;
+               }
+               if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
+--- a/drivers/i3c/master/mipi-i3c-hci/core.c
++++ b/drivers/i3c/master/mipi-i3c-hci/core.c
+@@ -230,7 +230,7 @@ static int i3c_hci_send_ccc_cmd(struct i
+               goto out;
+       if (!wait_for_completion_timeout(&done, HZ) &&
+           hci->io->dequeue_xfer(hci, xfer, nxfers)) {
+-              ret = -ETIME;
++              ret = -ETIMEDOUT;
+               goto out;
+       }
+       for (i = prefixed; i < nxfers; i++) {
+@@ -309,7 +309,7 @@ static int i3c_hci_i3c_xfers(struct i3c_
+               goto out;
+       if (!wait_for_completion_timeout(&done, HZ) &&
+           hci->io->dequeue_xfer(hci, xfer, nxfers)) {
+-              ret = -ETIME;
++              ret = -ETIMEDOUT;
+               goto out;
+       }
+       for (i = 0; i < nxfers; i++) {
+@@ -357,7 +357,7 @@ static int i3c_hci_i2c_xfers(struct i2c_
+               goto out;
+       if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
+           hci->io->dequeue_xfer(hci, xfer, nxfers)) {
+-              ret = -ETIME;
++              ret = -ETIMEDOUT;
+               goto out;
+       }
+       for (i = 0; i < nxfers; i++) {
index 884d1154d2494629232b0d77d6a242c87546aa30..83bc6827cdde431a762b1db4193e58f68c428642 100644 (file)
@@ -362,3 +362,10 @@ iio-imu-inv_icm42600-fix-odr-switch-to-the-same-value.patch
 iio-imu-inv_icm42600-fix-odr-switch-when-turning-buffer-off.patch
 iio-proximity-hx9023s-fix-assignment-order-for-__counted_by.patch
 iio-proximity-hx9023s-protect-against-division-by-zero-in-set_samp_freq.patch
+i3c-mipi-i3c-hci-use-etimedout-instead-of-etime-for-timeout-errors.patch
+i3c-mipi-i3c-hci-factor-out-dma-mapping-from-queuing-path.patch
+i3c-mipi-i3c-hci-consolidate-spinlocks.patch
+i3c-mipi-i3c-hci-restart-dma-ring-correctly-after-dequeue-abort.patch
+i3c-mipi-i3c-hci-add-missing-tid-field-to-no-op-command-descriptor.patch
+i3c-mipi-i3c-hci-fix-race-in-dma-ring-dequeue.patch
+i3c-mipi-i3c-hci-correct-ring_ctrl_abort-handling-in-dma-dequeue.patch