aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorJoerg Roedel <joro@8bytes.org>2013-04-18 11:55:04 -0400
committerJoerg Roedel <joro@8bytes.org>2013-04-19 14:53:26 -0400
commitd3263bc29706e42f74d8800807c2dedf320d77f1 (patch)
tree7a1208b29e81c620265899b2b9a940e5a7328ed9 /drivers/iommu
parent7d8bfa26f236bc9528415402dda6b498a0682e42 (diff)
iommu/amd: Workaround for ERBT1312
Work around an IOMMU hardware bug where clearing the EVT_INT or PPR_INT bit in the status register may race with the hardware trying to set it again. When not handled the bit might not be cleared and we lose all future event or ppr interrupts. Reported-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Cc: stable@vger.kernel.org Signed-off-by: Joerg Roedel <joro@8bytes.org>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/amd_iommu.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index f42793d1574d..27792f8c429d 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -700,14 +700,23 @@ retry:
700 700
701static void iommu_poll_events(struct amd_iommu *iommu) 701static void iommu_poll_events(struct amd_iommu *iommu)
702{ 702{
703 u32 head, tail; 703 u32 head, tail, status;
704 unsigned long flags; 704 unsigned long flags;
705 705
706 /* enable event interrupts again */
707 writel(MMIO_STATUS_EVT_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET);
708
709 spin_lock_irqsave(&iommu->lock, flags); 706 spin_lock_irqsave(&iommu->lock, flags);
710 707
708 /* enable event interrupts again */
709 do {
710 /*
711 * Workaround for Erratum ERBT1312
712 * Clearing the EVT_INT bit may race in the hardware, so read
713 * it again and make sure it was really cleared
714 */
715 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
716 writel(MMIO_STATUS_EVT_INT_MASK,
717 iommu->mmio_base + MMIO_STATUS_OFFSET);
718 } while (status & MMIO_STATUS_EVT_INT_MASK);
719
711 head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET); 720 head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
712 tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET); 721 tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
713 722
@@ -744,16 +753,25 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw)
744static void iommu_poll_ppr_log(struct amd_iommu *iommu) 753static void iommu_poll_ppr_log(struct amd_iommu *iommu)
745{ 754{
746 unsigned long flags; 755 unsigned long flags;
747 u32 head, tail; 756 u32 head, tail, status;
748 757
749 if (iommu->ppr_log == NULL) 758 if (iommu->ppr_log == NULL)
750 return; 759 return;
751 760
752 /* enable ppr interrupts again */
753 writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET);
754
755 spin_lock_irqsave(&iommu->lock, flags); 761 spin_lock_irqsave(&iommu->lock, flags);
756 762
763 /* enable ppr interrupts again */
764 do {
765 /*
766 * Workaround for Erratum ERBT1312
767 * Clearing the PPR_INT bit may race in the hardware, so read
768 * it again and make sure it was really cleared
769 */
770 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
771 writel(MMIO_STATUS_PPR_INT_MASK,
772 iommu->mmio_base + MMIO_STATUS_OFFSET);
773 } while (status & MMIO_STATUS_PPR_INT_MASK);
774
757 head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); 775 head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
758 tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); 776 tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
759 777