From 970a9ef174184a61ce94fe4c461f05887ed2edf3 Mon Sep 17 00:00:00 2001 From: Mostafa Saleh Date: Wed, 12 Apr 2023 16:36:42 +0000 Subject: [PATCH] ANDROID: KVM: arm64: iommu: Pass device specific flags to hypervisor We need to pass some device specific flags that are detected from EL1 (as built-in sync device) to the hypervisor. The flags are defined by the driver but hosted in the main iommu struct. As we use SMCCC1.1 we only have 7 args, which were already used, so mem_size is removed as it really not needed as all page donations are 1 page. so passing the base address is enough. Bug: 255266847 Change-Id: I14e6d2573d7a822334455999aa9fd6f01ac97450 Signed-off-by: Mostafa Saleh --- arch/arm64/include/asm/kvm_host.h | 4 ++-- arch/arm64/kvm/hyp/include/nvhe/iommu.h | 5 +++-- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 +++---- arch/arm64/kvm/hyp/nvhe/iommu.c | 14 +++++++------- arch/arm64/kvm/iommu.c | 7 +++---- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 29668379d6a3..adaa8889ad9d 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -397,8 +397,8 @@ struct pkvm_iommu_driver { }; int pkvm_iommu_driver_init(u64 drv, void *data, size_t size); -int pkvm_iommu_register(struct device *dev, u64 drv, - phys_addr_t pa, size_t size, struct device *parent); +int pkvm_iommu_register(struct device *dev, u64 drv, phys_addr_t pa, + size_t size, struct device *parent, u8 flags); int pkvm_iommu_suspend(struct device *dev); int pkvm_iommu_resume(struct device *dev); diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h index ffa7dcfc7952..ad05bf0bf764 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h +++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h @@ -81,14 +81,15 @@ struct pkvm_iommu { void *va; size_t size; bool powered; + u8 flags; char data[]; }; int __pkvm_iommu_driver_init(struct pkvm_iommu_driver *drv, void *data, size_t size); int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, phys_addr_t dev_pa, size_t dev_size, - unsigned long parent_id, - void *kern_mem_va, size_t mem_size); + unsigned long parent_id, u8 flags, + void *kern_mem_va); int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event); int __pkvm_iommu_finalize(int err); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index 8e291ac1a053..285d5458b624 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -1152,12 +1152,11 @@ static void handle___pkvm_iommu_register(struct kvm_cpu_context *host_ctxt) DECLARE_REG(phys_addr_t, dev_pa, host_ctxt, 3); DECLARE_REG(size_t, dev_size, host_ctxt, 4); DECLARE_REG(unsigned long, parent_id, host_ctxt, 5); - DECLARE_REG(void *, mem, host_ctxt, 6); - DECLARE_REG(size_t, mem_size, host_ctxt, 7); + DECLARE_REG(u8, flags, host_ctxt, 6); + DECLARE_REG(void *, mem, host_ctxt, 7); cpu_reg(host_ctxt, 1) = __pkvm_iommu_register(dev_id, drv_id, dev_pa, - dev_size, parent_id, - mem, mem_size); + dev_size, parent_id, flags, mem); } static void handle___pkvm_iommu_pm_notify(struct kvm_cpu_context *host_ctxt) diff --git a/arch/arm64/kvm/hyp/nvhe/iommu.c b/arch/arm64/kvm/hyp/nvhe/iommu.c index 6c90b32491f0..bd7f177408e6 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu.c @@ -329,8 +329,8 @@ out_unlock: int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, phys_addr_t dev_pa, size_t dev_size, - unsigned long parent_id, - void *kern_mem_va, size_t mem_size) + unsigned long parent_id, u8 flags, + void *kern_mem_va) { struct pkvm_iommu *dev = NULL; struct pkvm_iommu_driver *drv; @@ -364,16 +364,15 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, * Accept memory donation if the host is providing new memory. * Note: We do not return the memory even if there is an error later. */ - if (kern_mem_va && mem_size) { + if (kern_mem_va) { mem_va = kern_hyp_va(kern_mem_va); - if (!PAGE_ALIGNED(mem_va) || !PAGE_ALIGNED(mem_size)) { + if (!PAGE_ALIGNED(mem_va)) { ret = -EINVAL; goto out_unlock; } - ret = __pkvm_host_donate_hyp(hyp_virt_to_pfn(mem_va), - mem_size >> PAGE_SHIFT); + ret = __pkvm_host_donate_hyp(hyp_virt_to_pfn(mem_va), 1); if (ret) goto out_unlock; } @@ -381,7 +380,7 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, host_lock_component(); /* Allocate memory for the new device entry. */ - dev = alloc_iommu(drv, mem_va, mem_size); + dev = alloc_iommu(drv, mem_va, PAGE_SIZE); if (!dev) { ret = -ENOMEM; goto out_free; @@ -394,6 +393,7 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, .ops = drv->ops, .pa = dev_pa, .size = dev_size, + .flags = flags, }; if (!validate_against_existing_iommus(dev)) { diff --git a/arch/arm64/kvm/iommu.c b/arch/arm64/kvm/iommu.c index 5fe0b3080fc3..4a03f1908307 100644 --- a/arch/arm64/kvm/iommu.c +++ b/arch/arm64/kvm/iommu.c @@ -19,7 +19,7 @@ int pkvm_iommu_driver_init(u64 drv, void *data, size_t size) EXPORT_SYMBOL_GPL(pkvm_iommu_driver_init); int pkvm_iommu_register(struct device *dev, u64 drv, phys_addr_t pa, - size_t size, struct device *parent) + size_t size, struct device *parent, u8 flags) { void *mem; int ret; @@ -30,15 +30,14 @@ int pkvm_iommu_register(struct device *dev, u64 drv, phys_addr_t pa, * We assume that hyp never allocates more than a page per hypcall. */ ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev), - drv, pa, size, dev_to_id(parent), NULL, 0); + drv, pa, size, dev_to_id(parent), flags, NULL); if (ret == -ENOMEM) { mem = (void *)__get_free_page(GFP_KERNEL); if (!mem) return -ENOMEM; ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev), - drv, pa, size, dev_to_id(parent), - mem, PAGE_SIZE); + drv, pa, size, dev_to_id(parent), flags, mem); } return ret; }