Skip to content

Commit 9aa667a

Browse files
quic-guptapbibekpatro
authored andcommitted
FROMLIST: iommu/arm-smmu: Use pm_runtime in fault handlers
Commit d4a44f0 ("iommu/arm-smmu: Invoke pm_runtime across the driver") enabled pm_runtime for the arm-smmu device. On systems where the SMMU sits in a power domain, all register accesses must be done while the device is runtime active to avoid unclocked register reads and potential NoC errors. So far, this has not been an issue for most SMMU clients because stall-on-fault is enabled by default. While a translation fault is being handled, the SMMU stalls further translations for that context bank, so the fault handler would not race with a powered-down SMMU. Adreno SMMU now disables stall-on-fault in the presence of fault storms to avoid saturating SMMU resources and hanging the GMU. With stall-on-fault disabled, the SMMU can generate faults while its power domain may no longer be enabled, which makes unclocked accesses to fault-status registers in the SMMU fault handlers possible. Guard the context and global fault handlers with pm_runtime_get_if_active() and pm_runtime_put_autosuspend() so that all SMMU fault register accesses are done with the SMMU powered. In case pm_runtime is not active we can safely ignore the fault as for pm runtime resume the smmu device is reset and fault registers are cleared. Fixes: b130440 ("drm/msm: Temporarily disable stall-on-fault after a page fault") Co-developed-by: Pratyush Brahma <pratyush.brahma@oss.qualcomm.com> Signed-off-by: Pratyush Brahma <pratyush.brahma@oss.qualcomm.com> Signed-off-by: Prakash Gupta <prakash.gupta@oss.qualcomm.com> Link: https://lore.kernel.org/all/20260313-smmu-rpm-v2-1-8c2236b402b0@oss.qualcomm.com/
1 parent 883da00 commit 9aa667a

1 file changed

Lines changed: 39 additions & 21 deletions

File tree

drivers/iommu/arm/arm-smmu/arm-smmu.c

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,20 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
462462
int idx = smmu_domain->cfg.cbndx;
463463
int ret;
464464

465+
if (!pm_runtime_get_if_active(smmu->dev))
466+
return IRQ_NONE;
467+
468+
if (smmu->impl && smmu->impl->context_fault) {
469+
ret = smmu->impl->context_fault(irq, dev);
470+
goto out_power_off;
471+
}
472+
465473
arm_smmu_read_context_fault_info(smmu, idx, &cfi);
466474

467-
if (!(cfi.fsr & ARM_SMMU_CB_FSR_FAULT))
468-
return IRQ_NONE;
475+
if (!(cfi.fsr & ARM_SMMU_CB_FSR_FAULT)) {
476+
ret = IRQ_NONE;
477+
goto out_power_off;
478+
}
469479

470480
ret = report_iommu_fault(&smmu_domain->domain, NULL, cfi.iova,
471481
cfi.fsynr & ARM_SMMU_CB_FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ);
@@ -480,7 +490,12 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
480490
ret == -EAGAIN ? 0 : ARM_SMMU_RESUME_TERMINATE);
481491
}
482492

483-
return IRQ_HANDLED;
493+
ret = IRQ_HANDLED;
494+
495+
out_power_off:
496+
pm_runtime_put_autosuspend(smmu->dev);
497+
498+
return ret;
484499
}
485500

486501
static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
@@ -489,14 +504,25 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
489504
struct arm_smmu_device *smmu = dev;
490505
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
491506
DEFAULT_RATELIMIT_BURST);
507+
int ret;
508+
509+
if (!pm_runtime_get_if_active(smmu->dev))
510+
return IRQ_NONE;
511+
512+
if (smmu->impl && smmu->impl->global_fault) {
513+
ret = smmu->impl->global_fault(irq, dev);
514+
goto out_power_off;
515+
}
492516

493517
gfsr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR);
494518
gfsynr0 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR0);
495519
gfsynr1 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR1);
496520
gfsynr2 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR2);
497521

498-
if (!gfsr)
499-
return IRQ_NONE;
522+
if (!gfsr) {
523+
ret = IRQ_NONE;
524+
goto out_power_off;
525+
}
500526

501527
if (__ratelimit(&rs)) {
502528
if (IS_ENABLED(CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT) &&
@@ -513,7 +539,11 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
513539
}
514540

515541
arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, gfsr);
516-
return IRQ_HANDLED;
542+
ret = IRQ_HANDLED;
543+
544+
out_power_off:
545+
pm_runtime_put_autosuspend(smmu->dev);
546+
return ret;
517547
}
518548

519549
static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
@@ -683,7 +713,6 @@ static int arm_smmu_init_domain_context(struct arm_smmu_domain *smmu_domain,
683713
enum io_pgtable_fmt fmt;
684714
struct iommu_domain *domain = &smmu_domain->domain;
685715
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
686-
irqreturn_t (*context_fault)(int irq, void *dev);
687716

688717
mutex_lock(&smmu_domain->init_mutex);
689718
if (smmu_domain->smmu)
@@ -850,19 +879,14 @@ static int arm_smmu_init_domain_context(struct arm_smmu_domain *smmu_domain,
850879
*/
851880
irq = smmu->irqs[cfg->irptndx];
852881

853-
if (smmu->impl && smmu->impl->context_fault)
854-
context_fault = smmu->impl->context_fault;
855-
else
856-
context_fault = arm_smmu_context_fault;
857-
858882
if (smmu->impl && smmu->impl->context_fault_needs_threaded_irq)
859883
ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
860-
context_fault,
884+
arm_smmu_context_fault,
861885
IRQF_ONESHOT | IRQF_SHARED,
862886
"arm-smmu-context-fault",
863887
smmu_domain);
864888
else
865-
ret = devm_request_irq(smmu->dev, irq, context_fault, IRQF_SHARED,
889+
ret = devm_request_irq(smmu->dev, irq, arm_smmu_context_fault, IRQF_SHARED,
866890
"arm-smmu-context-fault", smmu_domain);
867891

868892
if (ret < 0) {
@@ -2122,7 +2146,6 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
21222146
struct device *dev = &pdev->dev;
21232147
int num_irqs, i, err;
21242148
u32 global_irqs, pmu_irqs;
2125-
irqreturn_t (*global_fault)(int irq, void *dev);
21262149

21272150
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
21282151
if (!smmu) {
@@ -2202,18 +2225,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
22022225
smmu->num_context_irqs = smmu->num_context_banks;
22032226
}
22042227

2205-
if (smmu->impl && smmu->impl->global_fault)
2206-
global_fault = smmu->impl->global_fault;
2207-
else
2208-
global_fault = arm_smmu_global_fault;
2209-
22102228
for (i = 0; i < global_irqs; i++) {
22112229
int irq = platform_get_irq(pdev, i);
22122230

22132231
if (irq < 0)
22142232
return irq;
22152233

2216-
err = devm_request_irq(dev, irq, global_fault, IRQF_SHARED,
2234+
err = devm_request_irq(dev, irq, arm_smmu_global_fault, IRQF_SHARED,
22172235
"arm-smmu global fault", smmu);
22182236
if (err)
22192237
return dev_err_probe(dev, err,

0 commit comments

Comments
 (0)