Skip to content

Commit 6bf3fc2

Browse files
nxpfranklialexandrebelloni
authored andcommitted
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: dd3c528 ("i3c: master: svc: Add Silvaco I3C master driver") Cc: <[email protected]> Reviewed-by: Miquel Raynal <[email protected]> Signed-off-by: Frank Li <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 57ec42b commit 6bf3fc2

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

drivers/i3c/master/svc-i3c-master.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ struct svc_i3c_regs_save {
175175
* @ibi.slots: Available IBI slots
176176
* @ibi.tbq_slot: To be queued IBI slot
177177
* @ibi.lock: IBI lock
178+
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
178179
*/
179180
struct svc_i3c_master {
180181
struct i3c_master_controller base;
@@ -203,6 +204,7 @@ struct svc_i3c_master {
203204
/* Prevent races within IBI handlers */
204205
spinlock_t lock;
205206
} ibi;
207+
struct mutex lock;
206208
};
207209

208210
/**
@@ -384,6 +386,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
384386
u32 status, val;
385387
int ret;
386388

389+
mutex_lock(&master->lock);
387390
/* Acknowledge the incoming interrupt with the AUTOIBI mechanism */
388391
writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI |
389392
SVC_I3C_MCTRL_IBIRESP_AUTO,
@@ -460,6 +463,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
460463

461464
reenable_ibis:
462465
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
466+
mutex_unlock(&master->lock);
463467
}
464468

465469
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,
12041208
cmd->read_len = 0;
12051209
cmd->continued = false;
12061210

1211+
mutex_lock(&master->lock);
12071212
svc_i3c_master_enqueue_xfer(master, xfer);
12081213
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
12091214
svc_i3c_master_dequeue_xfer(master, xfer);
1215+
mutex_unlock(&master->lock);
12101216

12111217
ret = xfer->ret;
12121218
kfree(buf);
@@ -1250,9 +1256,11 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
12501256
cmd->read_len = read_len;
12511257
cmd->continued = false;
12521258

1259+
mutex_lock(&master->lock);
12531260
svc_i3c_master_enqueue_xfer(master, xfer);
12541261
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
12551262
svc_i3c_master_dequeue_xfer(master, xfer);
1263+
mutex_unlock(&master->lock);
12561264

12571265
if (cmd->read_len != xfer_len)
12581266
ccc->dests[0].payload.len = cmd->read_len;
@@ -1309,9 +1317,11 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
13091317
cmd->continued = (i + 1) < nxfers;
13101318
}
13111319

1320+
mutex_lock(&master->lock);
13121321
svc_i3c_master_enqueue_xfer(master, xfer);
13131322
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
13141323
svc_i3c_master_dequeue_xfer(master, xfer);
1324+
mutex_unlock(&master->lock);
13151325

13161326
ret = xfer->ret;
13171327
svc_i3c_master_free_xfer(xfer);
@@ -1347,9 +1357,11 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
13471357
cmd->continued = (i + 1 < nxfers);
13481358
}
13491359

1360+
mutex_lock(&master->lock);
13501361
svc_i3c_master_enqueue_xfer(master, xfer);
13511362
if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
13521363
svc_i3c_master_dequeue_xfer(master, xfer);
1364+
mutex_unlock(&master->lock);
13531365

13541366
ret = xfer->ret;
13551367
svc_i3c_master_free_xfer(xfer);
@@ -1540,6 +1552,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
15401552

15411553
INIT_WORK(&master->hj_work, svc_i3c_master_hj_work);
15421554
INIT_WORK(&master->ibi_work, svc_i3c_master_ibi_work);
1555+
mutex_init(&master->lock);
1556+
15431557
ret = devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler,
15441558
IRQF_NO_SUSPEND, "svc-i3c-irq", master);
15451559
if (ret)

0 commit comments

Comments
 (0)