From 7931d3dddf57576cc6491fd71bc08365ba9efdf3 Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Fri, 5 Jun 2020 03:09:22 +0530 Subject: [PATCH] iommu: add a function to get MID/PID/BID info For certain use cases SID remains same and when an smmu page fault occurs it becomes difficult for client to identify which of the usecases is actually causing the fault. In such cases MID/PID/BID info can help. So, add a function for the same so that clients can call this from their fault handler and get the info. Change-Id: Ia720641224f908287ae1d66908ab12def82bbbab Signed-off-by: Vijayanand Jitta --- drivers/iommu/arm-smmu.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/iommu.h | 14 +++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) 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)