Loading drivers/iommu/arm-smmu-regs.h +4 −0 Original line number Diff line number Diff line Loading @@ -276,4 +276,8 @@ enum arm_smmu_s2cr_privcfg { #define ACTLR_QCOM_NSH_SHIFT 30 #define ACTLR_QCOM_NSH 1 #define FSYNR1_BID GENMASK(15, 13) #define FSYNR1_PID GENMASK(12, 8) #define FSYNR1_MID GENMASK(7, 0) #endif /* _ARM_SMMU_REGS_H */ drivers/iommu/arm-smmu.c +51 −2 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ #include "iommu-logger.h" #include <linux/debugfs.h> #include <linux/uaccess.h> #include <linux/bitfield.h> /* * Apparently, some Qualcomm arm64 platforms which appear to expose their SMMU Loading Loading @@ -156,7 +157,6 @@ struct arm_smmu_impl_def_reg { u32 value; }; /* * attach_count * The SMR and S2CR registers are only programmed when the number of Loading Loading @@ -1981,6 +1981,46 @@ 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_cfg *cfg; struct arm_smmu_device *smmu; void __iomem *cb_base; u32 fsr, fsynr1; int ret; if (!domain || !f_ids) return -EINVAL; smmu_domain = to_smmu_domain(domain); cfg = &smmu_domain->cfg; smmu = smmu_domain->smmu; ret = arm_smmu_power_on(smmu->pwr); if (ret) return ret; cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); if (!(fsr & FSR_FAULT)) { arm_smmu_power_off(smmu->pwr); return -EINVAL; } fsynr1 = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR1); arm_smmu_power_off(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; Loading Loading @@ -2042,6 +2082,11 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) dev_dbg(smmu->dev, "Context fault handled by client: iova=0x%08lx, cb=%d, fsr=0x%x, fsynr0=0x%x, fsynr1=0x%x\n", iova, cfg->cbndx, fsr, fsynr0, fsynr1); dev_dbg(smmu->dev, "Client info: BID=0x%x, PID=0x%x, MID=0x%x\n", FIELD_GET(FSYNR1_BID, fsynr1), FIELD_GET(FSYNR1_PID, fsynr1), FIELD_GET(FSYNR1_MID, fsynr1)); dev_dbg(smmu->dev, "soft iova-to-phys=%pa\n", &phys_soft); ret = IRQ_HANDLED; Loading @@ -2056,7 +2101,11 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) dev_err(smmu->dev, "Unhandled context fault: iova=0x%08lx, cb=%d, fsr=0x%x, fsynr0=0x%x, fsynr1=0x%x\n", iova, cfg->cbndx, fsr, fsynr0, fsynr1); dev_err(smmu->dev, "Client info: BID=0x%x, PID=0x%x, MID=0x%x\n", FIELD_GET(FSYNR1_BID, fsynr1), FIELD_GET(FSYNR1_PID, fsynr1), FIELD_GET(FSYNR1_MID, fsynr1)); dev_err(smmu->dev, "soft iova-to-phys=%pa\n", &phys_soft); Loading include/linux/iommu.h +13 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,12 @@ struct notifier_block; typedef int (*iommu_fault_handler_t)(struct iommu_domain *, struct device *, unsigned long, int, 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 */ Loading Loading @@ -385,7 +391,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); Loading Loading @@ -631,6 +638,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) Loading Loading
drivers/iommu/arm-smmu-regs.h +4 −0 Original line number Diff line number Diff line Loading @@ -276,4 +276,8 @@ enum arm_smmu_s2cr_privcfg { #define ACTLR_QCOM_NSH_SHIFT 30 #define ACTLR_QCOM_NSH 1 #define FSYNR1_BID GENMASK(15, 13) #define FSYNR1_PID GENMASK(12, 8) #define FSYNR1_MID GENMASK(7, 0) #endif /* _ARM_SMMU_REGS_H */
drivers/iommu/arm-smmu.c +51 −2 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ #include "iommu-logger.h" #include <linux/debugfs.h> #include <linux/uaccess.h> #include <linux/bitfield.h> /* * Apparently, some Qualcomm arm64 platforms which appear to expose their SMMU Loading Loading @@ -156,7 +157,6 @@ struct arm_smmu_impl_def_reg { u32 value; }; /* * attach_count * The SMR and S2CR registers are only programmed when the number of Loading Loading @@ -1981,6 +1981,46 @@ 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_cfg *cfg; struct arm_smmu_device *smmu; void __iomem *cb_base; u32 fsr, fsynr1; int ret; if (!domain || !f_ids) return -EINVAL; smmu_domain = to_smmu_domain(domain); cfg = &smmu_domain->cfg; smmu = smmu_domain->smmu; ret = arm_smmu_power_on(smmu->pwr); if (ret) return ret; cb_base = ARM_SMMU_CB(smmu, cfg->cbndx); fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); if (!(fsr & FSR_FAULT)) { arm_smmu_power_off(smmu->pwr); return -EINVAL; } fsynr1 = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR1); arm_smmu_power_off(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; Loading Loading @@ -2042,6 +2082,11 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) dev_dbg(smmu->dev, "Context fault handled by client: iova=0x%08lx, cb=%d, fsr=0x%x, fsynr0=0x%x, fsynr1=0x%x\n", iova, cfg->cbndx, fsr, fsynr0, fsynr1); dev_dbg(smmu->dev, "Client info: BID=0x%x, PID=0x%x, MID=0x%x\n", FIELD_GET(FSYNR1_BID, fsynr1), FIELD_GET(FSYNR1_PID, fsynr1), FIELD_GET(FSYNR1_MID, fsynr1)); dev_dbg(smmu->dev, "soft iova-to-phys=%pa\n", &phys_soft); ret = IRQ_HANDLED; Loading @@ -2056,7 +2101,11 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) dev_err(smmu->dev, "Unhandled context fault: iova=0x%08lx, cb=%d, fsr=0x%x, fsynr0=0x%x, fsynr1=0x%x\n", iova, cfg->cbndx, fsr, fsynr0, fsynr1); dev_err(smmu->dev, "Client info: BID=0x%x, PID=0x%x, MID=0x%x\n", FIELD_GET(FSYNR1_BID, fsynr1), FIELD_GET(FSYNR1_PID, fsynr1), FIELD_GET(FSYNR1_MID, fsynr1)); dev_err(smmu->dev, "soft iova-to-phys=%pa\n", &phys_soft); Loading
include/linux/iommu.h +13 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,12 @@ struct notifier_block; typedef int (*iommu_fault_handler_t)(struct iommu_domain *, struct device *, unsigned long, int, 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 */ Loading Loading @@ -385,7 +391,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); Loading Loading @@ -631,6 +638,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) Loading