107 lines
3.4 KiB
C
107 lines
3.4 KiB
C
/* 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__ */
|