@@ -116,6 +116,7 @@ TEST_F(iommufd, cmd_length)
116116 TEST_LENGTH (iommu_destroy , IOMMU_DESTROY , id );
117117 TEST_LENGTH (iommu_hw_info , IOMMU_GET_HW_INFO , __reserved );
118118 TEST_LENGTH (iommu_hwpt_alloc , IOMMU_HWPT_ALLOC , __reserved );
119+ TEST_LENGTH (iommu_hwpt_invalidate , IOMMU_HWPT_INVALIDATE , __reserved );
119120 TEST_LENGTH (iommu_ioas_alloc , IOMMU_IOAS_ALLOC , out_ioas_id );
120121 TEST_LENGTH (iommu_ioas_iova_ranges , IOMMU_IOAS_IOVA_RANGES ,
121122 out_iova_alignment );
@@ -271,7 +272,9 @@ TEST_F(iommufd_ioas, alloc_hwpt_nested)
271272 struct iommu_hwpt_selftest data = {
272273 .iotlb = IOMMU_TEST_IOTLB_DEFAULT ,
273274 };
275+ struct iommu_hwpt_invalidate_selftest inv_reqs [2 ] = {};
274276 uint32_t nested_hwpt_id [2 ] = {};
277+ uint32_t num_inv ;
275278 uint32_t parent_hwpt_id = 0 ;
276279 uint32_t parent_hwpt_id_not_work = 0 ;
277280 uint32_t test_hwpt_id = 0 ;
@@ -344,6 +347,151 @@ TEST_F(iommufd_ioas, alloc_hwpt_nested)
344347 EXPECT_ERRNO (EBUSY ,
345348 _test_ioctl_destroy (self -> fd , parent_hwpt_id ));
346349
350+ /* hwpt_invalidate only supports a user-managed hwpt (nested) */
351+ num_inv = 1 ;
352+ test_err_hwpt_invalidate (ENOENT , parent_hwpt_id , inv_reqs ,
353+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
354+ sizeof (* inv_reqs ), & num_inv );
355+ assert (!num_inv );
356+
357+ /* Check data_type by passing zero-length array */
358+ num_inv = 0 ;
359+ test_cmd_hwpt_invalidate (nested_hwpt_id [0 ], inv_reqs ,
360+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
361+ sizeof (* inv_reqs ), & num_inv );
362+ assert (!num_inv );
363+
364+ /* Negative test: Invalid data_type */
365+ num_inv = 1 ;
366+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], inv_reqs ,
367+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST_INVALID ,
368+ sizeof (* inv_reqs ), & num_inv );
369+ assert (!num_inv );
370+
371+ /* Negative test: structure size sanity */
372+ num_inv = 1 ;
373+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], inv_reqs ,
374+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
375+ sizeof (* inv_reqs ) + 1 , & num_inv );
376+ assert (!num_inv );
377+
378+ num_inv = 1 ;
379+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], inv_reqs ,
380+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
381+ 1 , & num_inv );
382+ assert (!num_inv );
383+
384+ /* Negative test: invalid flag is passed */
385+ num_inv = 1 ;
386+ inv_reqs [0 ].flags = 0xffffffff ;
387+ test_err_hwpt_invalidate (EOPNOTSUPP , nested_hwpt_id [0 ], inv_reqs ,
388+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
389+ sizeof (* inv_reqs ), & num_inv );
390+ assert (!num_inv );
391+
392+ /* Negative test: invalid data_uptr when array is not empty */
393+ num_inv = 1 ;
394+ inv_reqs [0 ].flags = 0 ;
395+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], NULL ,
396+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
397+ sizeof (* inv_reqs ), & num_inv );
398+ assert (!num_inv );
399+
400+ /* Negative test: invalid entry_len when array is not empty */
401+ num_inv = 1 ;
402+ inv_reqs [0 ].flags = 0 ;
403+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], inv_reqs ,
404+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
405+ 0 , & num_inv );
406+ assert (!num_inv );
407+
408+ /* Negative test: invalid iotlb_id */
409+ num_inv = 1 ;
410+ inv_reqs [0 ].flags = 0 ;
411+ inv_reqs [0 ].iotlb_id = MOCK_NESTED_DOMAIN_IOTLB_ID_MAX + 1 ;
412+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], inv_reqs ,
413+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
414+ sizeof (* inv_reqs ), & num_inv );
415+ assert (!num_inv );
416+
417+ /*
418+ * Invalidate the 1st iotlb entry but fail the 2nd request
419+ * due to invalid flags configuration in the 2nd request.
420+ */
421+ num_inv = 2 ;
422+ inv_reqs [0 ].flags = 0 ;
423+ inv_reqs [0 ].iotlb_id = 0 ;
424+ inv_reqs [1 ].flags = 0xffffffff ;
425+ inv_reqs [1 ].iotlb_id = 1 ;
426+ test_err_hwpt_invalidate (EOPNOTSUPP , nested_hwpt_id [0 ], inv_reqs ,
427+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
428+ sizeof (* inv_reqs ), & num_inv );
429+ assert (num_inv == 1 );
430+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 0 , 0 );
431+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 1 ,
432+ IOMMU_TEST_IOTLB_DEFAULT );
433+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 2 ,
434+ IOMMU_TEST_IOTLB_DEFAULT );
435+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 3 ,
436+ IOMMU_TEST_IOTLB_DEFAULT );
437+
438+ /*
439+ * Invalidate the 1st iotlb entry but fail the 2nd request
440+ * due to invalid iotlb_id configuration in the 2nd request.
441+ */
442+ num_inv = 2 ;
443+ inv_reqs [0 ].flags = 0 ;
444+ inv_reqs [0 ].iotlb_id = 0 ;
445+ inv_reqs [1 ].flags = 0 ;
446+ inv_reqs [1 ].iotlb_id = MOCK_NESTED_DOMAIN_IOTLB_ID_MAX + 1 ;
447+ test_err_hwpt_invalidate (EINVAL , nested_hwpt_id [0 ], inv_reqs ,
448+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
449+ sizeof (* inv_reqs ), & num_inv );
450+ assert (num_inv == 1 );
451+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 0 , 0 );
452+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 1 ,
453+ IOMMU_TEST_IOTLB_DEFAULT );
454+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 2 ,
455+ IOMMU_TEST_IOTLB_DEFAULT );
456+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 3 ,
457+ IOMMU_TEST_IOTLB_DEFAULT );
458+
459+ /* Invalidate the 2nd iotlb entry and verify */
460+ num_inv = 1 ;
461+ inv_reqs [0 ].flags = 0 ;
462+ inv_reqs [0 ].iotlb_id = 1 ;
463+ test_cmd_hwpt_invalidate (nested_hwpt_id [0 ], inv_reqs ,
464+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
465+ sizeof (* inv_reqs ), & num_inv );
466+ assert (num_inv == 1 );
467+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 0 , 0 );
468+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 1 , 0 );
469+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 2 ,
470+ IOMMU_TEST_IOTLB_DEFAULT );
471+ test_cmd_hwpt_check_iotlb (nested_hwpt_id [0 ], 3 ,
472+ IOMMU_TEST_IOTLB_DEFAULT );
473+
474+ /* Invalidate the 3rd and 4th iotlb entries and verify */
475+ num_inv = 2 ;
476+ inv_reqs [0 ].flags = 0 ;
477+ inv_reqs [0 ].iotlb_id = 2 ;
478+ inv_reqs [1 ].flags = 0 ;
479+ inv_reqs [1 ].iotlb_id = 3 ;
480+ test_cmd_hwpt_invalidate (nested_hwpt_id [0 ], inv_reqs ,
481+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
482+ sizeof (* inv_reqs ), & num_inv );
483+ assert (num_inv == 2 );
484+ test_cmd_hwpt_check_iotlb_all (nested_hwpt_id [0 ], 0 );
485+
486+ /* Invalidate all iotlb entries for nested_hwpt_id[1] and verify */
487+ num_inv = 1 ;
488+ inv_reqs [0 ].flags = IOMMU_TEST_INVALIDATE_FLAG_ALL ;
489+ test_cmd_hwpt_invalidate (nested_hwpt_id [1 ], inv_reqs ,
490+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST ,
491+ sizeof (* inv_reqs ), & num_inv );
492+ assert (num_inv == 1 );
493+ test_cmd_hwpt_check_iotlb_all (nested_hwpt_id [1 ], 0 );
494+
347495 /* Attach device to nested_hwpt_id[0] that then will be busy */
348496 test_cmd_mock_domain_replace (self -> stdev_id , nested_hwpt_id [0 ]);
349497 EXPECT_ERRNO (EBUSY ,
0 commit comments