Skip to content

Commit 4db97c2

Browse files
nicolincjgunthorpe
authored andcommitted
iommufd/viommu: Add IOMMU_VIOMMU_ALLOC ioctl
Add a new ioctl for user space to do a vIOMMU allocation. It must be based on a nesting parent HWPT, so take its refcount. IOMMU driver wanting to support vIOMMUs must define its IOMMU_VIOMMU_TYPE_ in the uAPI header and implement a viommu_alloc op in its iommu_ops. Link: https://patch.msgid.link/r/dc2b8ba9ac935007beff07c1761c31cd097ed780.1730836219.git.nicolinc@nvidia.com Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent d56d1e8 commit 4db97c2

File tree

5 files changed

+132
-1
lines changed

5 files changed

+132
-1
lines changed

drivers/iommu/iommufd/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ iommufd-y := \
77
ioas.o \
88
main.o \
99
pages.o \
10-
vfio_compat.o
10+
vfio_compat.o \
11+
viommu.o
1112

1213
iommufd-$(CONFIG_IOMMUFD_TEST) += selftest.o
1314

drivers/iommu/iommufd/iommufd_private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ static inline int iommufd_hwpt_replace_device(struct iommufd_device *idev,
506506
return iommu_group_replace_domain(idev->igroup->group, hwpt->domain);
507507
}
508508

509+
int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd);
510+
void iommufd_viommu_destroy(struct iommufd_object *obj);
511+
509512
#ifdef CONFIG_IOMMUFD_TEST
510513
int iommufd_test(struct iommufd_ucmd *ucmd);
511514
void iommufd_selftest_destroy(struct iommufd_object *obj);

drivers/iommu/iommufd/main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ union ucmd_buffer {
307307
struct iommu_ioas_unmap unmap;
308308
struct iommu_option option;
309309
struct iommu_vfio_ioas vfio_ioas;
310+
struct iommu_viommu_alloc viommu;
310311
#ifdef CONFIG_IOMMUFD_TEST
311312
struct iommu_test_cmd test;
312313
#endif
@@ -360,6 +361,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
360361
val64),
361362
IOCTL_OP(IOMMU_VFIO_IOAS, iommufd_vfio_ioas, struct iommu_vfio_ioas,
362363
__reserved),
364+
IOCTL_OP(IOMMU_VIOMMU_ALLOC, iommufd_viommu_alloc_ioctl,
365+
struct iommu_viommu_alloc, out_viommu_id),
363366
#ifdef CONFIG_IOMMUFD_TEST
364367
IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last),
365368
#endif
@@ -495,6 +498,9 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
495498
[IOMMUFD_OBJ_FAULT] = {
496499
.destroy = iommufd_fault_destroy,
497500
},
501+
[IOMMUFD_OBJ_VIOMMU] = {
502+
.destroy = iommufd_viommu_destroy,
503+
},
498504
#ifdef CONFIG_IOMMUFD_TEST
499505
[IOMMUFD_OBJ_SELFTEST] = {
500506
.destroy = iommufd_selftest_destroy,

drivers/iommu/iommufd/viommu.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES
3+
*/
4+
#include "iommufd_private.h"
5+
6+
void iommufd_viommu_destroy(struct iommufd_object *obj)
7+
{
8+
struct iommufd_viommu *viommu =
9+
container_of(obj, struct iommufd_viommu, obj);
10+
11+
if (viommu->ops && viommu->ops->destroy)
12+
viommu->ops->destroy(viommu);
13+
refcount_dec(&viommu->hwpt->common.obj.users);
14+
}
15+
16+
int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd)
17+
{
18+
struct iommu_viommu_alloc *cmd = ucmd->cmd;
19+
struct iommufd_hwpt_paging *hwpt_paging;
20+
struct iommufd_viommu *viommu;
21+
struct iommufd_device *idev;
22+
const struct iommu_ops *ops;
23+
int rc;
24+
25+
if (cmd->flags || cmd->type == IOMMU_VIOMMU_TYPE_DEFAULT)
26+
return -EOPNOTSUPP;
27+
28+
idev = iommufd_get_device(ucmd, cmd->dev_id);
29+
if (IS_ERR(idev))
30+
return PTR_ERR(idev);
31+
32+
ops = dev_iommu_ops(idev->dev);
33+
if (!ops->viommu_alloc) {
34+
rc = -EOPNOTSUPP;
35+
goto out_put_idev;
36+
}
37+
38+
hwpt_paging = iommufd_get_hwpt_paging(ucmd, cmd->hwpt_id);
39+
if (IS_ERR(hwpt_paging)) {
40+
rc = PTR_ERR(hwpt_paging);
41+
goto out_put_idev;
42+
}
43+
44+
if (!hwpt_paging->nest_parent) {
45+
rc = -EINVAL;
46+
goto out_put_hwpt;
47+
}
48+
49+
viommu = ops->viommu_alloc(idev->dev, hwpt_paging->common.domain,
50+
ucmd->ictx, cmd->type);
51+
if (IS_ERR(viommu)) {
52+
rc = PTR_ERR(viommu);
53+
goto out_put_hwpt;
54+
}
55+
56+
viommu->type = cmd->type;
57+
viommu->ictx = ucmd->ictx;
58+
viommu->hwpt = hwpt_paging;
59+
refcount_inc(&viommu->hwpt->common.obj.users);
60+
/*
61+
* It is the most likely case that a physical IOMMU is unpluggable. A
62+
* pluggable IOMMU instance (if exists) is responsible for refcounting
63+
* on its own.
64+
*/
65+
viommu->iommu_dev = __iommu_get_iommu_dev(idev->dev);
66+
67+
cmd->out_viommu_id = viommu->obj.id;
68+
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
69+
if (rc)
70+
goto out_abort;
71+
iommufd_object_finalize(ucmd->ictx, &viommu->obj);
72+
goto out_put_hwpt;
73+
74+
out_abort:
75+
iommufd_object_abort_and_destroy(ucmd->ictx, &viommu->obj);
76+
out_put_hwpt:
77+
iommufd_put_object(ucmd->ictx, &hwpt_paging->common.obj);
78+
out_put_idev:
79+
iommufd_put_object(ucmd->ictx, &idev->obj);
80+
return rc;
81+
}

include/uapi/linux/iommufd.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum {
5252
IOMMUFD_CMD_HWPT_INVALIDATE = 0x8d,
5353
IOMMUFD_CMD_FAULT_QUEUE_ALLOC = 0x8e,
5454
IOMMUFD_CMD_IOAS_MAP_FILE = 0x8f,
55+
IOMMUFD_CMD_VIOMMU_ALLOC = 0x90,
5556
};
5657

5758
/**
@@ -822,4 +823,43 @@ struct iommu_fault_alloc {
822823
__u32 out_fault_fd;
823824
};
824825
#define IOMMU_FAULT_QUEUE_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_FAULT_QUEUE_ALLOC)
826+
827+
/**
828+
* enum iommu_viommu_type - Virtual IOMMU Type
829+
* @IOMMU_VIOMMU_TYPE_DEFAULT: Reserved for future use
830+
*/
831+
enum iommu_viommu_type {
832+
IOMMU_VIOMMU_TYPE_DEFAULT = 0,
833+
};
834+
835+
/**
836+
* struct iommu_viommu_alloc - ioctl(IOMMU_VIOMMU_ALLOC)
837+
* @size: sizeof(struct iommu_viommu_alloc)
838+
* @flags: Must be 0
839+
* @type: Type of the virtual IOMMU. Must be defined in enum iommu_viommu_type
840+
* @dev_id: The device's physical IOMMU will be used to back the virtual IOMMU
841+
* @hwpt_id: ID of a nesting parent HWPT to associate to
842+
* @out_viommu_id: Output virtual IOMMU ID for the allocated object
843+
*
844+
* Allocate a virtual IOMMU object, representing the underlying physical IOMMU's
845+
* virtualization support that is a security-isolated slice of the real IOMMU HW
846+
* that is unique to a specific VM. Operations global to the IOMMU are connected
847+
* to the vIOMMU, such as:
848+
* - Security namespace for guest owned ID, e.g. guest-controlled cache tags
849+
* - Non-device-affiliated event reporting, e.g. invalidation queue errors
850+
* - Access to a sharable nesting parent pagetable across physical IOMMUs
851+
* - Virtualization of various platforms IDs, e.g. RIDs and others
852+
* - Delivery of paravirtualized invalidation
853+
* - Direct assigned invalidation queues
854+
* - Direct assigned interrupts
855+
*/
856+
struct iommu_viommu_alloc {
857+
__u32 size;
858+
__u32 flags;
859+
__u32 type;
860+
__u32 dev_id;
861+
__u32 hwpt_id;
862+
__u32 out_viommu_id;
863+
};
864+
#define IOMMU_VIOMMU_ALLOC _IO(IOMMUFD_TYPE, IOMMUFD_CMD_VIOMMU_ALLOC)
825865
#endif

0 commit comments

Comments
 (0)