diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e44721d31d14..f96205352fb2 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -915,6 +915,9 @@ struct kvm_vcpu_arch { /* Per-vcpu CCSIDR override or NULL */ u32 *ccsidr; + /* mem cache for pvIOMMU usage in guests. */ + struct kvm_hyp_memcache iommu_mc; + /* PAGE_SIZE bound list of requests from the hypervisor to the host. */ struct kvm_hyp_req *hyp_reqs; }; @@ -1716,6 +1719,8 @@ struct kvm_iommu_driver { int (*get_device_iommu_num_ids)(struct device *dev); int (*get_device_iommu_id)(struct device *dev, u32 id, pkvm_handle_t *out_iommu, u32 *out_sid); + void *(*guest_alloc)(void *flags, unsigned long order); + void (*guest_free)(void *addr, void *flags, unsigned long order); ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); ANDROID_KABI_RESERVE(3); @@ -1737,6 +1742,9 @@ pkvm_handle_t kvm_get_iommu_id_by_of(struct device_node *np); int pkvm_iommu_suspend(struct device *dev); int pkvm_iommu_resume(struct device *dev); +int kvm_iommu_guest_alloc_mc(struct kvm_hyp_memcache *mc, u32 pgsize, u32 nr_pages); +void kvm_iommu_guest_free_mc(struct kvm_hyp_memcache *mc); + struct kvm_iommu_sg { phys_addr_t phys; size_t pgsize; @@ -1760,4 +1768,13 @@ int kvm_iommu_device_id(struct device *dev, u32 idx, pkvm_handle_t *out_iommu, u32 *out_sid); #define __KVM_HAVE_ARCH_ASSIGNED_DEVICE_GROUP +static inline phys_addr_t kvm_host_pa(void *addr) +{ + return __pa(addr); +} + +static inline void *kvm_host_va(phys_addr_t phys) +{ + return __va(phys); +} #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 33b5e0bc32fa..f65e428c1223 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -388,6 +388,9 @@ static int handle_hyp_req_mem(struct kvm_vcpu *vcpu, atomic64_add(nr_pages << PAGE_SHIFT, &kvm->stat.protected_hyp_mem); return ret; + case REQ_MEM_DEST_HYP_IOMMU: + return kvm_iommu_guest_alloc_mc(&vcpu->arch.iommu_mc, + req->mem.sz_alloc, req->mem.nr_pages); }; pr_warn("Unknown kvm_hyp_req mem dest: %d\n", req->mem.dest); diff --git a/arch/arm64/kvm/iommu.c b/arch/arm64/kvm/iommu.c index 18176d79c229..e018f5057923 100644 --- a/arch/arm64/kvm/iommu.c +++ b/arch/arm64/kvm/iommu.c @@ -142,3 +142,24 @@ int kvm_iommu_device_id(struct device *dev, u32 idx, return -ENODEV; } EXPORT_SYMBOL_GPL(kvm_iommu_device_id); + +int kvm_iommu_guest_alloc_mc(struct kvm_hyp_memcache *mc, u32 pgsize, u32 nr_pages) +{ + u8 order = get_order(pgsize); + + /* Driver might have dedicated allocator especially if it needs large pages. */ + if (iommu_driver && iommu_driver->guest_alloc && iommu_driver->guest_free) + return __topup_hyp_memcache(mc, nr_pages, iommu_driver->guest_alloc, + kvm_host_pa, 0, order); + + return topup_hyp_memcache(mc, nr_pages, order); +} + +void kvm_iommu_guest_free_mc(struct kvm_hyp_memcache *mc) +{ + if (iommu_driver && iommu_driver->guest_alloc && iommu_driver->guest_free) + __free_hyp_memcache(mc, iommu_driver->guest_free, + kvm_host_va, 0); + else + free_hyp_memcache(mc); +} diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 16a2776ecdfe..1c9fe0479bee 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -280,16 +280,6 @@ static int kvm_host_page_count(void *addr) return page_count(virt_to_page(addr)); } -static phys_addr_t kvm_host_pa(void *addr) -{ - return __pa(addr); -} - -static void *kvm_host_va(phys_addr_t phys) -{ - return __va(phys); -} - static void clean_dcache_guest_page(void *va, size_t size) { __clean_dcache_guest_page(va, size); diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index d09d72d2ab4e..ead08452cd36 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -434,6 +434,8 @@ out_free: kvm_unshare_hyp(hyp_reqs, hyp_reqs + 1); host_vcpu->arch.hyp_reqs = NULL; free_page((unsigned long)hyp_reqs); + + kvm_iommu_guest_free_mc(&host_vcpu->arch.iommu_mc); } }