Skip to content

Commit 8d29fa6

Browse files
stanleychuysalexandrebelloni
authored andcommitted
i3c: master: svc: Receive IBI requests in interrupt context
Moving the job from workqueue to ISR for two reasons. 1. Improve bus utilization. If the requests are postponed to be received in the workqueue thread, the SDA line remains low for a long time while the system loading is high. During this period, the bus is not available for other targets to raise requests. 2. Ensure prompt response to requests. For timing-critical requests, the target may encouter a failure or the event is missed if the request is not received in time. IBI request is short, ISR can receive the data quickly and then queue a work to handle it in the bottom half. Signed-off-by: Stanley Chu <[email protected]> Reviewed-by: Frank Li <[email protected]> Acked-by: Miquel Raynal <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent bd91680 commit 8d29fa6

File tree

1 file changed

+10
-15
lines changed

1 file changed

+10
-15
lines changed

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

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ struct svc_i3c_drvdata {
201201
* @addrs: Array containing the dynamic addresses of each attached device
202202
* @descs: Array of descriptors, one per attached device
203203
* @hj_work: Hot-join work
204-
* @ibi_work: IBI work
205204
* @irq: Main interrupt
206205
* @pclk: System clock
207206
* @fclk: Fast clock (bus)
@@ -229,7 +228,6 @@ struct svc_i3c_master {
229228
u8 addrs[SVC_I3C_MAX_DEVS];
230229
struct i3c_dev_desc *descs[SVC_I3C_MAX_DEVS];
231230
struct work_struct hj_work;
232-
struct work_struct ibi_work;
233231
int irq;
234232
struct clk *pclk;
235233
struct clk *fclk;
@@ -487,9 +485,8 @@ static int svc_i3c_master_handle_ibi_won(struct svc_i3c_master *master, u32 msta
487485
return ret;
488486
}
489487

490-
static void svc_i3c_master_ibi_work(struct work_struct *work)
488+
static void svc_i3c_master_ibi_isr(struct svc_i3c_master *master)
491489
{
492-
struct svc_i3c_master *master = container_of(work, struct svc_i3c_master, ibi_work);
493490
struct svc_i3c_i2c_dev_data *data;
494491
unsigned int ibitype, ibiaddr;
495492
struct i3c_dev_desc *dev;
@@ -504,7 +501,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
504501
* schedule during the whole I3C transaction, otherwise, the I3C bus timeout may happen if
505502
* any irq or schedule happen during transaction.
506503
*/
507-
guard(spinlock_irqsave)(&master->xferqueue.lock);
504+
guard(spinlock)(&master->xferqueue.lock);
508505

509506
/*
510507
* IBIWON may be set before SVC_I3C_MCTRL_REQUEST_AUTO_IBI, causing
@@ -530,7 +527,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
530527
if (ret) {
531528
dev_err(master->dev, "Timeout when polling for IBIWON\n");
532529
svc_i3c_master_emit_stop(master);
533-
goto reenable_ibis;
530+
return;
534531
}
535532

536533
status = readl(master->regs + SVC_I3C_MSTATUS);
@@ -574,7 +571,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
574571

575572
svc_i3c_master_emit_stop(master);
576573

577-
goto reenable_ibis;
574+
return;
578575
}
579576

580577
/* Handle the non critical tasks */
@@ -597,9 +594,6 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
597594
default:
598595
break;
599596
}
600-
601-
reenable_ibis:
602-
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
603597
}
604598

605599
static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
@@ -618,10 +612,12 @@ static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
618612
!SVC_I3C_MSTATUS_STATE_SLVREQ(active))
619613
return IRQ_HANDLED;
620614

621-
svc_i3c_master_disable_interrupts(master);
622-
623-
/* Handle the interrupt in a non atomic context */
624-
queue_work(master->base.wq, &master->ibi_work);
615+
/*
616+
* The SDA line remains low until the request is processed.
617+
* Receive the request in the interrupt context to respond promptly
618+
* and restore the bus to idle state.
619+
*/
620+
svc_i3c_master_ibi_isr(master);
625621

626622
return IRQ_HANDLED;
627623
}
@@ -1947,7 +1943,6 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
19471943
return ret;
19481944

19491945
INIT_WORK(&master->hj_work, svc_i3c_master_hj_work);
1950-
INIT_WORK(&master->ibi_work, svc_i3c_master_ibi_work);
19511946
mutex_init(&master->lock);
19521947

19531948
ret = devm_request_irq(dev, master->irq, svc_i3c_master_irq_handler,

0 commit comments

Comments
 (0)