Skip to content

Commit eee5353

Browse files
committed
iommu/amd: Fix deadlock in ppr-handling error path
In the error path of the ppr_notifer it can happen that the iommu->lock is taken recursivly. This patch fixes the problem by releasing the iommu->lock before any notifier is invoked. This also requires to move the erratum workaround for the ppr-log (interrupt may be faster than data in the log) one function up. Cc: [email protected] # v3.3, v3.4 Signed-off-by: Joerg Roedel <[email protected]>
1 parent c1bf94e commit eee5353

File tree

1 file changed

+44
-27
lines changed

1 file changed

+44
-27
lines changed

drivers/iommu/amd_iommu.c

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -547,26 +547,12 @@ static void iommu_poll_events(struct amd_iommu *iommu)
547547
spin_unlock_irqrestore(&iommu->lock, flags);
548548
}
549549

550-
static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u32 head)
550+
static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw)
551551
{
552552
struct amd_iommu_fault fault;
553-
volatile u64 *raw;
554-
int i;
555553

556554
INC_STATS_COUNTER(pri_requests);
557555

558-
raw = (u64 *)(iommu->ppr_log + head);
559-
560-
/*
561-
* Hardware bug: Interrupt may arrive before the entry is written to
562-
* memory. If this happens we need to wait for the entry to arrive.
563-
*/
564-
for (i = 0; i < LOOP_TIMEOUT; ++i) {
565-
if (PPR_REQ_TYPE(raw[0]) != 0)
566-
break;
567-
udelay(1);
568-
}
569-
570556
if (PPR_REQ_TYPE(raw[0]) != PPR_REQ_FAULT) {
571557
pr_err_ratelimited("AMD-Vi: Unknown PPR request received\n");
572558
return;
@@ -578,12 +564,6 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u32 head)
578564
fault.tag = PPR_TAG(raw[0]);
579565
fault.flags = PPR_FLAGS(raw[0]);
580566

581-
/*
582-
* To detect the hardware bug we need to clear the entry
583-
* to back to zero.
584-
*/
585-
raw[0] = raw[1] = 0;
586-
587567
atomic_notifier_call_chain(&ppr_notifier, 0, &fault);
588568
}
589569

@@ -595,25 +575,62 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu)
595575
if (iommu->ppr_log == NULL)
596576
return;
597577

578+
/* enable ppr interrupts again */
579+
writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET);
580+
598581
spin_lock_irqsave(&iommu->lock, flags);
599582

600583
head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
601584
tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
602585

603586
while (head != tail) {
587+
volatile u64 *raw;
588+
u64 entry[2];
589+
int i;
604590

605-
/* Handle PPR entry */
606-
iommu_handle_ppr_entry(iommu, head);
591+
raw = (u64 *)(iommu->ppr_log + head);
592+
593+
/*
594+
* Hardware bug: Interrupt may arrive before the entry is
595+
* written to memory. If this happens we need to wait for the
596+
* entry to arrive.
597+
*/
598+
for (i = 0; i < LOOP_TIMEOUT; ++i) {
599+
if (PPR_REQ_TYPE(raw[0]) != 0)
600+
break;
601+
udelay(1);
602+
}
603+
604+
/* Avoid memcpy function-call overhead */
605+
entry[0] = raw[0];
606+
entry[1] = raw[1];
607607

608-
/* Update and refresh ring-buffer state*/
608+
/*
609+
* To detect the hardware bug we need to clear the entry
610+
* back to zero.
611+
*/
612+
raw[0] = raw[1] = 0UL;
613+
614+
/* Update head pointer of hardware ring-buffer */
609615
head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
610616
writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
617+
618+
/*
619+
* Release iommu->lock because ppr-handling might need to
620+
* re-aquire it
621+
*/
622+
spin_unlock_irqrestore(&iommu->lock, flags);
623+
624+
/* Handle PPR entry */
625+
iommu_handle_ppr_entry(iommu, entry);
626+
627+
spin_lock_irqsave(&iommu->lock, flags);
628+
629+
/* Refresh ring-buffer information */
630+
head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
611631
tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
612632
}
613633

614-
/* enable ppr interrupts again */
615-
writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET);
616-
617634
spin_unlock_irqrestore(&iommu->lock, flags);
618635
}
619636

0 commit comments

Comments
 (0)