@@ -264,6 +264,121 @@ TEST_F(iommufd_ioas, ioas_destroy)
264
264
}
265
265
}
266
266
267
+ TEST_F (iommufd_ioas , alloc_hwpt_nested )
268
+ {
269
+ const uint32_t min_data_len =
270
+ offsetofend (struct iommu_hwpt_selftest , iotlb );
271
+ struct iommu_hwpt_selftest data = {
272
+ .iotlb = IOMMU_TEST_IOTLB_DEFAULT ,
273
+ };
274
+ uint32_t nested_hwpt_id [2 ] = {};
275
+ uint32_t parent_hwpt_id = 0 ;
276
+ uint32_t parent_hwpt_id_not_work = 0 ;
277
+ uint32_t test_hwpt_id = 0 ;
278
+
279
+ if (self -> device_id ) {
280
+ /* Negative tests */
281
+ test_err_hwpt_alloc (ENOENT , self -> ioas_id , self -> device_id , 0 ,
282
+ & test_hwpt_id );
283
+ test_err_hwpt_alloc (EINVAL , self -> device_id , self -> device_id , 0 ,
284
+ & test_hwpt_id );
285
+
286
+ test_cmd_hwpt_alloc (self -> device_id , self -> ioas_id ,
287
+ IOMMU_HWPT_ALLOC_NEST_PARENT ,
288
+ & parent_hwpt_id );
289
+
290
+ test_cmd_hwpt_alloc (self -> device_id , self -> ioas_id , 0 ,
291
+ & parent_hwpt_id_not_work );
292
+
293
+ /* Negative nested tests */
294
+ test_err_hwpt_alloc_nested (EINVAL , self -> device_id ,
295
+ parent_hwpt_id , 0 ,
296
+ & nested_hwpt_id [0 ],
297
+ IOMMU_HWPT_DATA_NONE , & data ,
298
+ sizeof (data ));
299
+ test_err_hwpt_alloc_nested (EOPNOTSUPP , self -> device_id ,
300
+ parent_hwpt_id , 0 ,
301
+ & nested_hwpt_id [0 ],
302
+ IOMMU_HWPT_DATA_SELFTEST + 1 , & data ,
303
+ sizeof (data ));
304
+ test_err_hwpt_alloc_nested (EINVAL , self -> device_id ,
305
+ parent_hwpt_id , 0 ,
306
+ & nested_hwpt_id [0 ],
307
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
308
+ min_data_len - 1 );
309
+ test_err_hwpt_alloc_nested (EFAULT , self -> device_id ,
310
+ parent_hwpt_id , 0 ,
311
+ & nested_hwpt_id [0 ],
312
+ IOMMU_HWPT_DATA_SELFTEST , NULL ,
313
+ sizeof (data ));
314
+ test_err_hwpt_alloc_nested (
315
+ EOPNOTSUPP , self -> device_id , parent_hwpt_id ,
316
+ IOMMU_HWPT_ALLOC_NEST_PARENT , & nested_hwpt_id [0 ],
317
+ IOMMU_HWPT_DATA_SELFTEST , & data , sizeof (data ));
318
+ test_err_hwpt_alloc_nested (EINVAL , self -> device_id ,
319
+ parent_hwpt_id_not_work , 0 ,
320
+ & nested_hwpt_id [0 ],
321
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
322
+ sizeof (data ));
323
+
324
+ /* Allocate two nested hwpts sharing one common parent hwpt */
325
+ test_cmd_hwpt_alloc_nested (self -> device_id , parent_hwpt_id , 0 ,
326
+ & nested_hwpt_id [0 ],
327
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
328
+ sizeof (data ));
329
+ test_cmd_hwpt_alloc_nested (self -> device_id , parent_hwpt_id , 0 ,
330
+ & nested_hwpt_id [1 ],
331
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
332
+ sizeof (data ));
333
+
334
+ /* Negative test: a nested hwpt on top of a nested hwpt */
335
+ test_err_hwpt_alloc_nested (EINVAL , self -> device_id ,
336
+ nested_hwpt_id [0 ], 0 , & test_hwpt_id ,
337
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
338
+ sizeof (data ));
339
+ /* Negative test: parent hwpt now cannot be freed */
340
+ EXPECT_ERRNO (EBUSY ,
341
+ _test_ioctl_destroy (self -> fd , parent_hwpt_id ));
342
+
343
+ /* Attach device to nested_hwpt_id[0] that then will be busy */
344
+ test_cmd_mock_domain_replace (self -> stdev_id , nested_hwpt_id [0 ]);
345
+ EXPECT_ERRNO (EBUSY ,
346
+ _test_ioctl_destroy (self -> fd , nested_hwpt_id [0 ]));
347
+
348
+ /* Switch from nested_hwpt_id[0] to nested_hwpt_id[1] */
349
+ test_cmd_mock_domain_replace (self -> stdev_id , nested_hwpt_id [1 ]);
350
+ EXPECT_ERRNO (EBUSY ,
351
+ _test_ioctl_destroy (self -> fd , nested_hwpt_id [1 ]));
352
+ test_ioctl_destroy (nested_hwpt_id [0 ]);
353
+
354
+ /* Detach from nested_hwpt_id[1] and destroy it */
355
+ test_cmd_mock_domain_replace (self -> stdev_id , parent_hwpt_id );
356
+ test_ioctl_destroy (nested_hwpt_id [1 ]);
357
+
358
+ /* Detach from the parent hw_pagetable and destroy it */
359
+ test_cmd_mock_domain_replace (self -> stdev_id , self -> ioas_id );
360
+ test_ioctl_destroy (parent_hwpt_id );
361
+ test_ioctl_destroy (parent_hwpt_id_not_work );
362
+ } else {
363
+ test_err_hwpt_alloc (ENOENT , self -> device_id , self -> ioas_id , 0 ,
364
+ & parent_hwpt_id );
365
+ test_err_hwpt_alloc_nested (ENOENT , self -> device_id ,
366
+ parent_hwpt_id , 0 ,
367
+ & nested_hwpt_id [0 ],
368
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
369
+ sizeof (data ));
370
+ test_err_hwpt_alloc_nested (ENOENT , self -> device_id ,
371
+ parent_hwpt_id , 0 ,
372
+ & nested_hwpt_id [1 ],
373
+ IOMMU_HWPT_DATA_SELFTEST , & data ,
374
+ sizeof (data ));
375
+ test_err_mock_domain_replace (ENOENT , self -> stdev_id ,
376
+ nested_hwpt_id [0 ]);
377
+ test_err_mock_domain_replace (ENOENT , self -> stdev_id ,
378
+ nested_hwpt_id [1 ]);
379
+ }
380
+ }
381
+
267
382
TEST_F (iommufd_ioas , hwpt_attach )
268
383
{
269
384
/* Create a device attached directly to a hwpt */
0 commit comments