@@ -264,6 +264,121 @@ TEST_F(iommufd_ioas, ioas_destroy)
264264 }
265265}
266266
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+
267382TEST_F (iommufd_ioas , hwpt_attach )
268383{
269384 /* Create a device attached directly to a hwpt */
0 commit comments