diff options
Diffstat (limited to 'drivers/iommu/intel/dmar.c')
| -rw-r--r-- | drivers/iommu/intel/dmar.c | 72 | 
1 files changed, 65 insertions, 7 deletions
| diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index d5c51b5c20af..1757ac1e1623 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -1140,9 +1140,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)  		if (err)  			goto err_unmap; -		iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops); - -		err = iommu_device_register(&iommu->iommu); +		err = iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);  		if (err)  			goto err_unmap;  	} @@ -1205,6 +1203,63 @@ static inline void reclaim_free_desc(struct q_inval *qi)  	}  } +static const char *qi_type_string(u8 type) +{ +	switch (type) { +	case QI_CC_TYPE: +		return "Context-cache Invalidation"; +	case QI_IOTLB_TYPE: +		return "IOTLB Invalidation"; +	case QI_DIOTLB_TYPE: +		return "Device-TLB Invalidation"; +	case QI_IEC_TYPE: +		return "Interrupt Entry Cache Invalidation"; +	case QI_IWD_TYPE: +		return "Invalidation Wait"; +	case QI_EIOTLB_TYPE: +		return "PASID-based IOTLB Invalidation"; +	case QI_PC_TYPE: +		return "PASID-cache Invalidation"; +	case QI_DEIOTLB_TYPE: +		return "PASID-based Device-TLB Invalidation"; +	case QI_PGRP_RESP_TYPE: +		return "Page Group Response"; +	default: +		return "UNKNOWN"; +	} +} + +static void qi_dump_fault(struct intel_iommu *iommu, u32 fault) +{ +	unsigned int head = dmar_readl(iommu->reg + DMAR_IQH_REG); +	u64 iqe_err = dmar_readq(iommu->reg + DMAR_IQER_REG); +	struct qi_desc *desc = iommu->qi->desc + head; + +	if (fault & DMA_FSTS_IQE) +		pr_err("VT-d detected Invalidation Queue Error: Reason %llx", +		       DMAR_IQER_REG_IQEI(iqe_err)); +	if (fault & DMA_FSTS_ITE) +		pr_err("VT-d detected Invalidation Time-out Error: SID %llx", +		       DMAR_IQER_REG_ITESID(iqe_err)); +	if (fault & DMA_FSTS_ICE) +		pr_err("VT-d detected Invalidation Completion Error: SID %llx", +		       DMAR_IQER_REG_ICESID(iqe_err)); + +	pr_err("QI HEAD: %s qw0 = 0x%llx, qw1 = 0x%llx\n", +	       qi_type_string(desc->qw0 & 0xf), +	       (unsigned long long)desc->qw0, +	       (unsigned long long)desc->qw1); + +	head = ((head >> qi_shift(iommu)) + QI_LENGTH - 1) % QI_LENGTH; +	head <<= qi_shift(iommu); +	desc = iommu->qi->desc + head; + +	pr_err("QI PRIOR: %s qw0 = 0x%llx, qw1 = 0x%llx\n", +	       qi_type_string(desc->qw0 & 0xf), +	       (unsigned long long)desc->qw0, +	       (unsigned long long)desc->qw1); +} +  static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)  {  	u32 fault; @@ -1216,6 +1271,8 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)  		return -EAGAIN;  	fault = readl(iommu->reg + DMAR_FSTS_REG); +	if (fault & (DMA_FSTS_IQE | DMA_FSTS_ITE | DMA_FSTS_ICE)) +		qi_dump_fault(iommu, fault);  	/*  	 * If IQE happens, the head points to the descriptor associated @@ -1232,12 +1289,10 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)  			 * used by software as private data. We won't print  			 * out these two qw's for security consideration.  			 */ -			pr_err("VT-d detected invalid descriptor: qw0 = %llx, qw1 = %llx\n", -			       (unsigned long long)desc->qw0, -			       (unsigned long long)desc->qw1);  			memcpy(desc, qi->desc + (wait_index << shift),  			       1 << shift);  			writel(DMA_FSTS_IQE, iommu->reg + DMAR_FSTS_REG); +			pr_info("Invalidation Queue Error (IQE) cleared\n");  			return -EINVAL;  		}  	} @@ -1254,6 +1309,7 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)  		tail = ((tail >> shift) - 1 + QI_LENGTH) % QI_LENGTH;  		writel(DMA_FSTS_ITE, iommu->reg + DMAR_FSTS_REG); +		pr_info("Invalidation Time-out Error (ITE) cleared\n");  		do {  			if (qi->desc_status[head] == QI_IN_USE) @@ -1265,8 +1321,10 @@ static int qi_check_fault(struct intel_iommu *iommu, int index, int wait_index)  			return -EAGAIN;  	} -	if (fault & DMA_FSTS_ICE) +	if (fault & DMA_FSTS_ICE) {  		writel(DMA_FSTS_ICE, iommu->reg + DMAR_FSTS_REG); +		pr_info("Invalidation Completion Error (ICE) cleared\n"); +	}  	return 0;  } | 
