Merge remote-tracking branch 'pfdo/drm-fixes' into drm-next
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / dmar.c
index b8008f679bc72074b4156b85dc65ecce74824d44..a7967ceb79e6f20336354c14ae9511eb3e79c20b 100644 (file)
@@ -646,7 +646,7 @@ out:
 int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
        struct intel_iommu *iommu;
-       u32 ver;
+       u32 ver, sts;
        static int iommu_allocated = 0;
        int agaw = 0;
        int msagaw = 0;
@@ -696,6 +696,15 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
                (unsigned long long)iommu->cap,
                (unsigned long long)iommu->ecap);
 
+       /* Reflect status in gcmd */
+       sts = readl(iommu->reg + DMAR_GSTS_REG);
+       if (sts & DMA_GSTS_IRES)
+               iommu->gcmd |= DMA_GCMD_IRE;
+       if (sts & DMA_GSTS_TES)
+               iommu->gcmd |= DMA_GCMD_TE;
+       if (sts & DMA_GSTS_QIES)
+               iommu->gcmd |= DMA_GCMD_QIE;
+
        raw_spin_lock_init(&iommu->register_lock);
 
        drhd->iommu = iommu;
@@ -1205,7 +1214,7 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
 
        /* TBD: ignore advanced fault log currently */
        if (!(fault_status & DMA_FSTS_PPF))
-               goto clear_rest;
+               goto unlock_exit;
 
        fault_index = dma_fsts_fault_record_index(fault_status);
        reg = cap_fault_reg_offset(iommu->cap);
@@ -1246,11 +1255,10 @@ irqreturn_t dmar_fault(int irq, void *dev_id)
                        fault_index = 0;
                raw_spin_lock_irqsave(&iommu->register_lock, flag);
        }
-clear_rest:
-       /* clear all the other faults */
-       fault_status = readl(iommu->reg + DMAR_FSTS_REG);
-       writel(fault_status, iommu->reg + DMAR_FSTS_REG);
 
+       writel(DMA_FSTS_PFO | DMA_FSTS_PPF, iommu->reg + DMAR_FSTS_REG);
+
+unlock_exit:
        raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
        return IRQ_HANDLED;
 }
@@ -1298,6 +1306,7 @@ int __init enable_drhd_fault_handling(void)
        for_each_drhd_unit(drhd) {
                int ret;
                struct intel_iommu *iommu = drhd->iommu;
+               u32 fault_status;
                ret = dmar_set_interrupt(iommu);
 
                if (ret) {
@@ -1310,6 +1319,8 @@ int __init enable_drhd_fault_handling(void)
                 * Clear any previous faults.
                 */
                dmar_fault(iommu->irq, iommu);
+               fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+               writel(fault_status, iommu->reg + DMAR_FSTS_REG);
        }
 
        return 0;