@@ -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[] = {