root/drivers/vfio/vfio.h
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
 *     Author: Alex Williamson <alex.williamson@redhat.com>
 */
#ifndef __VFIO_VFIO_H__
#define __VFIO_VFIO_H__

#include <linux/file.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/vfio.h>

struct iommufd_ctx;
struct iommu_group;
struct vfio_container;

struct vfio_device_file {
        struct vfio_device *device;
        struct vfio_group *group;

        u8 access_granted;
        u32 devid; /* only valid when iommufd is valid */
        spinlock_t kvm_ref_lock; /* protect kvm field */
        struct kvm *kvm;
        struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */
};

void vfio_device_put_registration(struct vfio_device *device);
bool vfio_device_try_get_registration(struct vfio_device *device);
int vfio_df_open(struct vfio_device_file *df);
void vfio_df_close(struct vfio_device_file *df);
struct vfio_device_file *
vfio_allocate_device_file(struct vfio_device *device);

extern const struct file_operations vfio_device_fops;

#ifdef CONFIG_VFIO_NOIOMMU
extern bool vfio_noiommu __read_mostly;
#else
enum { vfio_noiommu = false };
#endif

enum vfio_group_type {
        /*
         * Physical device with IOMMU backing.
         */
        VFIO_IOMMU,

        /*
         * Virtual device without IOMMU backing. The VFIO core fakes up an
         * iommu_group as the iommu_group sysfs interface is part of the
         * userspace ABI.  The user of these devices must not be able to
         * directly trigger unmediated DMA.
         */
        VFIO_EMULATED_IOMMU,

        /*
         * Physical device without IOMMU backing. The VFIO core fakes up an
         * iommu_group as the iommu_group sysfs interface is part of the
         * userspace ABI.  Users can trigger unmediated DMA by the device,
         * usage is highly dangerous, requires an explicit opt-in and will
         * taint the kernel.
         */
        VFIO_NO_IOMMU,
};

#if IS_ENABLED(CONFIG_VFIO_GROUP)
struct vfio_group {
        struct device                   dev;
        struct cdev                     cdev;
        /*
         * When drivers is non-zero a driver is attached to the struct device
         * that provided the iommu_group and thus the iommu_group is a valid
         * pointer. When drivers is 0 the driver is being detached. Once users
         * reaches 0 then the iommu_group is invalid.
         */
        refcount_t                      drivers;
        unsigned int                    container_users;
        struct iommu_group              *iommu_group;
        struct vfio_container           *container;
        struct list_head                device_list;
        struct mutex                    device_lock;
        struct list_head                vfio_next;
#if IS_ENABLED(CONFIG_VFIO_CONTAINER)
        struct list_head                container_next;
#endif
        enum vfio_group_type            type;
        struct mutex                    group_lock;
        struct kvm                      *kvm;
        struct file                     *opened_file;
        struct blocking_notifier_head   notifier;
        struct iommufd_ctx              *iommufd;
        spinlock_t                      kvm_ref_lock;
        unsigned int                    cdev_device_open_cnt;
};

int vfio_device_block_group(struct vfio_device *device);
void vfio_device_unblock_group(struct vfio_device *device);
int vfio_device_set_group(struct vfio_device *device,
                          enum vfio_group_type type);
void vfio_device_remove_group(struct vfio_device *device);
void vfio_device_group_register(struct vfio_device *device);
void vfio_device_group_unregister(struct vfio_device *device);
int vfio_device_group_use_iommu(struct vfio_device *device);
void vfio_device_group_unuse_iommu(struct vfio_device *device);
void vfio_df_group_close(struct vfio_device_file *df);
struct vfio_group *vfio_group_from_file(struct file *file);
bool vfio_group_enforced_coherent(struct vfio_group *group);
void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm);
bool vfio_device_has_container(struct vfio_device *device);
int __init vfio_group_init(void);
void vfio_group_cleanup(void);

static inline bool vfio_device_is_noiommu(struct vfio_device *vdev)
{
        return IS_ENABLED(CONFIG_VFIO_NOIOMMU) &&
               vdev->group->type == VFIO_NO_IOMMU;
}
#else
struct vfio_group;

static inline int vfio_device_block_group(struct vfio_device *device)
{
        return 0;
}

static inline void vfio_device_unblock_group(struct vfio_device *device)
{
}

static inline int vfio_device_set_group(struct vfio_device *device,
                                        enum vfio_group_type type)
{
        return 0;
}

static inline void vfio_device_remove_group(struct vfio_device *device)
{
}

static inline void vfio_device_group_register(struct vfio_device *device)
{
}

static inline void vfio_device_group_unregister(struct vfio_device *device)
{
}

static inline int vfio_device_group_use_iommu(struct vfio_device *device)
{
        return -EOPNOTSUPP;
}

static inline void vfio_device_group_unuse_iommu(struct vfio_device *device)
{
}

static inline void vfio_df_group_close(struct vfio_device_file *df)
{
}

static inline struct vfio_group *vfio_group_from_file(struct file *file)
{
        return NULL;
}

static inline bool vfio_group_enforced_coherent(struct vfio_group *group)
{
        return true;
}

static inline void vfio_group_set_kvm(struct vfio_group *group, struct kvm *kvm)
{
}

static inline bool vfio_device_has_container(struct vfio_device *device)
{
        return false;
}

static inline int __init vfio_group_init(void)
{
        return 0;
}

static inline void vfio_group_cleanup(void)
{
}

static inline bool vfio_device_is_noiommu(struct vfio_device *vdev)
{
        return false;
}
#endif /* CONFIG_VFIO_GROUP */

#if IS_ENABLED(CONFIG_VFIO_CONTAINER)
/**
 * struct vfio_iommu_driver_ops - VFIO IOMMU driver callbacks
 */
struct vfio_iommu_driver_ops {
        char            *name;
        struct module   *owner;
        void            *(*open)(unsigned long arg);
        void            (*release)(void *iommu_data);
        long            (*ioctl)(void *iommu_data, unsigned int cmd,
                                 unsigned long arg);
        int             (*attach_group)(void *iommu_data,
                                        struct iommu_group *group,
                                        enum vfio_group_type);
        void            (*detach_group)(void *iommu_data,
                                        struct iommu_group *group);
        int             (*pin_pages)(void *iommu_data,
                                     struct iommu_group *group,
                                     dma_addr_t user_iova,
                                     int npage, int prot,
                                     struct page **pages);
        void            (*unpin_pages)(void *iommu_data,
                                       dma_addr_t user_iova, int npage);
        void            (*register_device)(void *iommu_data,
                                           struct vfio_device *vdev);
        void            (*unregister_device)(void *iommu_data,
                                             struct vfio_device *vdev);
        int             (*dma_rw)(void *iommu_data, dma_addr_t user_iova,
                                  void *data, size_t count, bool write);
        struct iommu_domain *(*group_iommu_domain)(void *iommu_data,
                                                   struct iommu_group *group);
};

struct vfio_iommu_driver {
        const struct vfio_iommu_driver_ops      *ops;
        struct list_head                        vfio_next;
};

int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops);
void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops);

struct vfio_container *vfio_container_from_file(struct file *filep);
int vfio_group_use_container(struct vfio_group *group);
void vfio_group_unuse_container(struct vfio_group *group);
int vfio_container_attach_group(struct vfio_container *container,
                                struct vfio_group *group);
void vfio_group_detach_container(struct vfio_group *group);
void vfio_device_container_register(struct vfio_device *device);
void vfio_device_container_unregister(struct vfio_device *device);
int vfio_device_container_pin_pages(struct vfio_device *device,
                                    dma_addr_t iova, int npage,
                                    int prot, struct page **pages);
void vfio_device_container_unpin_pages(struct vfio_device *device,
                                       dma_addr_t iova, int npage);
int vfio_device_container_dma_rw(struct vfio_device *device,
                                 dma_addr_t iova, void *data,
                                 size_t len, bool write);

int __init vfio_container_init(void);
void vfio_container_cleanup(void);
#else
static inline struct vfio_container *
vfio_container_from_file(struct file *filep)
{
        return NULL;
}

static inline int vfio_group_use_container(struct vfio_group *group)
{
        return -EOPNOTSUPP;
}

static inline void vfio_group_unuse_container(struct vfio_group *group)
{
}

static inline int vfio_container_attach_group(struct vfio_container *container,
                                              struct vfio_group *group)
{
        return -EOPNOTSUPP;
}

static inline void vfio_group_detach_container(struct vfio_group *group)
{
}

static inline void vfio_device_container_register(struct vfio_device *device)
{
}

static inline void vfio_device_container_unregister(struct vfio_device *device)
{
}

static inline int vfio_device_container_pin_pages(struct vfio_device *device,
                                                  dma_addr_t iova, int npage,
                                                  int prot, struct page **pages)
{
        return -EOPNOTSUPP;
}

static inline void vfio_device_container_unpin_pages(struct vfio_device *device,
                                                     dma_addr_t iova, int npage)
{
}

static inline int vfio_device_container_dma_rw(struct vfio_device *device,
                                               dma_addr_t iova, void *data,
                                               size_t len, bool write)
{
        return -EOPNOTSUPP;
}

static inline int vfio_container_init(void)
{
        return 0;
}
static inline void vfio_container_cleanup(void)
{
}
#endif

#if IS_ENABLED(CONFIG_IOMMUFD)
bool vfio_iommufd_device_has_compat_ioas(struct vfio_device *vdev,
                                         struct iommufd_ctx *ictx);
int vfio_df_iommufd_bind(struct vfio_device_file *df);
void vfio_df_iommufd_unbind(struct vfio_device_file *df);
int vfio_iommufd_compat_attach_ioas(struct vfio_device *device,
                                    struct iommufd_ctx *ictx);
#else
static inline bool
vfio_iommufd_device_has_compat_ioas(struct vfio_device *vdev,
                                    struct iommufd_ctx *ictx)
{
        return false;
}

static inline int vfio_df_iommufd_bind(struct vfio_device_file *fd)
{
        return -EOPNOTSUPP;
}

static inline void vfio_df_iommufd_unbind(struct vfio_device_file *df)
{
}

static inline int
vfio_iommufd_compat_attach_ioas(struct vfio_device *device,
                                struct iommufd_ctx *ictx)
{
        return -EOPNOTSUPP;
}
#endif

int vfio_df_ioctl_attach_pt(struct vfio_device_file *df,
                            struct vfio_device_attach_iommufd_pt __user *arg);
int vfio_df_ioctl_detach_pt(struct vfio_device_file *df,
                            struct vfio_device_detach_iommufd_pt __user *arg);

#if IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV)
void vfio_init_device_cdev(struct vfio_device *device);

static inline int vfio_device_add(struct vfio_device *device)
{
        /* cdev does not support noiommu device */
        if (vfio_device_is_noiommu(device))
                return device_add(&device->device);
        vfio_init_device_cdev(device);
        return cdev_device_add(&device->cdev, &device->device);
}

static inline void vfio_device_del(struct vfio_device *device)
{
        if (vfio_device_is_noiommu(device))
                device_del(&device->device);
        else
                cdev_device_del(&device->cdev, &device->device);
}

int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep);
long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df,
                                struct vfio_device_bind_iommufd __user *arg);
void vfio_df_unbind_iommufd(struct vfio_device_file *df);
int vfio_cdev_init(struct class *device_class);
void vfio_cdev_cleanup(void);
#else
static inline void vfio_init_device_cdev(struct vfio_device *device)
{
}

static inline int vfio_device_add(struct vfio_device *device)
{
        return device_add(&device->device);
}

static inline void vfio_device_del(struct vfio_device *device)
{
        device_del(&device->device);
}

static inline int vfio_device_fops_cdev_open(struct inode *inode,
                                             struct file *filep)
{
        return 0;
}

static inline long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df,
                                              struct vfio_device_bind_iommufd __user *arg)
{
        return -ENOTTY;
}

static inline void vfio_df_unbind_iommufd(struct vfio_device_file *df)
{
}

static inline int vfio_cdev_init(struct class *device_class)
{
        return 0;
}

static inline void vfio_cdev_cleanup(void)
{
}
#endif /* CONFIG_VFIO_DEVICE_CDEV */

#if IS_ENABLED(CONFIG_VFIO_VIRQFD)
int __init vfio_virqfd_init(void);
void vfio_virqfd_exit(void);
#else
static inline int __init vfio_virqfd_init(void)
{
        return 0;
}
static inline void vfio_virqfd_exit(void)
{
}
#endif

#if IS_ENABLED(CONFIG_KVM)
void vfio_device_get_kvm_safe(struct vfio_device *device, struct kvm *kvm);
void vfio_device_put_kvm(struct vfio_device *device);
#else
static inline void vfio_device_get_kvm_safe(struct vfio_device *device,
                                            struct kvm *kvm)
{
}

static inline void vfio_device_put_kvm(struct vfio_device *device)
{
}
#endif

#ifdef CONFIG_VFIO_DEBUGFS
void vfio_debugfs_create_root(void);
void vfio_debugfs_remove_root(void);

void vfio_device_debugfs_init(struct vfio_device *vdev);
void vfio_device_debugfs_exit(struct vfio_device *vdev);
#else
static inline void vfio_debugfs_create_root(void) { }
static inline void vfio_debugfs_remove_root(void) { }

static inline void vfio_device_debugfs_init(struct vfio_device *vdev) { }
static inline void vfio_device_debugfs_exit(struct vfio_device *vdev) { }
#endif /* CONFIG_VFIO_DEBUGFS */

#endif