Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
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
 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 ictx
 82 *  -ENOENT = device is owned but there is no ID
 83 *  -ENODEV or other error = device is not owned
 84 */
 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	else
100		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 the
110 * physical device vdev->dev that was provided to vfio_init_group_dev(). Drivers
111 * 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	else
151		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 the
173 * "mdev path" and will call vfio_pin_pages()/vfio_dma_rw(). Drivers using this
174 * ops set should call vfio_register_emulated_iommu_dev(). Drivers that do
175 * 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	else
228		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);