diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index d02ce95edb17..a190f62923ab 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1271,6 +1271,43 @@ static phys_addr_t arm_smmu_verify_fault(struct iommu_domain *domain, return (phys_stimu == 0 ? phys_stimu_post_tlbiall : phys_stimu); } +int iommu_get_fault_ids(struct iommu_domain *domain, + struct iommu_fault_ids *f_ids) +{ + struct arm_smmu_domain *smmu_domain; + struct arm_smmu_device *smmu; + u32 fsr, fsynr1; + int idx, ret; + + if (!domain || !f_ids) + return -EINVAL; + + smmu_domain = to_smmu_domain(domain); + smmu = smmu_domain->smmu; + idx = smmu_domain->cfg.cbndx; + + ret = arm_smmu_power_on(smmu->pwr); + if (ret) + return ret; + + fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR); + + if (!(fsr & FSR_FAULT)) { + arm_smmu_power_off(smmu, smmu->pwr); + return -EINVAL; + } + + fsynr1 = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSYNR1); + arm_smmu_power_off(smmu, smmu->pwr); + + f_ids->bid = FIELD_GET(FSYNR1_BID, fsynr1); + f_ids->pid = FIELD_GET(FSYNR1_PID, fsynr1); + f_ids->mid = FIELD_GET(FSYNR1_MID, fsynr1); + + return 0; +} +EXPORT_SYMBOL(iommu_get_fault_ids); + static irqreturn_t arm_smmu_context_fault(int irq, void *dev) { int flags, ret, tmp; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index adbf54c068f2..a4ee89d3509c 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -65,6 +65,12 @@ typedef int (*iommu_mm_exit_handler_t)(struct device *dev, struct iommu_sva *, void *); typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *); +struct iommu_fault_ids { + u32 bid; + u32 pid; + u32 mid; +}; + struct iommu_domain_geometry { dma_addr_t aperture_start; /* First address that can be mapped */ dma_addr_t aperture_end; /* Last address that can be mapped */ @@ -544,7 +550,8 @@ extern bool iommu_is_iova_coherent(struct iommu_domain *domain, dma_addr_t iova); extern void iommu_set_fault_handler(struct iommu_domain *domain, iommu_fault_handler_t handler, void *token); - +extern int iommu_get_fault_ids(struct iommu_domain *domain, + struct iommu_fault_ids *f_ids); extern void iommu_get_resv_regions(struct device *dev, struct list_head *list); extern void iommu_put_resv_regions(struct device *dev, struct list_head *list); extern int iommu_request_dm_for_dev(struct device *dev); @@ -868,6 +875,11 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain, iommu_fault_handler_t handler, void *token) { } +static inline int iommu_get_fault_ids(struct iommu_domain *domain, + struct iommu_fault_ids *f_ids) +{ + return -EINVAL; +} static inline void iommu_get_resv_regions(struct device *dev, struct list_head *list)