]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
i3c: mipi-i3c-hci: Consolidate spinlocks
authorAdrian Hunter <adrian.hunter@intel.com>
Fri, 6 Mar 2026 07:24:41 +0000 (09:24 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Mar 2026 15:15:31 +0000 (16:15 +0100)
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
drivers/i3c/master/mipi-i3c-hci/dma.c
drivers/i3c/master/mipi-i3c-hci/hci.h
drivers/i3c/master/mipi-i3c-hci/pio.c

index 11efe28fb46cff36533521bbdc46c3ab8e83a5e0..3debc5f1327d08c257b2047cbb1528bdff10adb3 100644 (file)
@@ -631,6 +631,8 @@ static int i3c_hci_init(struct i3c_hci *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.
index 00809f19f69a4a01ae636d5f1374cfc76d0eaffa..9a1cc531ac98ab7eab826e702a2084d221792e6c 100644 (file)
@@ -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 *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_hci *hci,
        }
 
        /* 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_hci *hci, struct hci_rh_data *rh)
        }
 
        /* 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 i3c_hci *hci, struct hci_rh_data *rh)
 
 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;
index 249ccb13c909288b418938112f4997aebc212bd6..5656d43a100956739a5f30027694531f41ecb06d 100644 (file)
@@ -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;
index 710faa46a00faa9b558efc91eaeb667caef40a2e..67dc34163d51bdf6cdae3895fe27de89c2db47cd 100644 (file)
@@ -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 *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_hci *hci, struct hci_xfer *xfer, int n)
                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_hci *hci, struct hci_xfer *xfer, int n)
                        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 i3c_hci *hci, struct hci_xfer *xfer, int
        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 i3c_hci *hci)
        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 i3c_hci *hci)
        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;
 }