1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2022 - Google LLC
4 * Author: David Brazdil <dbrazdil@google.com>
5 */
6
7 #include <linux/kvm_host.h>
8
9 /* Did all IOMMUs register as expected. */
10 static bool finalised;
11
dev_to_id(struct device * dev)12 static unsigned long dev_to_id(struct device *dev)
13 {
14 /* Use the struct device pointer as a unique identifier. */
15 return (unsigned long)dev;
16 }
17
pkvm_iommu_driver_init(u64 drv,void * data,size_t size)18 int pkvm_iommu_driver_init(u64 drv, void *data, size_t size)
19 {
20 return kvm_call_hyp_nvhe(__pkvm_iommu_driver_init, drv, data, size);
21 }
22 EXPORT_SYMBOL(pkvm_iommu_driver_init);
23
pkvm_iommu_register(struct device * dev,u64 drv,phys_addr_t pa,size_t size,struct device * parent,u8 flags)24 int pkvm_iommu_register(struct device *dev, u64 drv, phys_addr_t pa,
25 size_t size, struct device *parent, u8 flags)
26 {
27 void *mem;
28 int ret;
29
30 /*
31 * Hypcall to register the device. It will return -ENOMEM if it needs
32 * more memory. In that case allocate a page and retry.
33 * We assume that hyp never allocates more than a page per hypcall.
34 */
35 ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev),
36 drv, pa, size, dev_to_id(parent), flags, NULL);
37 if (ret == -ENOMEM) {
38 mem = (void *)__get_free_page(GFP_KERNEL);
39 if (!mem)
40 return -ENOMEM;
41
42 ret = kvm_call_hyp_nvhe(__pkvm_iommu_register, dev_to_id(dev),
43 drv, pa, size, dev_to_id(parent), flags, mem);
44 }
45 return ret;
46 }
47 EXPORT_SYMBOL(pkvm_iommu_register);
48
pkvm_iommu_suspend(struct device * dev)49 int pkvm_iommu_suspend(struct device *dev)
50 {
51 return kvm_call_hyp_nvhe(__pkvm_iommu_pm_notify, dev_to_id(dev),
52 PKVM_IOMMU_PM_SUSPEND);
53 }
54 EXPORT_SYMBOL(pkvm_iommu_suspend);
55
pkvm_iommu_resume(struct device * dev)56 int pkvm_iommu_resume(struct device *dev)
57 {
58 return kvm_call_hyp_nvhe(__pkvm_iommu_pm_notify, dev_to_id(dev),
59 PKVM_IOMMU_PM_RESUME);
60 }
61 EXPORT_SYMBOL(pkvm_iommu_resume);
62
pkvm_iommu_finalize(int err)63 int pkvm_iommu_finalize(int err)
64 {
65 finalised = !err;
66 return kvm_call_hyp_nvhe(__pkvm_iommu_finalize, 0);
67 }
68 EXPORT_SYMBOL_GPL(pkvm_iommu_finalize);
69
pkvm_iommu_finalized(void)70 bool pkvm_iommu_finalized(void)
71 {
72 return finalised;
73 }
74