| /* SPDX-License-Identifier: GPL-2.0-only */ |
| #ifndef __ARM64_KVM_NVHE_IOMMU_H__ |
| #define __ARM64_KVM_NVHE_IOMMU_H__ |
| |
| #include <linux/types.h> |
| #include <asm/kvm_host.h> |
| |
| #include <nvhe/mem_protect.h> |
| |
| struct pkvm_iommu; |
| |
| struct pkvm_iommu_ops { |
| /* |
| * Global driver initialization called before devices are registered. |
| * Driver-specific arguments are passed in a buffer shared by the host. |
| * The buffer memory has been pinned in EL2 but host retains R/W access. |
| * Extra care must be taken when reading from it to avoid TOCTOU bugs. |
| * If the driver maintains its own page tables, it is expected to |
| * initialize them to all memory owned by the host. |
| * Driver initialization lock held during callback. |
| */ |
| int (*init)(void *data, size_t size); |
| |
| /* |
| * Driver-specific validation of a device that is being registered. |
| * All fields of the device struct have been populated. |
| * Called with the host lock held. |
| */ |
| int (*validate)(struct pkvm_iommu *dev); |
| |
| /* |
| * Validation of a new child device that is being register by |
| * the parent device the child selected. Called with the host lock held. |
| */ |
| int (*validate_child)(struct pkvm_iommu *dev, struct pkvm_iommu *child); |
| |
| /* |
| * Callback to apply a host stage-2 mapping change at driver level. |
| * Called before 'host_stage2_idmap_apply' with host lock held. |
| */ |
| void (*host_stage2_idmap_prepare)(phys_addr_t start, phys_addr_t end, |
| enum kvm_pgtable_prot prot); |
| |
| /* |
| * Callback to apply a host stage-2 mapping change at device level. |
| * Called after 'host_stage2_idmap_prepare' with host lock held. |
| */ |
| void (*host_stage2_idmap_apply)(struct pkvm_iommu *dev, |
| phys_addr_t start, phys_addr_t end); |
| |
| /* |
| * Callback to finish a host stage-2 mapping change at device level. |
| * Called after 'host_stage2_idmap_apply' with host lock held. |
| */ |
| void (*host_stage2_idmap_complete)(struct pkvm_iommu *dev); |
| |
| /* Power management callbacks. Called with host lock held. */ |
| int (*suspend)(struct pkvm_iommu *dev); |
| int (*resume)(struct pkvm_iommu *dev); |
| |
| /* |
| * Host data abort handler callback. Called with host lock held. |
| * Returns true if the data abort has been handled. |
| */ |
| bool (*host_dabt_handler)(struct pkvm_iommu *dev, |
| struct kvm_cpu_context *host_ctxt, |
| u32 esr, size_t off); |
| |
| /* Amount of memory allocated per-device for use by the driver. */ |
| size_t data_size; |
| }; |
| |
| struct pkvm_iommu { |
| struct pkvm_iommu *parent; |
| struct list_head list; |
| struct list_head siblings; |
| struct list_head children; |
| unsigned long id; |
| const struct pkvm_iommu_ops *ops; |
| phys_addr_t pa; |
| void *va; |
| size_t size; |
| bool powered; |
| char data[]; |
| }; |
| |
| int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t size); |
| int __pkvm_iommu_register(unsigned long dev_id, |
| enum pkvm_iommu_driver_id drv_id, |
| phys_addr_t dev_pa, size_t dev_size, |
| unsigned long parent_id, |
| void *kern_mem_va, size_t mem_size); |
| int __pkvm_iommu_pm_notify(unsigned long dev_id, |
| enum pkvm_iommu_pm_event event); |
| int __pkvm_iommu_finalize(void); |
| int pkvm_iommu_host_stage2_adjust_range(phys_addr_t addr, phys_addr_t *start, |
| phys_addr_t *end); |
| bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, |
| phys_addr_t fault_pa); |
| void pkvm_iommu_host_stage2_idmap(phys_addr_t start, phys_addr_t end, |
| enum kvm_pgtable_prot prot); |
| |
| extern const struct pkvm_iommu_ops pkvm_s2mpu_ops; |
| extern const struct pkvm_iommu_ops pkvm_sysmmu_sync_ops; |
| |
| #endif /* __ARM64_KVM_NVHE_IOMMU_H__ */ |