Skip to content

Commit 65fe32f

Browse files
nicolincjgunthorpe
authored andcommitted
iommufd/selftest: Add nested domain allocation for mock domain
Add nested domain support in the ->domain_alloc_user op with some proper sanity checks. Then, add a domain_nested_ops for all nested domains and split the get_md_pagetable helper into paging and nested helpers. Also, add an iotlb as a testing property of a nested domain. Link: https://lore.kernel.org/r/20231026043938.63898-10-yi.l.liu@intel.com Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Yi Liu <yi.l.liu@intel.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
1 parent e9d36c0 commit 65fe32f

File tree

2 files changed

+140
-30
lines changed

2 files changed

+140
-30
lines changed

drivers/iommu/iommufd/iommufd_test.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ enum {
4646
MOCK_FLAGS_DEVICE_NO_DIRTY = 1 << 0,
4747
};
4848

49+
enum {
50+
MOCK_NESTED_DOMAIN_IOTLB_ID_MAX = 3,
51+
MOCK_NESTED_DOMAIN_IOTLB_NUM = 4,
52+
};
53+
4954
struct iommu_test_cmd {
5055
__u32 size;
5156
__u32 op;
@@ -130,4 +135,17 @@ struct iommu_test_hw_info {
130135
__u32 test_reg;
131136
};
132137

138+
/* Should not be equal to any defined value in enum iommu_hwpt_data_type */
139+
#define IOMMU_HWPT_DATA_SELFTEST 0xdead
140+
#define IOMMU_TEST_IOTLB_DEFAULT 0xbadbeef
141+
142+
/**
143+
* struct iommu_hwpt_selftest
144+
*
145+
* @iotlb: default mock iotlb value, IOMMU_TEST_IOTLB_DEFAULT
146+
*/
147+
struct iommu_hwpt_selftest {
148+
__u32 iotlb;
149+
};
150+
133151
#endif

drivers/iommu/iommufd/selftest.c

Lines changed: 122 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ struct mock_iommu_domain {
9393
struct xarray pfns;
9494
};
9595

96+
struct mock_iommu_domain_nested {
97+
struct iommu_domain domain;
98+
struct mock_iommu_domain *parent;
99+
u32 iotlb[MOCK_NESTED_DOMAIN_IOTLB_NUM];
100+
};
101+
96102
enum selftest_obj_type {
97103
TYPE_IDEV,
98104
};
@@ -217,54 +223,99 @@ const struct iommu_dirty_ops dirty_ops = {
217223
};
218224

219225
static const struct iommu_ops mock_ops;
226+
static struct iommu_domain_ops domain_nested_ops;
220227

221-
static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
228+
static struct iommu_domain *
229+
__mock_domain_alloc_paging(unsigned int iommu_domain_type, bool needs_dirty_ops)
222230
{
223231
struct mock_iommu_domain *mock;
224232

225-
if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED)
226-
return &mock_blocking_domain;
227-
228-
if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED)
229-
return NULL;
230-
231233
mock = kzalloc(sizeof(*mock), GFP_KERNEL);
232234
if (!mock)
233-
return NULL;
235+
return ERR_PTR(-ENOMEM);
234236
mock->domain.geometry.aperture_start = MOCK_APERTURE_START;
235237
mock->domain.geometry.aperture_end = MOCK_APERTURE_LAST;
236238
mock->domain.pgsize_bitmap = MOCK_IO_PAGE_SIZE;
237239
mock->domain.ops = mock_ops.default_domain_ops;
240+
if (needs_dirty_ops)
241+
mock->domain.dirty_ops = &dirty_ops;
238242
mock->domain.type = iommu_domain_type;
239243
xa_init(&mock->pfns);
240244
return &mock->domain;
241245
}
242246

247+
static struct iommu_domain *
248+
__mock_domain_alloc_nested(struct mock_iommu_domain *mock_parent,
249+
const struct iommu_hwpt_selftest *user_cfg)
250+
{
251+
struct mock_iommu_domain_nested *mock_nested;
252+
int i;
253+
254+
mock_nested = kzalloc(sizeof(*mock_nested), GFP_KERNEL);
255+
if (!mock_nested)
256+
return ERR_PTR(-ENOMEM);
257+
mock_nested->parent = mock_parent;
258+
mock_nested->domain.ops = &domain_nested_ops;
259+
mock_nested->domain.type = IOMMU_DOMAIN_NESTED;
260+
for (i = 0; i < MOCK_NESTED_DOMAIN_IOTLB_NUM; i++)
261+
mock_nested->iotlb[i] = user_cfg->iotlb;
262+
return &mock_nested->domain;
263+
}
264+
265+
static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
266+
{
267+
struct iommu_domain *domain;
268+
269+
if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED)
270+
return &mock_blocking_domain;
271+
if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED)
272+
return NULL;
273+
domain = __mock_domain_alloc_paging(iommu_domain_type, false);
274+
if (IS_ERR(domain))
275+
domain = NULL;
276+
return domain;
277+
}
278+
243279
static struct iommu_domain *
244280
mock_domain_alloc_user(struct device *dev, u32 flags,
245281
struct iommu_domain *parent,
246282
const struct iommu_user_data *user_data)
247283
{
248-
struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
249-
struct iommu_domain *domain;
284+
struct mock_iommu_domain *mock_parent;
285+
struct iommu_hwpt_selftest user_cfg;
286+
int rc;
250287

251-
if (flags &
252-
(~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
253-
return ERR_PTR(-EOPNOTSUPP);
288+
/* must be mock_domain */
289+
if (!parent) {
290+
struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
291+
bool has_dirty_flag = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
292+
bool no_dirty_ops = mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY;
293+
294+
if (flags & (~(IOMMU_HWPT_ALLOC_NEST_PARENT |
295+
IOMMU_HWPT_ALLOC_DIRTY_TRACKING)))
296+
return ERR_PTR(-EOPNOTSUPP);
297+
if (user_data || (has_dirty_flag && no_dirty_ops))
298+
return ERR_PTR(-EOPNOTSUPP);
299+
return __mock_domain_alloc_paging(IOMMU_DOMAIN_UNMANAGED,
300+
has_dirty_flag);
301+
}
254302

255-
if (parent || user_data)
303+
/* must be mock_domain_nested */
304+
if (user_data->type != IOMMU_HWPT_DATA_SELFTEST || flags)
256305
return ERR_PTR(-EOPNOTSUPP);
306+
if (!parent || parent->ops != mock_ops.default_domain_ops)
307+
return ERR_PTR(-EINVAL);
257308

258-
if ((flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING) &&
259-
(mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
260-
return ERR_PTR(-EOPNOTSUPP);
309+
mock_parent = container_of(parent, struct mock_iommu_domain, domain);
310+
if (!mock_parent)
311+
return ERR_PTR(-EINVAL);
261312

262-
domain = mock_domain_alloc(IOMMU_DOMAIN_UNMANAGED);
263-
if (domain && !(mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY))
264-
domain->dirty_ops = &dirty_ops;
265-
if (!domain)
266-
domain = ERR_PTR(-ENOMEM);
267-
return domain;
313+
rc = iommu_copy_struct_from_user(&user_cfg, user_data,
314+
IOMMU_HWPT_DATA_SELFTEST, iotlb);
315+
if (rc)
316+
return ERR_PTR(rc);
317+
318+
return __mock_domain_alloc_nested(mock_parent, &user_cfg);
268319
}
269320

270321
static void mock_domain_free(struct iommu_domain *domain)
@@ -434,26 +485,67 @@ static const struct iommu_ops mock_ops = {
434485
},
435486
};
436487

488+
static void mock_domain_free_nested(struct iommu_domain *domain)
489+
{
490+
struct mock_iommu_domain_nested *mock_nested =
491+
container_of(domain, struct mock_iommu_domain_nested, domain);
492+
493+
kfree(mock_nested);
494+
}
495+
496+
static struct iommu_domain_ops domain_nested_ops = {
497+
.free = mock_domain_free_nested,
498+
.attach_dev = mock_domain_nop_attach,
499+
};
500+
437501
static inline struct iommufd_hw_pagetable *
438-
get_md_pagetable(struct iommufd_ucmd *ucmd, u32 mockpt_id,
439-
struct mock_iommu_domain **mock)
502+
__get_md_pagetable(struct iommufd_ucmd *ucmd, u32 mockpt_id, u32 hwpt_type)
440503
{
441-
struct iommufd_hw_pagetable *hwpt;
442504
struct iommufd_object *obj;
443505

444-
obj = iommufd_get_object(ucmd->ictx, mockpt_id,
445-
IOMMUFD_OBJ_HWPT_PAGING);
506+
obj = iommufd_get_object(ucmd->ictx, mockpt_id, hwpt_type);
446507
if (IS_ERR(obj))
447508
return ERR_CAST(obj);
448-
hwpt = container_of(obj, struct iommufd_hw_pagetable, obj);
449-
if (hwpt->domain->ops != mock_ops.default_domain_ops) {
509+
return container_of(obj, struct iommufd_hw_pagetable, obj);
510+
}
511+
512+
static inline struct iommufd_hw_pagetable *
513+
get_md_pagetable(struct iommufd_ucmd *ucmd, u32 mockpt_id,
514+
struct mock_iommu_domain **mock)
515+
{
516+
struct iommufd_hw_pagetable *hwpt;
517+
518+
hwpt = __get_md_pagetable(ucmd, mockpt_id, IOMMUFD_OBJ_HWPT_PAGING);
519+
if (IS_ERR(hwpt))
520+
return hwpt;
521+
if (hwpt->domain->type != IOMMU_DOMAIN_UNMANAGED ||
522+
hwpt->domain->ops != mock_ops.default_domain_ops) {
450523
iommufd_put_object(&hwpt->obj);
451524
return ERR_PTR(-EINVAL);
452525
}
453526
*mock = container_of(hwpt->domain, struct mock_iommu_domain, domain);
454527
return hwpt;
455528
}
456529

530+
static inline struct iommufd_hw_pagetable *
531+
get_md_pagetable_nested(struct iommufd_ucmd *ucmd, u32 mockpt_id,
532+
struct mock_iommu_domain_nested **mock_nested)
533+
{
534+
struct iommufd_hw_pagetable *hwpt;
535+
536+
hwpt = __get_md_pagetable(ucmd, mockpt_id, IOMMUFD_OBJ_HWPT_NESTED);
537+
if (IS_ERR(hwpt))
538+
return hwpt;
539+
if (hwpt->domain->type != IOMMU_DOMAIN_NESTED ||
540+
hwpt->domain->ops != &domain_nested_ops) {
541+
iommufd_put_object(&hwpt->obj);
542+
return ERR_PTR(-EINVAL);
543+
}
544+
*mock_nested = container_of(hwpt->domain,
545+
struct mock_iommu_domain_nested, domain);
546+
return hwpt;
547+
}
548+
457549
struct mock_bus_type {
458550
struct bus_type bus;
459551
struct notifier_block nb;

0 commit comments

Comments
 (0)