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:
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user