Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3a4e5978 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "iommu/arm-smmu: Replace while loop with for_each_set_bit"

parents 94e0b574 240d6f53
Loading
Loading
Loading
Loading
+93 −13
Original line number Diff line number Diff line
@@ -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))
@@ -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);
@@ -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;
}

@@ -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)
+11 −0
Original line number Diff line number Diff line
@@ -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)
@@ -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 */