brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 82eba69 Raw
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