diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c89039fad7ff..a30f891a391e 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -548,6 +548,18 @@ config ARM_SMMU_SKIP_MAP_POWER_ON If unsure, say N here. +config ARM_SMMU_POWER_ALWAYS_ON + bool "Never remove SMMU power resource votes" + depends on ARM_SMMU && !QGKI + help + Support for never removing SMMU power resource votes (i.e. + regulator, clocks, and interconnect votes). Never removing the + power resource votes allows for less time to be spent by the SMMU + driver in voting for power resources when it is actively working for + an extended period of time. + + If unsure, say N here. + config ARM_SMMU_V3 tristate "ARM Ltd. System MMU Version 3 (SMMUv3) Support" depends on ARM64 diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 6d1a12297aad..fc6aa7448c3d 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -5049,6 +5049,28 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) arm_smmu_interrupt_selftest(smmu); arm_smmu_power_off(smmu, smmu->pwr); + /* + * On GKI, we use the upstream implementation of the IOMMU page table + * management code, which lacks all of the optimizations that we have + * downstream to speed up calls into the SMMU driver to unmap memory. + * + * When the GPU goes into slumber, it relinquishes its votes for + * the regulators and clocks that the SMMU driver votes for. This + * means that when the SMMU driver adds/removes votes for the + * power resources required to access the GPU SMMU registers for + * TLB invalidations while unmapping memory, the SMMU driver has to + * wait for the resources to actually turn on/off, which incurs a + * considerable amount of delay. + * + * This delay, coupled with the use of the unoptimized IOMMU page table + * management code in GKI results in slow unmap calls. To alleviate + * that, we can remove the latency incurred by enabling/disabling the + * power resources, by always keeping them on. + */ + if (IS_ENABLED(CONFIG_ARM_SMMU_POWER_ALWAYS_ON) && + of_property_read_bool(dev->of_node, "qcom,power-always-on")) + arm_smmu_power_on(smmu->pwr); + /* * We want to avoid touching dev->power.lock in fastpaths unless * it's really going to do something useful - pm_runtime_enabled() @@ -5104,6 +5126,11 @@ static int arm_smmu_device_remove(struct platform_device *pdev) arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sCR0, sCR0_CLIENTPD); arm_smmu_power_off(smmu, smmu->pwr); + /* Remove the extra reference that was taken in the probe function */ + if (IS_ENABLED(CONFIG_ARM_SMMU_POWER_ALWAYS_ON) && + of_property_read_bool(pdev->dev.of_node, "qcom,power-always-on")) + arm_smmu_power_off(smmu, smmu->pwr); + arm_smmu_exit_power_resources(smmu->pwr); return 0;