BACKPORT: FROMLIST: KVM: arm64: smmu-v3: Add {alloc/free}_domain

Add SMMUv3 alloc/free domain, as this operations are not
tied to the IOMMU, we can't do much with the io-pgtable
allocation or configuration.

Link: https://lore.kernel.org/all/20241212180423.1578358-33-smostafa@google.com/

Bug: 357781595
Bug: 384432312

Change-Id: I06af7cbf5868e86f4cf8ebcc44d689fa8d36c567
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2024-12-12 18:03:56 +00:00
parent 6835a57068
commit 5d885dc270
2 changed files with 70 additions and 0 deletions
@@ -7,6 +7,8 @@
#include <asm/arm-smmu-v3-common.h>
#include <asm/kvm_hyp.h>
#include <kvm/arm_smmu_v3.h>
#include <linux/io-pgtable-arm.h>
#include <nvhe/alloc.h>
#include <nvhe/iommu.h>
#include <nvhe/mem_protect.h>
#include <nvhe/mm.h>
@@ -50,6 +52,22 @@ struct hyp_arm_smmu_v3_device *kvm_hyp_arm_smmu_v3_smmus;
smmu_wait(_cond); \
})
/*
* SMMUv3 domain:
* @domain: Pointer to the IOMMU domain.
* @smmu: SMMU instance for this domain.
* @type: Type of domain (S1, S2)
* @pgt_lock: Lock for page table
* @pgtable: io_pgtable instance for this domain
*/
struct hyp_arm_smmu_v3_domain {
struct kvm_hyp_iommu_domain *domain;
struct hyp_arm_smmu_v3_device *smmu;
u32 type;
hyp_spinlock_t pgt_lock;
struct io_pgtable *pgtable;
};
static int smmu_write_cr0(struct hyp_arm_smmu_v3_device *smmu, u32 val)
{
writel_relaxed(val, smmu->base + ARM_SMMU_CR0);
@@ -546,7 +564,53 @@ out_reclaim_smmu:
return ret;
}
static struct kvm_hyp_iommu *smmu_id_to_iommu(pkvm_handle_t smmu_id)
{
if (smmu_id >= kvm_hyp_arm_smmu_v3_count)
return NULL;
smmu_id = array_index_nospec(smmu_id, kvm_hyp_arm_smmu_v3_count);
return &kvm_hyp_arm_smmu_v3_smmus[smmu_id].iommu;
}
static int smmu_alloc_domain(struct kvm_hyp_iommu_domain *domain, int type)
{
struct hyp_arm_smmu_v3_domain *smmu_domain;
if (type >= KVM_ARM_SMMU_DOMAIN_MAX)
return -EINVAL;
smmu_domain = hyp_alloc(sizeof(*smmu_domain));
if (!smmu_domain)
return -ENOMEM;
/*
* Can't do much without knowing the SMMUv3.
* Page table will be allocated at attach_dev, but can be
* freed from free domain.
*/
smmu_domain->domain = domain;
smmu_domain->type = type;
hyp_spin_lock_init(&smmu_domain->pgt_lock);
domain->priv = (void *)smmu_domain;
return 0;
}
static void smmu_free_domain(struct kvm_hyp_iommu_domain *domain)
{
struct hyp_arm_smmu_v3_domain *smmu_domain = domain->priv;
if (smmu_domain->pgtable)
kvm_arm_io_pgtable_free(smmu_domain->pgtable);
hyp_free(smmu_domain);
}
/* Shared with the kernel driver in EL1 */
struct kvm_iommu_ops smmu_ops = {
.init = smmu_init,
.get_iommu_by_id = smmu_id_to_iommu,
.alloc_domain = smmu_alloc_domain,
.free_domain = smmu_free_domain,
};
+6
View File
@@ -33,4 +33,10 @@ extern size_t kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_count);
extern struct hyp_arm_smmu_v3_device *kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_smmus);
#define kvm_hyp_arm_smmu_v3_smmus kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_smmus)
enum kvm_arm_smmu_domain_type {
KVM_ARM_SMMU_DOMAIN_S1,
KVM_ARM_SMMU_DOMAIN_S2,
KVM_ARM_SMMU_DOMAIN_MAX,
};
#endif /* __KVM_ARM_SMMU_V3_H */