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

Commit 2c793736 authored by Isaac J. Manjarres's avatar Isaac J. Manjarres
Browse files

iommu/arm-smmu: Leave power resources enabled across unmap and sync ops



The votes for power resources can only be removed if there are no
outstanding TLB invalidation operations. This is true when the
downstream io-pgtable-arm optimizations are in use, as the code that
unmaps the memory from the IOMMU page tables ensures that all TLB
operations are complete before returning.

However, the upstream io-pgtable-arm implementation allows for a TLB
invalidation to be in progress when control is returned back to
arm_smmu_unmap(), at which point the votes for the power resources
will be removed. In cases where the GPU is in slumber, the GPU block
and GPU SMMU get powered down when the SMMU driver removes its votes.
This causes problems where unmapping buffers takes a long time.

For scenarios where it is not feasible to guarantee that TLB
invalidations have completed when control is returned to the
arm_smmu_unmap() function, leave the votes for power resources in place,
and rely on the subsequent sync operation to remove the votes.

Change-Id: Idc594cc69860b44a8eb56c72b5c592bf4799bf84
Signed-off-by: default avatarIsaac J. Manjarres <isaacm@codeaurora.org>
parent dc88450c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_QCOM_IOMMU_IO_PGTABLE_QUIRKS=y
CONFIG_IOMMU_LIMIT_IOVA_ALIGNMENT=y
CONFIG_ARM_SMMU_SKIP_MAP_POWER_ON=y
CONFIG_ARM_SMMU_POWER_OFF_AFTER_UNMAP=y
CONFIG_QTI_IOMMU_SUPPORT=y
CONFIG_QCOM_SCM=y
CONFIG_QCOM_SECURE_BUFFER=y
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ CONFIG_QCOM_LAZY_MAPPING=y
CONFIG_DEBUG_FS=y
CONFIG_IOMMU_DYNAMIC_DOMAINS=y
CONFIG_ARM_SMMU_SKIP_MAP_POWER_ON=y
CONFIG_ARM_SMMU_POWER_OFF_AFTER_UNMAP=y
CONFIG_QCOM_SECURE_BUFFER=y
# CONFIG_ZONE_DMA32 is not set
CONFIG_EDAC_KRYO_ARM64=y
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ CONFIG_ION_MSM_HEAPS=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_IOMMU_DYNAMIC_DOMAINS=y
CONFIG_ARM_SMMU_SKIP_MAP_POWER_ON=y
CONFIG_ARM_SMMU_POWER_OFF_AFTER_UNMAP=y
# CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST is not set
# CONFIG_IOMMU_IO_PGTABLE_FAST_PROVE_TLB is not set
# CONFIG_SOFTLOCKUP_DETECTOR is not set
+9 −0
Original line number Diff line number Diff line
@@ -548,6 +548,15 @@ config ARM_SMMU_SKIP_MAP_POWER_ON

	  If unsure, say N here.

config ARM_SMMU_POWER_OFF_AFTER_UNMAP
	bool "Remove power votes after unmapping memory"
	depends on ARM_SMMU && QGKI
	help
	  Support for ensuring that votes for power resources are removed
	  after memory is unmapped. This should be enabled when it is guaranteed
	  that there are no outstanding TLB invalidations after the memory
	  has been unmapped from the IOMMU page tables.

config ARM_SMMU_V3
	tristate "ARM Ltd. System MMU Version 3 (SMMUv3) Support"
	depends on ARM64
+24 −0
Original line number Diff line number Diff line
@@ -3235,9 +3235,25 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
	spin_lock_irqsave(&smmu_domain->cb_lock, flags);
	ret = ops->unmap(ops, iova, size, gather);
	spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
	/*
	 * The votes for power resources can only be removed if there are no
	 * outstanding TLB invalidation operations. This is true when the
	 * downstream io-pgtable-arm optimizations are in use, as the code that
	 * unmaps the memory from the IOMMU page tables ensures that all TLB
	 * operations are complete before returning.
	 *
	 * However, the upstream io-pgtable-arm implementation allows for a TLB
	 * invalidation to be in progress when control is returned back here,
	 * and the votes for the power resources will be removed, which has been
	 * observed to cause problems where unmapping buffers takes a long time.
	 * For those scenarios, leave the votes for power resources in place,
	 * and rely on the subsequent sync operation to remove the votes.
	 */
#ifdef CONFIG_ARM_SMMU_POWER_OFF_AFTER_UNMAP
	arm_smmu_rpm_put(smmu);

	arm_smmu_domain_power_off(domain, smmu_domain->smmu);
#endif
	/*
	 * While splitting up block mappings, we might allocate page table
	 * memory during unmap, so the vmids needs to be assigned to the
@@ -3275,12 +3291,20 @@ static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
	struct arm_smmu_device *smmu = smmu_domain->smmu;

	if (smmu_domain->flush_ops) {
		/*
		 * Voting for power resources when
		 * CONFIG_ARM_SMMU_POWER_OFF_AFTER_UNMAP is enabled, is required
		 * as the unmap call has removed the votes for the power
		 * resources.
		 */
#ifdef CONFIG_ARM_SMMU_POWER_OFF_AFTER_UNMAP
		arm_smmu_rpm_get(smmu);
		if (arm_smmu_domain_power_on(domain, smmu)) {
			WARN_ON(1);
			arm_smmu_rpm_put(smmu);
			return;
		}
#endif
		smmu_domain->flush_ops->tlb_sync(smmu_domain);
		arm_smmu_domain_power_off(domain, smmu);
		arm_smmu_rpm_put(smmu);