Message ID | 1694594861-12691-3-git-send-email-quic_qianyu@quicinc.com |
---|---|
State | Superseded |
Headers | show |
Series | Add lock to avoid race when ringing channel DB | expand |
On 9/13/2023 2:47 AM, Qiang Yu wrote: > From: Hemant Kumar <quic_hemantk@quicinc.com> > > Take irqsave lock after TRE is generated to avoid deadlock due to core > getting interrupts enabled as local_bh_enable must not be called with > irqs disabled based on upstream patch. Where is local_bh_enable() being called? What patch? What is upstream of the codebase you submitted this to? Why is it safe to call mhi_gen_tre() without the lock?
On 9/22/2023 10:50 PM, Jeffrey Hugo wrote: > On 9/13/2023 2:47 AM, Qiang Yu wrote: >> From: Hemant Kumar <quic_hemantk@quicinc.com> >> >> Take irqsave lock after TRE is generated to avoid deadlock due to core >> getting interrupts enabled as local_bh_enable must not be called with >> irqs disabled based on upstream patch. > > Where is local_bh_enable() being called? What patch? What is > upstream of the codebase you submitted this to? Why is it safe to > call mhi_gen_tre() without the lock? This patch is to fix the issue included by "[PATCH v2 1/2] bus: mhi: host: Add spinlock to protect WP access when queueing TREs". In that patch, we add write_lock_bh/write_unlock_bh in mhi_gen_tre(). However, before mhi_gen_tre() is invoked, mhi_cntrl->pm_lock is getted, line 1125, and it is a spin lock. So it becomes we want to get and release bh lock after spin lock. __local_bh_enable_ip is called as part of write_unlock_bh and local_bh_enable. When CONFIG_TRACE_IRQFLAGS is enabled, irq will be enabled once __local_bh_enable_ip is called. The commit message is not clear and confusing, will change it in [patch v3].
On 9/24/2023 10:08 PM, Qiang Yu wrote: > > On 9/22/2023 10:50 PM, Jeffrey Hugo wrote: >> On 9/13/2023 2:47 AM, Qiang Yu wrote: >>> From: Hemant Kumar <quic_hemantk@quicinc.com> >>> >>> Take irqsave lock after TRE is generated to avoid deadlock due to core >>> getting interrupts enabled as local_bh_enable must not be called with >>> irqs disabled based on upstream patch. >> >> Where is local_bh_enable() being called? What patch? What is >> upstream of the codebase you submitted this to? Why is it safe to >> call mhi_gen_tre() without the lock? > > This patch is to fix the issue included by "[PATCH v2 1/2] bus: mhi: > host: Add spinlock to protect WP access when queueing TREs". In that > patch, we add write_lock_bh/write_unlock_bh in mhi_gen_tre(). > > However, before mhi_gen_tre() is invoked, mhi_cntrl->pm_lock is getted, > line 1125, and it is a spin lock. So it becomes we want to get and > release bh lock after spin lock. __local_bh_enable_ip is called as part > of write_unlock_bh > > and local_bh_enable. When CONFIG_TRACE_IRQFLAGS is enabled, irq will be > enabled once __local_bh_enable_ip is called. The commit message is not > clear and confusing, will change it in [patch v3]. > In addition to clarifying the commit message, I recommend looking at adding this to the other patch. It seems very odd to review a series where one patch introduces a known issue, and a following patch corrects that issue. It would be better to not introduce the issue in the first place.
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index 13c4b89..8accdfd 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -1124,17 +1124,15 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) return -EIO; - read_lock_irqsave(&mhi_cntrl->pm_lock, flags); - ret = mhi_is_ring_full(mhi_cntrl, tre_ring); - if (unlikely(ret)) { - ret = -EAGAIN; - goto exit_unlock; - } + if (unlikely(ret)) + return -EAGAIN; ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags); if (unlikely(ret)) - goto exit_unlock; + return ret; + + read_lock_irqsave(&mhi_cntrl->pm_lock, flags); /* Packet is queued, take a usage ref to exit M3 if necessary * for host->device buffer, balanced put is done on buffer completion @@ -1154,7 +1152,6 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (dir == DMA_FROM_DEVICE) mhi_cntrl->runtime_put(mhi_cntrl); -exit_unlock: read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); return ret;