Re: [PATCH] iommu/vt-d: Fix IQE handling to cover all descriptors in submission range
Samiullah Khawaja <[email protected]>
| Newsgroups | dev.linux.lists.iommu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On Thu, Aug 20, 2026 at 10:47:41PM +0800, Guanghui Feng wrote: >Currently, qi_check_fault() only handles IQE (Invalidation Queue Error) >when the faulting descriptor index exactly matches the first descriptor >of the current submission (head == index). This is too restrictive in >multi-descriptor submissions where the error could occur at any >descriptor within the batch. > >If the IQE is triggered by a descriptor that belongs to the current >submission but is not at the starting index, the function returns 0 >without clearing the IQE fault status. Since hardware stops fetching >new descriptors until IQE is cleared, this leads to an indefinite wait >on the wait descriptor completion - effectively a deadlock. > >Fix this by expanding the IQE handling condition to cover all descriptors >within the circular range [index, wait_index]. Use explicit bounds >checking that properly handles the wrap-around case of the circular >queue. > >Signed-off-by: Guanghui Feng <[email protected]> >Signed-off-by: bikuan.zbk <[email protected]> >--- > drivers/iommu/intel/dmar.c | 15 ++++++++++++++- > 1 file changed, 14 insertions(+), 1 deletion(-) > >diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c >index ba675b08cd20..ecc95af06f61 100644 >--- a/drivers/iommu/intel/dmar.c >+++ b/drivers/iommu/intel/dmar.c >@@ -1366,8 +1366,21 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index) > * is cleared. > */ > if (fault & DMA_FSTS_IQE) { >+ int head_idx; >+ > head = readl(iommu->reg + DMAR_IQH_REG); >- if ((head >> shift) == index) { >+ head_idx = head >> shift; >+ >+ /* >+ * The faulting descriptor can be anywhere within the current >+ * submission's range [index, wait_index]. Since the queue is >+ * circular, this submission may wrap around QI_LENGTH >+ * (index > wait_index in that case), so check both the >+ * non-wrapped and wrapped cases of the range. >+ */ >+ if (index <= wait_index ? >+ (head_idx >= index && head_idx <= wait_index) : >+ (head_idx >= index || head_idx <= wait_index)) { > struct qi_desc *desc = qi->desc + head; > > /* >-- >2.43.7 > > Reviewed-by: Samiullah Khawaja <[email protected]>