1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (C) 2021 Intel Corporation 4 * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES 5 */ 6 #ifndef __LINUX_IOMMUFD_H 7 #define __LINUX_IOMMUFD_H 8 9 #include <linux/err.h> 10 #include <linux/errno.h> 11 #include <linux/refcount.h> 12 #include <linux/types.h> 13 #include <linux/xarray.h> 14 #include <uapi/linux/iommufd.h> 15 16 struct device; 17 struct file; 18 struct iommu_group; 19 struct iommu_user_data; 20 struct iommu_user_data_array; 21 struct iommufd_access; 22 struct iommufd_ctx; 23 struct iommufd_device; 24 struct iommufd_viommu_ops; 25 struct page; 26 27 enum iommufd_object_type { 28 IOMMUFD_OBJ_NONE, 29 IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE, 30 IOMMUFD_OBJ_DEVICE, 31 IOMMUFD_OBJ_HWPT_PAGING, 32 IOMMUFD_OBJ_HWPT_NESTED, 33 IOMMUFD_OBJ_IOAS, 34 IOMMUFD_OBJ_ACCESS, 35 IOMMUFD_OBJ_FAULT, 36 IOMMUFD_OBJ_VIOMMU, 37 IOMMUFD_OBJ_VDEVICE, 38 IOMMUFD_OBJ_VEVENTQ, 39 #ifdef CONFIG_IOMMUFD_TEST 40 IOMMUFD_OBJ_SELFTEST, 41 #endif 42 IOMMUFD_OBJ_MAX, 43 }; 44 45 /* Base struct for all objects with a userspace ID handle. */ 46 struct iommufd_object { 47 refcount_t shortterm_users; 48 refcount_t users; 49 enum iommufd_object_type type; 50 unsigned int id; 51 }; 52 53 struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx, 54 struct device *dev, u32 *id); 55 void iommufd_device_unbind(struct iommufd_device *idev); 56 57 int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id); 58 int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id); 59 void iommufd_device_detach(struct iommufd_device *idev); 60 61 struct iommufd_ctx *iommufd_device_to_ictx(struct iommufd_device *idev); 62 u32 iommufd_device_to_id(struct iommufd_device *idev); 63 64 struct iommufd_access_ops { 65 u8 needs_pin_pages : 1; 66 void (*unmap)(void *data, unsigned long iova, unsigned long length); 67 }; 68 69 enum { 70 IOMMUFD_ACCESS_RW_READ = 0, 71 IOMMUFD_ACCESS_RW_WRITE = 1 << 0, 72 /* Set if the caller is in a kthread then rw will use kthread_use_mm() */ 73 IOMMUFD_ACCESS_RW_KTHREAD = 1 << 1, 74 75 /* Only for use by selftest */ 76 __IOMMUFD_ACCESS_RW_SLOW_PATH = 1 << 2, 77 }; 78 79 struct iommufd_access * 80 iommufd_access_create(struct iommufd_ctx *ictx, 81 const struct iommufd_access_ops *ops, void *data, u32 *id); 82 void iommufd_access_destroy(struct iommufd_access *access); 83 int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id); 84 int iommufd_access_replace(struct iommufd_access *access, u32 ioas_id); 85 void iommufd_access_detach(struct iommufd_access *access); 86 87 void iommufd_ctx_get(struct iommufd_ctx *ictx); 88 89 struct iommufd_viommu { 90 struct iommufd_object obj; 91 struct iommufd_ctx *ictx; 92 struct iommu_device *iommu_dev; 93 struct iommufd_hwpt_paging *hwpt; 94 95 const struct iommufd_viommu_ops *ops; 96 97 struct xarray vdevs; 98 struct list_head veventqs; 99 struct rw_semaphore veventqs_rwsem; 100 101 unsigned int type; 102 }; 103 104 /** 105 * struct iommufd_viommu_ops - vIOMMU specific operations 106 * @destroy: Clean up all driver-specific parts of an iommufd_viommu. The memory 107 * of the vIOMMU will be free-ed by iommufd core after calling this op 108 * @alloc_domain_nested: Allocate a IOMMU_DOMAIN_NESTED on a vIOMMU that holds a 109 * nesting parent domain (IOMMU_DOMAIN_PAGING). @user_data 110 * must be defined in include/uapi/linux/iommufd.h. 111 * It must fully initialize the new iommu_domain before 112 * returning. Upon failure, ERR_PTR must be returned. 113 * @cache_invalidate: Flush hardware cache used by a vIOMMU. It can be used for 114 * any IOMMU hardware specific cache: TLB and device cache. 115 * The @array passes in the cache invalidation requests, in 116 * form of a driver data structure. A driver must update the 117 * array->entry_num to report the number of handled requests. 118 * The data structure of the array entry must be defined in 119 * include/uapi/linux/iommufd.h 120 */ 121 struct iommufd_viommu_ops { 122 void (*destroy)(struct iommufd_viommu *viommu); 123 struct iommu_domain *(*alloc_domain_nested)( 124 struct iommufd_viommu *viommu, u32 flags, 125 const struct iommu_user_data *user_data); 126 int (*cache_invalidate)(struct iommufd_viommu *viommu, 127 struct iommu_user_data_array *array); 128 }; 129 130 #if IS_ENABLED(CONFIG_IOMMUFD) 131 struct iommufd_ctx *iommufd_ctx_from_file(struct file *file); 132 struct iommufd_ctx *iommufd_ctx_from_fd(int fd); 133 void iommufd_ctx_put(struct iommufd_ctx *ictx); 134 bool iommufd_ctx_has_group(struct iommufd_ctx *ictx, struct iommu_group *group); 135 136 int iommufd_access_pin_pages(struct iommufd_access *access, unsigned long iova, 137 unsigned long length, struct page **out_pages, 138 unsigned int flags); 139 void iommufd_access_unpin_pages(struct iommufd_access *access, 140 unsigned long iova, unsigned long length); 141 int iommufd_access_rw(struct iommufd_access *access, unsigned long iova, 142 void *data, size_t len, unsigned int flags); 143 int iommufd_vfio_compat_ioas_get_id(struct iommufd_ctx *ictx, u32 *out_ioas_id); 144 int iommufd_vfio_compat_ioas_create(struct iommufd_ctx *ictx); 145 int iommufd_vfio_compat_set_no_iommu(struct iommufd_ctx *ictx); 146 #else /* !CONFIG_IOMMUFD */ 147 static inline struct iommufd_ctx *iommufd_ctx_from_file(struct file *file) 148 { 149 return ERR_PTR(-EOPNOTSUPP); 150 } 151 152 static inline void iommufd_ctx_put(struct iommufd_ctx *ictx) 153 { 154 } 155 156 static inline int iommufd_access_pin_pages(struct iommufd_access *access, 157 unsigned long iova, 158 unsigned long length, 159 struct page **out_pages, 160 unsigned int flags) 161 { 162 return -EOPNOTSUPP; 163 } 164 165 static inline void iommufd_access_unpin_pages(struct iommufd_access *access, 166 unsigned long iova, 167 unsigned long length) 168 { 169 } 170 171 static inline int iommufd_access_rw(struct iommufd_access *access, unsigned long iova, 172 void *data, size_t len, unsigned int flags) 173 { 174 return -EOPNOTSUPP; 175 } 176 177 static inline int iommufd_vfio_compat_ioas_create(struct iommufd_ctx *ictx) 178 { 179 return -EOPNOTSUPP; 180 } 181 182 static inline int iommufd_vfio_compat_set_no_iommu(struct iommufd_ctx *ictx) 183 { 184 return -EOPNOTSUPP; 185 } 186 #endif /* CONFIG_IOMMUFD */ 187 188 #if IS_ENABLED(CONFIG_IOMMUFD_DRIVER_CORE) 189 struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, 190 size_t size, 191 enum iommufd_object_type type); 192 struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu, 193 unsigned long vdev_id); 194 int iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, 195 struct device *dev, unsigned long *vdev_id); 196 int iommufd_viommu_report_event(struct iommufd_viommu *viommu, 197 enum iommu_veventq_type type, void *event_data, 198 size_t data_len); 199 #else /* !CONFIG_IOMMUFD_DRIVER_CORE */ 200 static inline struct iommufd_object * 201 _iommufd_object_alloc(struct iommufd_ctx *ictx, size_t size, 202 enum iommufd_object_type type) 203 { 204 return ERR_PTR(-EOPNOTSUPP); 205 } 206 207 static inline struct device * 208 iommufd_viommu_find_dev(struct iommufd_viommu *viommu, unsigned long vdev_id) 209 { 210 return NULL; 211 } 212 213 static inline int iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, 214 struct device *dev, 215 unsigned long *vdev_id) 216 { 217 return -ENOENT; 218 } 219 220 static inline int iommufd_viommu_report_event(struct iommufd_viommu *viommu, 221 enum iommu_veventq_type type, 222 void *event_data, size_t data_len) 223 { 224 return -EOPNOTSUPP; 225 } 226 #endif /* CONFIG_IOMMUFD_DRIVER_CORE */ 227 228 /* 229 * Helpers for IOMMU driver to allocate driver structures that will be freed by 230 * the iommufd core. The free op will be called prior to freeing the memory. 231 */ 232 #define iommufd_viommu_alloc(ictx, drv_struct, member, viommu_ops) \ 233 ({ \ 234 drv_struct *ret; \ 235 \ 236 static_assert(__same_type(struct iommufd_viommu, \ 237 ((drv_struct *)NULL)->member)); \ 238 static_assert(offsetof(drv_struct, member.obj) == 0); \ 239 ret = (drv_struct *)_iommufd_object_alloc( \ 240 ictx, sizeof(drv_struct), IOMMUFD_OBJ_VIOMMU); \ 241 if (!IS_ERR(ret)) \ 242 ret->member.ops = viommu_ops; \ 243 ret; \ 244 }) 245 #endif 246