[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250616025628.25454-8-xueqi.zhang@mediatek.com>
Date: Mon, 16 Jun 2025 10:56:13 +0800
From: Xueqi Zhang <xueqi.zhang@...iatek.com>
To: Yong Wu <yong.wu@...iatek.com>, Will Deacon <will@...nel.org>, Robin
Murphy <robin.murphy@....com>, Joerg Roedel <joro@...tes.org>, Rob Herring
<robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley
<conor+dt@...nel.org>, Matthias Brugger <matthias.bgg@...il.com>,
AngeloGioacchino Del Regno <angelogioacchino.delregno@...labora.com>
CC: <Project_Global_Chrome_Upstream_Group@...iatek.com>, Ning li
<ning.li@...iatek.com>, <linux-mediatek@...ts.infradead.org>,
<linux-kernel@...r.kernel.org>, <linux-arm-kernel@...ts.infradead.org>,
<devicetree@...r.kernel.org>, <iommu@...ts.linux.dev>, Xueqi Zhang
<xueqi.zhang@...iatek.com>
Subject: [RFC PATCH 7/8] iommu/arm-smmu-v3: Invoke rpm operation before accessing the hw
Invoke rpm operation before accessing the SMMU hw.
Signed-off-by: Xueqi Zhang <xueqi.zhang@...iatek.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 84 ++++++++++++++++++++-
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 3 +
2 files changed, 85 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 154417b380fa..88912b0f8132 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -122,6 +122,22 @@ static void parse_driver_options(struct arm_smmu_device *smmu)
} while (arm_smmu_options[++i].opt);
}
+static int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
+{
+ if (smmu && smmu->impl && smmu->impl->smmu_power_get)
+ return smmu->impl->smmu_power_get(smmu);
+
+ return 0;
+}
+
+static int arm_smmu_rpm_put(struct arm_smmu_device *smmu)
+{
+ if (smmu && smmu->impl && smmu->impl->smmu_power_put)
+ return smmu->impl->smmu_power_put(smmu);
+
+ return 0;
+}
+
/* Low-level queue manipulation functions */
static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
{
@@ -2082,23 +2098,35 @@ static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
{
struct arm_smmu_device *smmu = dev;
+ int ret;
+
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret)
+ return IRQ_NONE;
arm_smmu_evtq_thread(irq, dev);
if (smmu->features & ARM_SMMU_FEAT_PRI)
arm_smmu_priq_thread(irq, dev);
+ arm_smmu_rpm_put(smmu);
return IRQ_HANDLED;
}
static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
{
struct arm_smmu_device *smmu = dev;
+ int ret;
+
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret)
+ return IRQ_WAKE_THREAD;
arm_smmu_gerror_handler(irq, dev);
if (smmu->impl && smmu->impl->combined_irq_handle)
smmu->impl->combined_irq_handle(irq, smmu);
+ arm_smmu_rpm_put(smmu);
return IRQ_WAKE_THREAD;
}
@@ -2255,6 +2283,11 @@ static void arm_smmu_tlb_inv_context(void *cookie)
struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_cmdq_ent cmd;
+ int ret;
+
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret)
+ return;
/*
* NOTE: when io-pgtable is in non-strict mode, we may get here with
@@ -2271,6 +2304,8 @@ static void arm_smmu_tlb_inv_context(void *cookie)
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
}
arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
+
+ arm_smmu_rpm_put(smmu);
}
static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
@@ -2353,6 +2388,11 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
.leaf = leaf,
},
};
+ int ret;
+
+ ret = arm_smmu_rpm_get(smmu_domain->smmu);
+ if (ret)
+ return;
if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
cmd.opcode = smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
@@ -2378,6 +2418,8 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
* zapped an entire table.
*/
arm_smmu_atc_inv_domain(smmu_domain, iova, size);
+
+ arm_smmu_rpm_put(smmu_domain->smmu);
}
void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
@@ -2392,8 +2434,15 @@ void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
.leaf = leaf,
},
};
+ int ret;
+
+ ret = arm_smmu_rpm_get(smmu_domain->smmu);
+ if (ret)
+ return;
__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
+
+ arm_smmu_rpm_put(smmu_domain->smmu);
}
static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
@@ -3038,6 +3087,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
} else if (arm_smmu_ssids_in_use(&master->cd_table))
return -EBUSY;
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret) {
+ dev_info(smmu->dev, "[%s] power_status:%d\n", __func__, ret);
+ return -EBUSY;
+ }
+
/*
* Prevent arm_smmu_share_asid() from trying to change the ASID
* of either the old or new domain while we are working on it.
@@ -3049,6 +3104,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
ret = arm_smmu_attach_prepare(&state, domain);
if (ret) {
mutex_unlock(&arm_smmu_asid_lock);
+ arm_smmu_rpm_put(smmu);
return ret;
}
@@ -3074,6 +3130,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
arm_smmu_attach_commit(&state);
mutex_unlock(&arm_smmu_asid_lock);
+ arm_smmu_rpm_put(smmu);
return 0;
}
@@ -3216,7 +3273,13 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
.old_domain = iommu_get_domain_for_dev(dev),
.ssid = IOMMU_NO_PASID,
};
+ int ret;
+ ret = arm_smmu_rpm_get(master->smmu);
+ if (ret) {
+ dev_info(master->smmu->dev, "[%s] power_status:%d\n", __func__, ret);
+ return;
+ }
/*
* Do not allow any ASID to be changed while are working on the STE,
* otherwise we could miss invalidations.
@@ -3244,7 +3307,7 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
arm_smmu_install_ste_for_dev(master, ste);
arm_smmu_attach_commit(&state);
mutex_unlock(&arm_smmu_asid_lock);
-
+ arm_smmu_rpm_put(master->smmu);
/*
* This has to be done after removing the master from the
* arm_smmu_domain->devices to avoid races updating the same context
@@ -4799,10 +4862,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (irq > 0)
smmu->gerr_irq = irq;
}
+
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret) {
+ dev_info(smmu->dev, "[%s] power_status fail:%d\n", __func__, ret);
+ return ret;
+ }
+
/* Probe the h/w */
ret = arm_smmu_device_hw_probe(smmu);
if (ret)
- return ret;
+ goto err_pm_put;
/* Initialise in-memory data structures */
ret = arm_smmu_init_structures(smmu);
@@ -4840,6 +4910,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
arm_smmu_device_disable(smmu);
err_free_iopf:
iopf_queue_free(smmu->evtq.iopf);
+err_pm_put:
+ arm_smmu_rpm_put(smmu);
return ret;
}
@@ -4857,8 +4929,16 @@ static void arm_smmu_device_remove(struct platform_device *pdev)
static void arm_smmu_device_shutdown(struct platform_device *pdev)
{
struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+ int ret;
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret) {
+ dev_info(smmu->dev, "[%s] power_status:%d\n", __func__, ret);
+ return;
+ }
arm_smmu_device_disable(smmu);
+
+ arm_smmu_rpm_put(smmu);
}
static const struct of_device_id arm_smmu_of_match[] = {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index f45c4bf84bc1..cd96ff9cbc54 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -792,6 +792,7 @@ struct arm_smmu_device {
struct rb_root streams;
struct mutex streams_mutex;
+
const struct arm_smmu_v3_impl *impl;
};
@@ -1004,6 +1005,8 @@ struct arm_smmu_v3_impl {
int (*combined_irq_handle)(int irq, struct arm_smmu_device *smmu_dev);
int (*smmu_evt_handler)(int irq, struct arm_smmu_device *smmu_dev,
u64 *evt, struct ratelimit_state *rs);
+ int (*smmu_power_get)(struct arm_smmu_device *smmu);
+ int (*smmu_power_put)(struct arm_smmu_device *smmu);
};
struct arm_smmu_device *arm_smmu_v3_impl_init(struct arm_smmu_device *smmu);
--
2.46.0
Powered by blists - more mailing lists