Commit 6bf3fc26 authored by Frank Li's avatar Frank Li Committed by Alexandre Belloni

i3c: master: svc: fix race condition in ibi work thread

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: dd3c5284 ("i3c: master: svc: Add Silvaco I3C master driver")
Cc:  <stable@vger.kernel.org>
Reviewed-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: default avatarFrank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20231023161658.3890811-2-Frank.Li@nxp.comSigned-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent 57ec42b9
...@@ -175,6 +175,7 @@ struct svc_i3c_regs_save { ...@@ -175,6 +175,7 @@ struct svc_i3c_regs_save {
* @ibi.slots: Available IBI slots * @ibi.slots: Available IBI slots
* @ibi.tbq_slot: To be queued IBI slot * @ibi.tbq_slot: To be queued IBI slot
* @ibi.lock: IBI lock * @ibi.lock: IBI lock
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
*/ */
struct svc_i3c_master { struct svc_i3c_master {
struct i3c_master_controller base; struct i3c_master_controller base;
...@@ -203,6 +204,7 @@ struct svc_i3c_master { ...@@ -203,6 +204,7 @@ struct svc_i3c_master {
/* Prevent races within IBI handlers */ /* Prevent races within IBI handlers */
spinlock_t lock; spinlock_t lock;
} ibi; } ibi;
struct mutex lock;
}; };
/** /**
...@@ -384,6 +386,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) ...@@ -384,6 +386,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
u32 status, val; u32 status, val;
int ret; int ret;
mutex_lock(&master->lock);
/* Acknowledge the incoming interrupt with the AUTOIBI mechanism */ /* Acknowledge the incoming interrupt with the AUTOIBI mechanism */
writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI | writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI |
SVC_I3C_MCTRL_IBIRESP_AUTO, SVC_I3C_MCTRL_IBIRESP_AUTO,
...@@ -460,6 +463,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) ...@@ -460,6 +463,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
reenable_ibis: reenable_ibis:
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); 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) static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
...@@ -1204,9 +1208,11 @@ static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master, ...@@ -1204,9 +1208,11 @@ static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master,
cmd->read_len = 0; cmd->read_len = 0;
cmd->continued = false; cmd->continued = false;
mutex_lock(&master->lock);
svc_i3c_master_enqueue_xfer(master, xfer); svc_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
svc_i3c_master_dequeue_xfer(master, xfer); svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
ret = xfer->ret; ret = xfer->ret;
kfree(buf); kfree(buf);
...@@ -1250,9 +1256,11 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master, ...@@ -1250,9 +1256,11 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
cmd->read_len = read_len; cmd->read_len = read_len;
cmd->continued = false; cmd->continued = false;
mutex_lock(&master->lock);
svc_i3c_master_enqueue_xfer(master, xfer); svc_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
svc_i3c_master_dequeue_xfer(master, xfer); svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
if (cmd->read_len != xfer_len) if (cmd->read_len != xfer_len)
ccc->dests[0].payload.len = cmd->read_len; ccc->dests[0].payload.len = cmd->read_len;
...@@ -1309,9 +1317,11 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev, ...@@ -1309,9 +1317,11 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
cmd->continued = (i + 1) < nxfers; cmd->continued = (i + 1) < nxfers;
} }
mutex_lock(&master->lock);
svc_i3c_master_enqueue_xfer(master, xfer); svc_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
svc_i3c_master_dequeue_xfer(master, xfer); svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
ret = xfer->ret; ret = xfer->ret;
svc_i3c_master_free_xfer(xfer); svc_i3c_master_free_xfer(xfer);
...@@ -1347,9 +1357,11 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, ...@@ -1347,9 +1357,11 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
cmd->continued = (i + 1 < nxfers); cmd->continued = (i + 1 < nxfers);
} }
mutex_lock(&master->lock);
svc_i3c_master_enqueue_xfer(master, xfer); svc_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
svc_i3c_master_dequeue_xfer(master, xfer); svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
ret = xfer->ret; ret = xfer->ret;
svc_i3c_master_free_xfer(xfer); svc_i3c_master_free_xfer(xfer);
...@@ -1540,6 +1552,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev) ...@@ -1540,6 +1552,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
INIT_WORK(&master->hj_work, svc_i3c_master_hj_work); INIT_WORK(&master->hj_work, svc_i3c_master_hj_work);
INIT_WORK(&master->ibi_work, svc_i3c_master_ibi_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, ret = devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler,
IRQF_NO_SUSPEND, "svc-i3c-irq", master); IRQF_NO_SUSPEND, "svc-i3c-irq", master);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment