[RFC PATCH v2 45/58] iommu/arm-smmu-v3-kvm: Allocate structures and reset device
Mostafa Saleh
smostafa at google.com
Thu Dec 12 10:04:09 PST 2024
From: Jean-Philippe Brucker <jean-philippe at linaro.org>
Allocate the structures that will be shared between hypervisor and SMMU:
command queue and stream table. Install them in the MMIO registers,
along with some configuration bits. After hyp initialization, the host
won't have access to those pages anymore.
Signed-off-by: Jean-Philippe Brucker <jean-philippe at linaro.org>
Signed-off-by: Mostafa Saleh <smostafa at google.com>
---
.../iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c | 53 +++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c
index 4b0c9ff6e7f1..e4a5bdc830bc 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kvm.c
@@ -18,6 +18,7 @@ extern struct kvm_iommu_ops kvm_nvhe_sym(smmu_ops);
struct host_arm_smmu_device {
struct arm_smmu_device smmu;
pkvm_handle_t id;
+ u32 boot_gbpa;
};
#define smmu_to_host(_smmu) \
@@ -66,6 +67,35 @@ static bool kvm_arm_smmu_validate_features(struct arm_smmu_device *smmu)
return true;
}
+static int kvm_arm_smmu_device_reset(struct host_arm_smmu_device *host_smmu)
+{
+ int ret;
+ u32 reg;
+ struct arm_smmu_device *smmu = &host_smmu->smmu;
+
+ reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
+ if (reg & CR0_SMMUEN)
+ dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
+
+ /* Disable bypass */
+ host_smmu->boot_gbpa = readl_relaxed(smmu->base + ARM_SMMU_GBPA);
+ ret = arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
+ if (ret)
+ return ret;
+
+ ret = arm_smmu_device_disable(smmu);
+ if (ret)
+ return ret;
+
+ /* Stream table */
+ arm_smmu_write_strtab(smmu);
+
+ /* Command queue */
+ writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE);
+
+ return 0;
+}
+
static int kvm_arm_smmu_probe(struct platform_device *pdev)
{
int ret;
@@ -113,6 +143,20 @@ static int kvm_arm_smmu_probe(struct platform_device *pdev)
if (!kvm_arm_smmu_validate_features(smmu))
return -ENODEV;
+ ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, smmu->base,
+ ARM_SMMU_CMDQ_PROD, ARM_SMMU_CMDQ_CONS,
+ CMDQ_ENT_DWORDS, "cmdq");
+ if (ret)
+ return ret;
+
+ ret = arm_smmu_init_strtab(smmu);
+ if (ret)
+ return ret;
+
+ ret = kvm_arm_smmu_device_reset(host_smmu);
+ if (ret)
+ return ret;
+
platform_set_drvdata(pdev, smmu);
/* Hypervisor parameters */
@@ -129,6 +173,15 @@ static int kvm_arm_smmu_probe(struct platform_device *pdev)
static void kvm_arm_smmu_remove(struct platform_device *pdev)
{
+ struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+ struct host_arm_smmu_device *host_smmu = smmu_to_host(smmu);
+
+ /*
+ * There was an error during hypervisor setup. The hyp driver may
+ * have already enabled the device, so disable it.
+ */
+ arm_smmu_device_disable(smmu);
+ arm_smmu_update_gbpa(smmu, host_smmu->boot_gbpa, GBPA_ABORT);
}
static const struct of_device_id arm_smmu_of_match[] = {
--
2.47.0.338.g60cca15819-goog
More information about the linux-arm-kernel
mailing list