12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2022 - Google LLC
- * Author: David Brazdil <[email protected]>
- */
- #include <linux/kvm_host.h>
- /* Did all IOMMUs register as expected. */
- static bool finalised;
- static unsigned long dev_to_id(struct device *dev)
- {
- /* Use the struct device pointer as a unique identifier. */
- return (unsigned long)dev;
- }
- int pkvm_iommu_driver_init(u64 drv, void *data, size_t size)
- {
- return kvm_call_hyp_nvhe(__pkvm_iommu_driver_init, drv, data, size);
- }
- EXPORT_SYMBOL(pkvm_iommu_driver_init);
- int pkvm_iommu_register(struct device *dev, u64 drv, phys_addr_t pa,
- size_t size, struct device *parent, u8 flags)
- {
- void *mem;
- int ret;
- /*
- * Hypcall to register the device. It will return -ENOMEM if it needs
- * more memory. In that case allocate a page and retry.
- * 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), 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), flags, mem);
- }
- return ret;
- }
- EXPORT_SYMBOL(pkvm_iommu_register);
- int pkvm_iommu_suspend(struct device *dev)
- {
- return kvm_call_hyp_nvhe(__pkvm_iommu_pm_notify, dev_to_id(dev),
- PKVM_IOMMU_PM_SUSPEND);
- }
- EXPORT_SYMBOL(pkvm_iommu_suspend);
- int pkvm_iommu_resume(struct device *dev)
- {
- return kvm_call_hyp_nvhe(__pkvm_iommu_pm_notify, dev_to_id(dev),
- PKVM_IOMMU_PM_RESUME);
- }
- EXPORT_SYMBOL(pkvm_iommu_resume);
- int pkvm_iommu_finalize(int err)
- {
- finalised = !err;
- return kvm_call_hyp_nvhe(__pkvm_iommu_finalize, 0);
- }
- EXPORT_SYMBOL_GPL(pkvm_iommu_finalize);
- bool pkvm_iommu_finalized(void)
- {
- return finalised;
- }
|