6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Frank Li Frank.Li@nxp.com
commit 6bf3fc268183816856c96b8794cd66146bc27b35 upstream.
The ibi work thread operates asynchronously with other transfers, such as svc_i3c_master_priv_xfers(). Introduce mutex protection to ensure the completion of the entire i3c/i2c transaction.
Fixes: dd3c52846d59 ("i3c: master: svc: Add Silvaco I3C master driver") Cc: stable@vger.kernel.org Reviewed-by: Miquel Raynal miquel.raynal@bootlin.com Signed-off-by: Frank Li Frank.Li@nxp.com Link: https://lore.kernel.org/r/20231023161658.3890811-2-Frank.Li@nxp.com Signed-off-by: Alexandre Belloni alexandre.belloni@bootlin.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- drivers/i3c/master/svc-i3c-master.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
--- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -168,6 +168,7 @@ struct svc_i3c_xfer { * @ibi.slots: Available IBI slots * @ibi.tbq_slot: To be queued IBI slot * @ibi.lock: IBI lock + * @lock: Transfer lock, protect between IBI work thread and callbacks from master */ struct svc_i3c_master { struct i3c_master_controller base; @@ -195,6 +196,7 @@ struct svc_i3c_master { /* Prevent races within IBI handlers */ spinlock_t lock; } ibi; + struct mutex lock; };
/** @@ -376,6 +378,7 @@ static void svc_i3c_master_ibi_work(stru u32 status, val; int ret;
+ mutex_lock(&master->lock); /* Acknowledge the incoming interrupt with the AUTOIBI mechanism */ writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI | SVC_I3C_MCTRL_IBIRESP_AUTO, @@ -452,6 +455,7 @@ static void svc_i3c_master_ibi_work(stru
reenable_ibis: svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); + mutex_unlock(&master->lock); }
static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id) @@ -1191,9 +1195,11 @@ static int svc_i3c_master_send_bdcast_cc cmd->read_len = 0; cmd->continued = false;
+ mutex_lock(&master->lock); svc_i3c_master_enqueue_xfer(master, xfer); if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) svc_i3c_master_dequeue_xfer(master, xfer); + mutex_unlock(&master->lock);
ret = xfer->ret; kfree(buf); @@ -1237,9 +1243,11 @@ static int svc_i3c_master_send_direct_cc cmd->read_len = read_len; cmd->continued = false;
+ mutex_lock(&master->lock); svc_i3c_master_enqueue_xfer(master, xfer); if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) svc_i3c_master_dequeue_xfer(master, xfer); + mutex_unlock(&master->lock);
if (cmd->read_len != xfer_len) ccc->dests[0].payload.len = cmd->read_len; @@ -1296,9 +1304,11 @@ static int svc_i3c_master_priv_xfers(str cmd->continued = (i + 1) < nxfers; }
+ mutex_lock(&master->lock); svc_i3c_master_enqueue_xfer(master, xfer); if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) svc_i3c_master_dequeue_xfer(master, xfer); + mutex_unlock(&master->lock);
ret = xfer->ret; svc_i3c_master_free_xfer(xfer); @@ -1334,9 +1344,11 @@ static int svc_i3c_master_i2c_xfers(stru cmd->continued = (i + 1 < nxfers); }
+ mutex_lock(&master->lock); svc_i3c_master_enqueue_xfer(master, xfer); if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) svc_i3c_master_dequeue_xfer(master, xfer); + mutex_unlock(&master->lock);
ret = xfer->ret; svc_i3c_master_free_xfer(xfer); @@ -1527,6 +1539,8 @@ static int svc_i3c_master_probe(struct p
INIT_WORK(&master->hj_work, svc_i3c_master_hj_work); INIT_WORK(&master->ibi_work, svc_i3c_master_ibi_work); + mutex_init(&master->lock); + ret = devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler, IRQF_NO_SUSPEND, "svc-i3c-irq", master); if (ret)