Message ID | 20190125152300.248d58f4@xhacker.debian (mailing list archive) |
---|---|
State | Mainlined |
Commit | f36c1f9a8dfd6a78e6c3fe7aff5e722b84307597 |
Headers | show |
Series | i3c: master: dw: fix deadlock | expand |
Hi Jisheng, Thanks for your report. On 25/01/19 07:29, Jisheng Zhang wrote: > In dw_i3c_master_irq_handler(), we already have gotten > &master->xferqueue.lock, if we try to get the same lock again in > dw_i3c_master_dequeue_xfer(), deadlock happens. > > We fix this issue by introduing dw_i3c_master_dequeue_xfer_locked() > which does all what dw_i3c_master_dequeue_xfer() does without trying > to lock &master->xferqueue.lock. > > Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com> > --- > drivers/i3c/master/dw-i3c-master.c | 18 ++++++++++++------ > 1 file changed, 12 insertions(+), 6 deletions(-) > > diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c > index f8c00b94817f..bb03079fbade 100644 > --- a/drivers/i3c/master/dw-i3c-master.c > +++ b/drivers/i3c/master/dw-i3c-master.c > @@ -419,12 +419,9 @@ static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master, > spin_unlock_irqrestore(&master->xferqueue.lock, flags); > } > > -static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, > - struct dw_i3c_xfer *xfer) > +static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master, > + struct dw_i3c_xfer *xfer) > { > - unsigned long flags; > - > - spin_lock_irqsave(&master->xferqueue.lock, flags); > if (master->xferqueue.cur == xfer) { > u32 status; > > @@ -439,6 +436,15 @@ static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, > } else { > list_del_init(&xfer->node); > } > +} > + > +static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, > + struct dw_i3c_xfer *xfer) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&master->xferqueue.lock, flags); > + dw_i3c_master_dequeue_xfer_locked(master, xfer); > spin_unlock_irqrestore(&master->xferqueue.lock, flags); > } > > @@ -494,7 +500,7 @@ static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr) > complete(&xfer->comp); > > if (ret < 0) { > - dw_i3c_master_dequeue_xfer(master, xfer); > + dw_i3c_master_dequeue_xfer_locked(master, xfer); > writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME, > master->regs + DEVICE_CTRL); > } Acked-by: Vitor Soares <vitor.soares@synopsys.com>
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index f8c00b94817f..bb03079fbade 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -419,12 +419,9 @@ static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master, spin_unlock_irqrestore(&master->xferqueue.lock, flags); } -static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, - struct dw_i3c_xfer *xfer) +static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master, + struct dw_i3c_xfer *xfer) { - unsigned long flags; - - spin_lock_irqsave(&master->xferqueue.lock, flags); if (master->xferqueue.cur == xfer) { u32 status; @@ -439,6 +436,15 @@ static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, } else { list_del_init(&xfer->node); } +} + +static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master, + struct dw_i3c_xfer *xfer) +{ + unsigned long flags; + + spin_lock_irqsave(&master->xferqueue.lock, flags); + dw_i3c_master_dequeue_xfer_locked(master, xfer); spin_unlock_irqrestore(&master->xferqueue.lock, flags); } @@ -494,7 +500,7 @@ static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr) complete(&xfer->comp); if (ret < 0) { - dw_i3c_master_dequeue_xfer(master, xfer); + dw_i3c_master_dequeue_xfer_locked(master, xfer); writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_RESUME, master->regs + DEVICE_CTRL); }
In dw_i3c_master_irq_handler(), we already have gotten &master->xferqueue.lock, if we try to get the same lock again in dw_i3c_master_dequeue_xfer(), deadlock happens. We fix this issue by introduing dw_i3c_master_dequeue_xfer_locked() which does all what dw_i3c_master_dequeue_xfer() does without trying to lock &master->xferqueue.lock. Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com> --- drivers/i3c/master/dw-i3c-master.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)