Loading drivers/iommu/arm-smmu.c +93 −13 Original line number Diff line number Diff line Loading @@ -196,6 +196,8 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain, static int arm_smmu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data); static void __arm_smmu_tlb_sync_timeout(struct arm_smmu_device *smmu); static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu) { if (pm_runtime_enabled(smmu->dev)) Loading Loading @@ -887,7 +889,6 @@ static int __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, int sync, int status) { unsigned int inc, delay; u32 sync_inv_ack, tbu_pwr_status = -EINVAL, sync_inv_progress = -EINVAL; u32 reg; arm_smmu_writel(smmu, page, sync, QCOM_DUMMY_VAL); Loading @@ -902,19 +903,8 @@ static int __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, inc *= 2; } sync_inv_ack = arm_smmu_readl(smmu, ARM_SMMU_IMPL_DEF0, ARM_SMMU_STATS_SYNC_INV_TBU_ACK); qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_TBU_PWR_STATUS), &tbu_pwr_status); qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR), &sync_inv_progress); trace_tlbsync_timeout(smmu->dev, 0); dev_err_ratelimited(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked ack 0x%x pwr 0x%x sync and invalidation progress 0x%x\n", sync_inv_ack, tbu_pwr_status, sync_inv_progress); BUG_ON(IS_ENABLED(CONFIG_IOMMU_TLBSYNC_DEBUG)); __arm_smmu_tlb_sync_timeout(smmu); return -EINVAL; } Loading Loading @@ -5004,6 +4994,96 @@ struct qsmmuv500_group_iommudata { ((struct qsmmuv500_group_iommudata *) \ (iommu_group_get_iommudata(group))) static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu( struct arm_smmu_device *smmu, u32 sid); static void __arm_smmu_tlb_sync_timeout(struct arm_smmu_device *smmu) { u32 sync_inv_ack, tbu_pwr_status, sync_inv_progress; u32 tbu_inv_pending = 0, tbu_sync_pending = 0; u32 tbu_inv_acked = 0, tbu_sync_acked = 0; u32 tcu_inv_pending = 0, tcu_sync_pending = 0; u32 tbu_ids = 0; int ret; static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); dev_err_ratelimited(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n"); sync_inv_ack = arm_smmu_readl(smmu, ARM_SMMU_IMPL_DEF0, ARM_SMMU_STATS_SYNC_INV_TBU_ACK); ret = qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_TBU_PWR_STATUS), &tbu_pwr_status); if (ret) { dev_err_ratelimited(smmu->dev, "SCM read of TBU power status fails: %d\n", ret); goto out; } ret = qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR), &sync_inv_progress); if (ret) { dev_err_ratelimited(smmu->dev, "SCM read of TBU sync/inv prog fails: %d\n", ret); goto out; } if (sync_inv_ack) { tbu_inv_pending = FIELD_GET(TBU_INV_REQ, sync_inv_ack); tbu_inv_acked = FIELD_GET(TBU_INV_ACK, sync_inv_ack); tbu_sync_pending = FIELD_GET(TBU_SYNC_REQ, sync_inv_ack); tbu_sync_acked = FIELD_GET(TBU_SYNC_ACK, sync_inv_ack); } if (tbu_pwr_status) { if (tbu_sync_pending) tbu_ids = tbu_pwr_status & ~tbu_sync_acked; else if (tbu_inv_pending) tbu_ids = tbu_pwr_status & ~tbu_inv_acked; } tcu_inv_pending = FIELD_GET(TCU_INV_IN_PRGSS, sync_inv_progress); tcu_sync_pending = FIELD_GET(TCU_SYNC_IN_PRGSS, sync_inv_progress); if (__ratelimit(&_rs)) { unsigned long tbu_id; dev_err(smmu->dev, "TBU ACK 0x%x TBU PWR 0x%x TCU sync_inv 0x%x\n", sync_inv_ack, tbu_pwr_status, sync_inv_progress); dev_err(smmu->dev, "TCU invalidation %s, TCU sync %s\n", tcu_inv_pending?"pending":"completed", tcu_sync_pending?"pending":"completed"); for_each_set_bit(tbu_id, (unsigned long *) &tbu_ids, sizeof(tbu_ids) * BITS_PER_BYTE) { struct qsmmuv500_tbu_device *tbu; tbu = qsmmuv500_find_tbu(smmu, (u16)(tbu_id << TBUID_SHIFT)); if (tbu) { dev_err(smmu->dev, "TBU %s ack pending for TBU %s, %s\n", tbu_sync_pending?"sync" : "inv", dev_name(tbu->dev), tbu_sync_pending ? "check pending transactions on TBU" : "check for TBU power status"); } } } out: BUG_ON(IS_ENABLED(CONFIG_IOMMU_TLBSYNC_DEBUG)); } static bool arm_smmu_fwspec_match_smr(struct iommu_fwspec *fwspec, struct arm_smmu_smr *smr) Loading drivers/iommu/arm-smmu.h +11 −0 Original line number Diff line number Diff line Loading @@ -229,10 +229,18 @@ enum arm_smmu_cbar_type { /* Implementation Defined Register Space 0 registers*/ /* Relative to IMPL_DEF_0 page */ #define ARM_SMMU_STATS_SYNC_INV_TBU_ACK 0x5dc #define TBU_SYNC_ACK GENMASK(25, 17) #define TBU_SYNC_REQ BIT(16) #define TBU_INV_ACK GENMASK(9, 1) #define TBU_INV_REQ BIT(0) /* Relative to SMMU_BASE */ #define ARM_SMMU_TBU_PWR_STATUS 0x2204 /* Relative SMMU_BASE */ #define ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x2670 #define TCU_SYNC_IN_PRGSS BIT(20) #define TCU_INV_IN_PRGSS BIT(16) #define ARM_SMMU_CB_ATSR 0x8f0 #define ATSR_ACTIVE BIT(0) Loading Loading @@ -503,4 +511,7 @@ static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page, struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu); /* Misc. constants */ #define TBUID_SHIFT 10 #endif /* _ARM_SMMU_H */ Loading
drivers/iommu/arm-smmu.c +93 −13 Original line number Diff line number Diff line Loading @@ -196,6 +196,8 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain, static int arm_smmu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data); static void __arm_smmu_tlb_sync_timeout(struct arm_smmu_device *smmu); static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu) { if (pm_runtime_enabled(smmu->dev)) Loading Loading @@ -887,7 +889,6 @@ static int __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, int sync, int status) { unsigned int inc, delay; u32 sync_inv_ack, tbu_pwr_status = -EINVAL, sync_inv_progress = -EINVAL; u32 reg; arm_smmu_writel(smmu, page, sync, QCOM_DUMMY_VAL); Loading @@ -902,19 +903,8 @@ static int __arm_smmu_tlb_sync(struct arm_smmu_device *smmu, int page, inc *= 2; } sync_inv_ack = arm_smmu_readl(smmu, ARM_SMMU_IMPL_DEF0, ARM_SMMU_STATS_SYNC_INV_TBU_ACK); qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_TBU_PWR_STATUS), &tbu_pwr_status); qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR), &sync_inv_progress); trace_tlbsync_timeout(smmu->dev, 0); dev_err_ratelimited(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked ack 0x%x pwr 0x%x sync and invalidation progress 0x%x\n", sync_inv_ack, tbu_pwr_status, sync_inv_progress); BUG_ON(IS_ENABLED(CONFIG_IOMMU_TLBSYNC_DEBUG)); __arm_smmu_tlb_sync_timeout(smmu); return -EINVAL; } Loading Loading @@ -5004,6 +4994,96 @@ struct qsmmuv500_group_iommudata { ((struct qsmmuv500_group_iommudata *) \ (iommu_group_get_iommudata(group))) static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu( struct arm_smmu_device *smmu, u32 sid); static void __arm_smmu_tlb_sync_timeout(struct arm_smmu_device *smmu) { u32 sync_inv_ack, tbu_pwr_status, sync_inv_progress; u32 tbu_inv_pending = 0, tbu_sync_pending = 0; u32 tbu_inv_acked = 0, tbu_sync_acked = 0; u32 tcu_inv_pending = 0, tcu_sync_pending = 0; u32 tbu_ids = 0; int ret; static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); dev_err_ratelimited(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n"); sync_inv_ack = arm_smmu_readl(smmu, ARM_SMMU_IMPL_DEF0, ARM_SMMU_STATS_SYNC_INV_TBU_ACK); ret = qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_TBU_PWR_STATUS), &tbu_pwr_status); if (ret) { dev_err_ratelimited(smmu->dev, "SCM read of TBU power status fails: %d\n", ret); goto out; } ret = qcom_scm_io_readl((unsigned long)(smmu->phys_addr + ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR), &sync_inv_progress); if (ret) { dev_err_ratelimited(smmu->dev, "SCM read of TBU sync/inv prog fails: %d\n", ret); goto out; } if (sync_inv_ack) { tbu_inv_pending = FIELD_GET(TBU_INV_REQ, sync_inv_ack); tbu_inv_acked = FIELD_GET(TBU_INV_ACK, sync_inv_ack); tbu_sync_pending = FIELD_GET(TBU_SYNC_REQ, sync_inv_ack); tbu_sync_acked = FIELD_GET(TBU_SYNC_ACK, sync_inv_ack); } if (tbu_pwr_status) { if (tbu_sync_pending) tbu_ids = tbu_pwr_status & ~tbu_sync_acked; else if (tbu_inv_pending) tbu_ids = tbu_pwr_status & ~tbu_inv_acked; } tcu_inv_pending = FIELD_GET(TCU_INV_IN_PRGSS, sync_inv_progress); tcu_sync_pending = FIELD_GET(TCU_SYNC_IN_PRGSS, sync_inv_progress); if (__ratelimit(&_rs)) { unsigned long tbu_id; dev_err(smmu->dev, "TBU ACK 0x%x TBU PWR 0x%x TCU sync_inv 0x%x\n", sync_inv_ack, tbu_pwr_status, sync_inv_progress); dev_err(smmu->dev, "TCU invalidation %s, TCU sync %s\n", tcu_inv_pending?"pending":"completed", tcu_sync_pending?"pending":"completed"); for_each_set_bit(tbu_id, (unsigned long *) &tbu_ids, sizeof(tbu_ids) * BITS_PER_BYTE) { struct qsmmuv500_tbu_device *tbu; tbu = qsmmuv500_find_tbu(smmu, (u16)(tbu_id << TBUID_SHIFT)); if (tbu) { dev_err(smmu->dev, "TBU %s ack pending for TBU %s, %s\n", tbu_sync_pending?"sync" : "inv", dev_name(tbu->dev), tbu_sync_pending ? "check pending transactions on TBU" : "check for TBU power status"); } } } out: BUG_ON(IS_ENABLED(CONFIG_IOMMU_TLBSYNC_DEBUG)); } static bool arm_smmu_fwspec_match_smr(struct iommu_fwspec *fwspec, struct arm_smmu_smr *smr) Loading
drivers/iommu/arm-smmu.h +11 −0 Original line number Diff line number Diff line Loading @@ -229,10 +229,18 @@ enum arm_smmu_cbar_type { /* Implementation Defined Register Space 0 registers*/ /* Relative to IMPL_DEF_0 page */ #define ARM_SMMU_STATS_SYNC_INV_TBU_ACK 0x5dc #define TBU_SYNC_ACK GENMASK(25, 17) #define TBU_SYNC_REQ BIT(16) #define TBU_INV_ACK GENMASK(9, 1) #define TBU_INV_REQ BIT(0) /* Relative to SMMU_BASE */ #define ARM_SMMU_TBU_PWR_STATUS 0x2204 /* Relative SMMU_BASE */ #define ARM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x2670 #define TCU_SYNC_IN_PRGSS BIT(20) #define TCU_INV_IN_PRGSS BIT(16) #define ARM_SMMU_CB_ATSR 0x8f0 #define ATSR_ACTIVE BIT(0) Loading Loading @@ -503,4 +511,7 @@ static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page, struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu); /* Misc. constants */ #define TBUID_SHIFT 10 #endif /* _ARM_SMMU_H */