From: Joerg Roedel Date: Thu, 2 May 2013 10:10:19 +0000 (+0200) Subject: Merge branches 'iommu/fixes', 'x86/vt-d', 'x86/amd', 'ppc/pamu', 'core' and 'arm... X-Git-Tag: v3.12-rc1~888^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0c4513be3d01a854867446ee793748409cc0ebdf;p=kernel%2Fkernel-generic.git Merge branches 'iommu/fixes', 'x86/vt-d', 'x86/amd', 'ppc/pamu', 'core' and 'arm/tegra' into next --- 0c4513be3d01a854867446ee793748409cc0ebdf diff --cc drivers/iommu/amd_iommu.c index 98f555d,c6f3c7e,a7f6b04,685f282,b287ca3..1d84be1 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@@@@@ -807,13 -786,39 -807,13 -802,13 -807,13 +781,39 @@@@@@ static void iommu_poll_ppr_log(struct a irqreturn_t amd_iommu_int_thread(int irq, void *data) { - --- struct amd_iommu *iommu; + +++ struct amd_iommu *iommu = (struct amd_iommu *) data; + +++ u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); - --- for_each_iommu(iommu) { - --- iommu_poll_events(iommu); - --- iommu_poll_ppr_log(iommu); - --- } + +++ while (status & (MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK)) { + +++ /* Enable EVT and PPR interrupts again */ + +++ writel((MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK), + +++ iommu->mmio_base + MMIO_STATUS_OFFSET); + + + +++ if (status & MMIO_STATUS_EVT_INT_MASK) { + +++ pr_devel("AMD-Vi: Processing IOMMU Event Log\n"); + +++ iommu_poll_events(iommu); + +++ } + + + + +++ if (status & MMIO_STATUS_PPR_INT_MASK) { + +++ pr_devel("AMD-Vi: Processing IOMMU PPR Log\n"); + +++ iommu_poll_ppr_log(iommu); + +++ } +++ + +++ /* + +++ * Hardware bug: ERBT1312 + +++ * When re-enabling interrupt (by writing 1 + +++ * to clear the bit), the hardware might also try to set + +++ * the interrupt bit in the event status register. + +++ * In this scenario, the bit will be set, and disable + +++ * subsequent interrupts. + +++ * + +++ * Workaround: The IOMMU driver should read back the + +++ * status register and check if the interrupt bits are cleared. + +++ * If not, driver will need to go through the interrupt handler + +++ * again and re-clear the bits + +++ */ + +++ status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET); + +++ } return IRQ_HANDLED; }