Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
  4 */
  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
 13int vfio_iommufd_bind(struct vfio_device *vdev, struct iommufd_ctx *ictx)
 14{
 15	u32 ioas_id;
 16	u32 device_id;
 17	int ret;
 18
 19	lockdep_assert_held(&vdev->dev_set->lock);
 20
 21	/*
 22	 * If the driver doesn't provide this op then it means the device does
 23	 * not do DMA at all. So nothing to do.
 24	 */
 25	if (!vdev->ops->bind_iommufd)
 26		return 0;
 27
 28	ret = vdev->ops->bind_iommufd(vdev, ictx, &device_id);
 29	if (ret)
 30		return ret;
 31
 32	ret = iommufd_vfio_compat_ioas_id(ictx, &ioas_id);
 33	if (ret)
 34		goto err_unbind;
 35	ret = vdev->ops->attach_ioas(vdev, &ioas_id);
 36	if (ret)
 37		goto err_unbind;
 38
 39	/*
 40	 * The legacy path has no way to return the device id or the selected
 41	 * pt_id
 42	 */
 43	return 0;
 44
 45err_unbind:
 46	if (vdev->ops->unbind_iommufd)
 47		vdev->ops->unbind_iommufd(vdev);
 48	return ret;
 49}
 50
 51void vfio_iommufd_unbind(struct vfio_device *vdev)
 52{
 53	lockdep_assert_held(&vdev->dev_set->lock);
 54
 55	if (vdev->ops->unbind_iommufd)
 56		vdev->ops->unbind_iommufd(vdev);
 57}
 58
 59/*
 60 * The physical standard ops mean that the iommufd_device is bound to the
 61 * physical device vdev->dev that was provided to vfio_init_group_dev(). Drivers
 62 * using this ops set should call vfio_register_group_dev()
 63 */
 64int vfio_iommufd_physical_bind(struct vfio_device *vdev,
 65			       struct iommufd_ctx *ictx, u32 *out_device_id)
 66{
 67	struct iommufd_device *idev;
 68
 69	idev = iommufd_device_bind(ictx, vdev->dev, out_device_id);
 70	if (IS_ERR(idev))
 71		return PTR_ERR(idev);
 72	vdev->iommufd_device = idev;
 73	return 0;
 74}
 75EXPORT_SYMBOL_GPL(vfio_iommufd_physical_bind);
 76
 77void vfio_iommufd_physical_unbind(struct vfio_device *vdev)
 78{
 79	lockdep_assert_held(&vdev->dev_set->lock);
 80
 81	if (vdev->iommufd_attached) {
 82		iommufd_device_detach(vdev->iommufd_device);
 83		vdev->iommufd_attached = false;
 84	}
 85	iommufd_device_unbind(vdev->iommufd_device);
 86	vdev->iommufd_device = NULL;
 87}
 88EXPORT_SYMBOL_GPL(vfio_iommufd_physical_unbind);
 89
 90int vfio_iommufd_physical_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
 91{
 92	int rc;
 93
 94	rc = iommufd_device_attach(vdev->iommufd_device, pt_id);
 95	if (rc)
 96		return rc;
 97	vdev->iommufd_attached = true;
 98	return 0;
 99}
100EXPORT_SYMBOL_GPL(vfio_iommufd_physical_attach_ioas);
101
102/*
103 * The emulated standard ops mean that vfio_device is going to use the
104 * "mdev path" and will call vfio_pin_pages()/vfio_dma_rw(). Drivers using this
105 * ops set should call vfio_register_emulated_iommu_dev().
106 */
107
108static void vfio_emulated_unmap(void *data, unsigned long iova,
109				unsigned long length)
110{
111	struct vfio_device *vdev = data;
112
113	vdev->ops->dma_unmap(vdev, iova, length);
114}
115
116static const struct iommufd_access_ops vfio_user_ops = {
117	.needs_pin_pages = 1,
118	.unmap = vfio_emulated_unmap,
119};
120
121int vfio_iommufd_emulated_bind(struct vfio_device *vdev,
122			       struct iommufd_ctx *ictx, u32 *out_device_id)
123{
124	lockdep_assert_held(&vdev->dev_set->lock);
125
126	vdev->iommufd_ictx = ictx;
127	iommufd_ctx_get(ictx);
128	return 0;
129}
130EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_bind);
131
132void vfio_iommufd_emulated_unbind(struct vfio_device *vdev)
133{
134	lockdep_assert_held(&vdev->dev_set->lock);
135
136	if (vdev->iommufd_access) {
137		iommufd_access_destroy(vdev->iommufd_access);
138		vdev->iommufd_access = NULL;
139	}
140	iommufd_ctx_put(vdev->iommufd_ictx);
141	vdev->iommufd_ictx = NULL;
142}
143EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_unbind);
144
145int vfio_iommufd_emulated_attach_ioas(struct vfio_device *vdev, u32 *pt_id)
146{
147	struct iommufd_access *user;
148
149	lockdep_assert_held(&vdev->dev_set->lock);
150
151	user = iommufd_access_create(vdev->iommufd_ictx, *pt_id, &vfio_user_ops,
152				     vdev);
153	if (IS_ERR(user))
154		return PTR_ERR(user);
155	vdev->iommufd_access = user;
156	return 0;
157}
158EXPORT_SYMBOL_GPL(vfio_iommufd_emulated_attach_ioas);