248 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES4 */5#include <linux/vfio.h>6#include <linux/iommufd.h>7 8#include "vfio.h"9 10MODULE_IMPORT_NS(IOMMUFD);11MODULE_IMPORT_NS(IOMMUFD_VFIO);12 13bool vfio_iommufd_device_has_compat_ioas(struct vfio_device *vdev,14 struct iommufd_ctx *ictx)15{16 u32 ioas_id;17 18 return !iommufd_vfio_compat_ioas_get_id(ictx, &ioas_id);19}20 21int vfio_df_iommufd_bind(struct vfio_device_file *df)22{23 struct vfio_device *vdev = df->device;24 struct iommufd_ctx *ictx = df->iommufd;25 26 lockdep_assert_held(&vdev->dev_set->lock);27 28 return vdev->ops->bind_iommufd(vdev, ictx, &df->devid);29}30 31int vfio_iommufd_compat_attach_ioas(struct vfio_device *vdev,32 struct iommufd_ctx *ictx)33{34 u32 ioas_id;35 int ret;36 37 lockdep_assert_held(&vdev->dev_set->lock);38 39 /* compat noiommu does not need to do ioas attach */40 if (vfio_device_is_noiommu(vdev))41 return 0;42 43 ret = iommufd_vfio_compat_ioas_get_id(ictx, &ioas_id);44 if (ret)45 return ret;46 47 /* The legacy path has no way to return the selected pt_id */48 return vdev->ops->attach_ioas(vdev, &ioas_id);49}50 51void vfio_df_iommufd_unbind(struct vfio_device_file *df)52{53 struct vfio_device *vdev = df->device;54 55 lockdep_assert_held(&vdev->dev_set->lock);56 57 if (vfio_device_is_noiommu(vdev))58 return;59 60 if (vdev->ops->unbind_iommufd)61 vdev->ops->unbind_iommufd(vdev);62}63 64struct iommufd_ctx *vfio_iommufd_device_ictx(struct vfio_device *vdev)65{66 if (vdev->iommufd_device)67 return iommufd_device_to_ictx(vdev->iommufd_device);68 return NULL;69}70EXPORT_SYMBOL_GPL(vfio_iommufd_device_ictx);71 72static int vfio_iommufd_device_id(struct vfio_device *vdev)73{74 if (vdev->iommufd_device)75 return iommufd_device_to_id(vdev->iommufd_device);76 return -EINVAL;77}78 79/*80 * Return devid for a device.81 * valid ID for the device that is owned by the ictx82 * -ENOENT = device is owned but there is no ID83 * -ENODEV or other error = device is not owned84 */85int vfio_iommufd_get_dev_id(struct vfio_device *vdev, struct iommufd_ctx *ictx)86{87 struct iommu_group *group;88 int devid;89 90 if (vfio_iommufd_device_ictx(vdev) == ictx)91 return vfio_iommufd_device_id(vdev);92 93 group = iommu_group_get(vdev->dev);94 if (!group)95 return -ENODEV;96 97 if (iommufd_ctx_has_group(ictx, group))98 devid = -ENOENT;99 else100 devid = -ENODEV;101 102 iommu_group_put(group);103 104 return devid;105}106EXPORT_SYMBOL_GPL(vfio_iommufd_get_dev_id);107 108/*109 * The physical standard ops mean that the iommufd_device is bound to the110 * physical device vdev->dev that was provided to vfio_init_group_dev(). Drivers111 * using this ops set should call vfio_register_group_dev()112 */113int vfio_iommufd_physical_bind(struct vfio_device *vdev,114 struct iommufd_ctx *ictx, u32 *out_device_id)115{116 struct iommufd_device *idev;117 118 idev = iommufd_device_bind(ictx, vdev->dev, out_device_id);119 if (IS_ERR(idev))120 return PTR_ERR(idev);121 vdev->iommufd_device = idev;122 return 0;123}124EXPORT_SYMBOL_GPL(vfio_iommufd_physical_bind);125 126void vfio_iommufd_physical_unbind(struct vfio_device *vdev)127{128 lockdep_assert_held(&vdev->dev_set->lock);129 130 if (vdev->iommufd_attached) {131 iommufd_device_detach(vdev->iommufd_device);132 vdev->iommufd_attached = false;133 }134 iommufd_device_unbind(vdev->iommufd_device);135 vdev->iommufd_device = NULL;136}137EXPORT_SYMBOL_GPL(vfio_iommufd_physical_unbind);138 139int vfio_iommufd_physical_attach_ioas(struct vfio_device *vdev, u32 *pt_id)140{141 int rc;142 143 lockdep_assert_held(&vdev->dev_set->lock);144 145 if (WARN_ON(!vdev->iommufd_device))146 return -EINVAL;147 148 if (vdev->iommufd_attached)149 rc = iommufd_device_replace(vdev->iommufd_device, pt_id);150 else151 rc = iommufd_device_attach(vdev->iommufd_device, pt_id);152 if (rc)153 return rc;154 vdev->iommufd_attached = true;155 return 0;156}157EXPORT_SYMBOL_GPL(vfio_iommufd_physical_attach_ioas);158 159void vfio_iommufd_physical_detach_ioas(struct vfio_device *vdev)160{161 lockdep_assert_held(&vdev->dev_set->lock);162 163 if (WARN_ON(!vdev->iommufd_device) || !vdev->iommufd_attached)164 return;165 166 iommufd_device_detach(vdev->iommufd_device);167 vdev->iommufd_attached = false;168}169EXPORT_SYMBOL_GPL(vfio_iommufd_physical_detach_ioas);170 171/*172 * The emulated standard ops mean that vfio_device is going to use the173 * "mdev path" and will call vfio_pin_pages()/vfio_dma_rw(). Drivers using this174 * ops set should call vfio_register_emulated_iommu_dev(). Drivers that do175 * not call vfio_pin_pages()/vfio_dma_rw() have no need to provide dma_unmap.176 */177 178static void vfio_emulated_unmap(void *data, unsigned long iova,179 unsigned long length)180{181 struct vfio_device *vdev = data;182 183 if (vdev->ops->dma_unmap)184 vdev->ops->dma_unmap(vdev, iova, length);185}186 187static const struct iommufd_access_ops vfio_user_ops = {188 .needs_pin_pages = 1,189 .unmap = vfio_emulated_unmap,190};191 192int vfio_iommufd_emulated_bind(struct vfio_device *vdev,193 struct iommufd_ctx *ictx, u32 *out_device_id)194{195 struct iommufd_access *user;196 197 lockdep_assert_held(&vdev->dev_set->lock);198 199 user = iommufd_access_create(ictx, &vfio_user_ops, vdev, out_device_id);200 if (IS_ERR(user))201 return PTR_ERR(user);202 vdev->iommufd_access = user;203 return 0;204}205EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_bind);206 207void vfio_iommufd_emulated_unbind(struct vfio_device *vdev)208{209 lockdep_assert_held(&vdev->dev_set->lock);210 211 if (vdev->iommufd_access) {212 iommufd_access_destroy(vdev->iommufd_access);213 vdev->iommufd_attached = false;214 vdev->iommufd_access = NULL;215 }216}217EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_unbind);218 219int vfio_iommufd_emulated_attach_ioas(struct vfio_device *vdev, u32 *pt_id)220{221 int rc;222 223 lockdep_assert_held(&vdev->dev_set->lock);224 225 if (vdev->iommufd_attached)226 rc = iommufd_access_replace(vdev->iommufd_access, *pt_id);227 else228 rc = iommufd_access_attach(vdev->iommufd_access, *pt_id);229 if (rc)230 return rc;231 vdev->iommufd_attached = true;232 return 0;233}234EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_attach_ioas);235 236void vfio_iommufd_emulated_detach_ioas(struct vfio_device *vdev)237{238 lockdep_assert_held(&vdev->dev_set->lock);239 240 if (WARN_ON(!vdev->iommufd_access) ||241 !vdev->iommufd_attached)242 return;243 244 iommufd_access_detach(vdev->iommufd_access);245 vdev->iommufd_attached = false;246}247EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_detach_ioas);248