@@ -2996,4 +2996,305 @@ TEST_F(iommufd_viommu, vdevice_cache)
29962996 }
29972997}
29982998
2999+ FIXTURE (iommufd_device_pasid )
3000+ {
3001+ int fd ;
3002+ uint32_t ioas_id ;
3003+ uint32_t hwpt_id ;
3004+ uint32_t stdev_id ;
3005+ uint32_t device_id ;
3006+ uint32_t no_pasid_stdev_id ;
3007+ uint32_t no_pasid_device_id ;
3008+ };
3009+
3010+ FIXTURE_VARIANT (iommufd_device_pasid )
3011+ {
3012+ bool pasid_capable ;
3013+ };
3014+
3015+ FIXTURE_SETUP (iommufd_device_pasid )
3016+ {
3017+ self -> fd = open ("/dev/iommu" , O_RDWR );
3018+ ASSERT_NE (-1 , self -> fd );
3019+ test_ioctl_ioas_alloc (& self -> ioas_id );
3020+
3021+ test_cmd_mock_domain_flags (self -> ioas_id ,
3022+ MOCK_FLAGS_DEVICE_PASID ,
3023+ & self -> stdev_id , & self -> hwpt_id ,
3024+ & self -> device_id );
3025+ if (!variant -> pasid_capable )
3026+ test_cmd_mock_domain_flags (self -> ioas_id , 0 ,
3027+ & self -> no_pasid_stdev_id , NULL ,
3028+ & self -> no_pasid_device_id );
3029+ }
3030+
3031+ FIXTURE_TEARDOWN (iommufd_device_pasid )
3032+ {
3033+ teardown_iommufd (self -> fd , _metadata );
3034+ }
3035+
3036+ FIXTURE_VARIANT_ADD (iommufd_device_pasid , no_pasid )
3037+ {
3038+ .pasid_capable = false,
3039+ };
3040+
3041+ FIXTURE_VARIANT_ADD (iommufd_device_pasid , has_pasid )
3042+ {
3043+ .pasid_capable = true,
3044+ };
3045+
3046+ TEST_F (iommufd_device_pasid , pasid_attach )
3047+ {
3048+ struct iommu_hwpt_selftest data = {
3049+ .iotlb = IOMMU_TEST_IOTLB_DEFAULT ,
3050+ };
3051+ uint32_t nested_hwpt_id [3 ] = {};
3052+ uint32_t parent_hwpt_id = 0 ;
3053+ uint32_t fault_id , fault_fd ;
3054+ uint32_t s2_hwpt_id = 0 ;
3055+ uint32_t iopf_hwpt_id ;
3056+ uint32_t pasid = 100 ;
3057+ uint32_t viommu_id ;
3058+
3059+ /* Allocate two nested hwpts sharing one common parent hwpt */
3060+ test_cmd_hwpt_alloc (self -> device_id , self -> ioas_id ,
3061+ IOMMU_HWPT_ALLOC_NEST_PARENT ,
3062+ & parent_hwpt_id );
3063+ test_cmd_hwpt_alloc_nested (self -> device_id , parent_hwpt_id ,
3064+ IOMMU_HWPT_ALLOC_PASID ,
3065+ & nested_hwpt_id [0 ],
3066+ IOMMU_HWPT_DATA_SELFTEST ,
3067+ & data , sizeof (data ));
3068+ test_cmd_hwpt_alloc_nested (self -> device_id , parent_hwpt_id ,
3069+ IOMMU_HWPT_ALLOC_PASID ,
3070+ & nested_hwpt_id [1 ],
3071+ IOMMU_HWPT_DATA_SELFTEST ,
3072+ & data , sizeof (data ));
3073+
3074+ /* Fault related preparation */
3075+ test_ioctl_fault_alloc (& fault_id , & fault_fd );
3076+ test_cmd_hwpt_alloc_iopf (self -> device_id , parent_hwpt_id , fault_id ,
3077+ IOMMU_HWPT_FAULT_ID_VALID | IOMMU_HWPT_ALLOC_PASID ,
3078+ & iopf_hwpt_id ,
3079+ IOMMU_HWPT_DATA_SELFTEST , & data ,
3080+ sizeof (data ));
3081+
3082+ /* Allocate a regular nested hwpt based on viommu */
3083+ test_cmd_viommu_alloc (self -> device_id , parent_hwpt_id ,
3084+ IOMMU_VIOMMU_TYPE_SELFTEST ,
3085+ & viommu_id );
3086+ test_cmd_hwpt_alloc_nested (self -> device_id , viommu_id ,
3087+ IOMMU_HWPT_ALLOC_PASID ,
3088+ & nested_hwpt_id [2 ],
3089+ IOMMU_HWPT_DATA_SELFTEST , & data ,
3090+ sizeof (data ));
3091+
3092+ test_cmd_hwpt_alloc (self -> device_id , self -> ioas_id ,
3093+ IOMMU_HWPT_ALLOC_PASID ,
3094+ & s2_hwpt_id );
3095+
3096+ /* Attach RID to non-pasid compat domain, */
3097+ test_cmd_mock_domain_replace (self -> stdev_id , parent_hwpt_id );
3098+ /* then attach to pasid should fail */
3099+ test_err_pasid_attach (EINVAL , pasid , s2_hwpt_id );
3100+
3101+ /* Attach RID to pasid compat domain, */
3102+ test_cmd_mock_domain_replace (self -> stdev_id , s2_hwpt_id );
3103+ /* then attach to pasid should succeed, */
3104+ test_cmd_pasid_attach (pasid , nested_hwpt_id [0 ]);
3105+ /* but attach RID to non-pasid compat domain should fail now. */
3106+ test_err_mock_domain_replace (EINVAL , self -> stdev_id , parent_hwpt_id );
3107+ /*
3108+ * Detach hwpt from pasid 100, and check if the pasid 100
3109+ * has null domain.
3110+ */
3111+ test_cmd_pasid_detach (pasid );
3112+ ASSERT_EQ (0 ,
3113+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3114+ pasid , 0 ));
3115+ /* RID is attached to pasid-comapt domain, pasid path is not used */
3116+
3117+ if (!variant -> pasid_capable ) {
3118+ /*
3119+ * PASID-compatible domain can be used by non-PASID-capable
3120+ * device.
3121+ */
3122+ test_cmd_mock_domain_replace (self -> no_pasid_stdev_id , nested_hwpt_id [0 ]);
3123+ test_cmd_mock_domain_replace (self -> no_pasid_stdev_id , self -> ioas_id );
3124+ /*
3125+ * Attach hwpt to pasid 100 of non-PASID-capable device,
3126+ * should fail, no matter domain is pasid-comapt or not.
3127+ */
3128+ EXPECT_ERRNO (EINVAL ,
3129+ _test_cmd_pasid_attach (self -> fd , self -> no_pasid_stdev_id ,
3130+ pasid , parent_hwpt_id ));
3131+ EXPECT_ERRNO (EINVAL ,
3132+ _test_cmd_pasid_attach (self -> fd , self -> no_pasid_stdev_id ,
3133+ pasid , s2_hwpt_id ));
3134+ }
3135+
3136+ /*
3137+ * Attach non pasid compat hwpt to pasid-capable device, should
3138+ * fail, and have null domain.
3139+ */
3140+ test_err_pasid_attach (EINVAL , pasid , parent_hwpt_id );
3141+ ASSERT_EQ (0 ,
3142+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3143+ pasid , 0 ));
3144+
3145+ /*
3146+ * Attach ioas to pasid 100, should fail, domain should
3147+ * be null.
3148+ */
3149+ test_err_pasid_attach (EINVAL , pasid , self -> ioas_id );
3150+ ASSERT_EQ (0 ,
3151+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3152+ pasid , 0 ));
3153+
3154+ /*
3155+ * Attach the s2_hwpt to pasid 100, should succeed, domain should
3156+ * be valid.
3157+ */
3158+ test_cmd_pasid_attach (pasid , s2_hwpt_id );
3159+ ASSERT_EQ (0 ,
3160+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3161+ pasid , s2_hwpt_id ));
3162+
3163+ /*
3164+ * Try attach pasid 100 with another hwpt, should FAIL
3165+ * as attach does not allow overwrite, use REPLACE instead.
3166+ */
3167+ test_err_pasid_attach (EBUSY , pasid , nested_hwpt_id [0 ]);
3168+
3169+ /*
3170+ * Detach hwpt from pasid 100 for next test, should succeed,
3171+ * and have null domain.
3172+ */
3173+ test_cmd_pasid_detach (pasid );
3174+ ASSERT_EQ (0 ,
3175+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3176+ pasid , 0 ));
3177+
3178+ /*
3179+ * Attach nested hwpt to pasid 100, should succeed, domain
3180+ * should be valid.
3181+ */
3182+ test_cmd_pasid_attach (pasid , nested_hwpt_id [0 ]);
3183+ ASSERT_EQ (0 ,
3184+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3185+ pasid , nested_hwpt_id [0 ]));
3186+
3187+ /* Attach to pasid 100 which has been attached, should fail. */
3188+ test_err_pasid_attach (EBUSY , pasid , nested_hwpt_id [0 ]);
3189+
3190+ /* cleanup pasid 100 */
3191+ test_cmd_pasid_detach (pasid );
3192+
3193+ /* Replace tests */
3194+
3195+ pasid = 200 ;
3196+ /*
3197+ * Replace pasid 200 without attaching it, should fail
3198+ * with -EINVAL.
3199+ */
3200+ test_err_pasid_replace (EINVAL , pasid , s2_hwpt_id );
3201+
3202+ /*
3203+ * Attach the s2 hwpt to pasid 200, should succeed, domain should
3204+ * be valid.
3205+ */
3206+ test_cmd_pasid_attach (pasid , s2_hwpt_id );
3207+ ASSERT_EQ (0 ,
3208+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3209+ pasid , s2_hwpt_id ));
3210+
3211+ /*
3212+ * Replace pasid 200 with self->ioas_id, should fail
3213+ * and domain should be the prior s2 hwpt.
3214+ */
3215+ test_err_pasid_replace (EINVAL , pasid , self -> ioas_id );
3216+ ASSERT_EQ (0 ,
3217+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3218+ pasid , s2_hwpt_id ));
3219+
3220+ /*
3221+ * Replace a nested hwpt for pasid 200, should succeed,
3222+ * and have valid domain.
3223+ */
3224+ test_cmd_pasid_replace (pasid , nested_hwpt_id [0 ]);
3225+ ASSERT_EQ (0 ,
3226+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3227+ pasid , nested_hwpt_id [0 ]));
3228+
3229+ /*
3230+ * Replace with another nested hwpt for pasid 200, should
3231+ * succeed, and have valid domain.
3232+ */
3233+ test_cmd_pasid_replace (pasid , nested_hwpt_id [1 ]);
3234+ ASSERT_EQ (0 ,
3235+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3236+ pasid , nested_hwpt_id [1 ]));
3237+
3238+ /* cleanup pasid 200 */
3239+ test_cmd_pasid_detach (pasid );
3240+
3241+ /* Negative Tests for pasid replace, use pasid 1024 */
3242+
3243+ /*
3244+ * Attach the s2 hwpt to pasid 1024, should succeed, domain should
3245+ * be valid.
3246+ */
3247+ pasid = 1024 ;
3248+ test_cmd_pasid_attach (pasid , s2_hwpt_id );
3249+ ASSERT_EQ (0 ,
3250+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3251+ pasid , s2_hwpt_id ));
3252+
3253+ /*
3254+ * Replace pasid 1024 with nested_hwpt_id[0], should fail,
3255+ * but have the old valid domain. This is a designed
3256+ * negative case. Normally, this shall succeed.
3257+ */
3258+ test_err_pasid_replace (ENOMEM , pasid , nested_hwpt_id [0 ]);
3259+ ASSERT_EQ (0 ,
3260+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3261+ pasid , s2_hwpt_id ));
3262+
3263+ /* cleanup pasid 1024 */
3264+ test_cmd_pasid_detach (pasid );
3265+
3266+ /* Attach to iopf-capable hwpt */
3267+
3268+ /*
3269+ * Attach an iopf hwpt to pasid 2048, should succeed, domain should
3270+ * be valid.
3271+ */
3272+ pasid = 2048 ;
3273+ test_cmd_pasid_attach (pasid , iopf_hwpt_id );
3274+ ASSERT_EQ (0 ,
3275+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3276+ pasid , iopf_hwpt_id ));
3277+
3278+ test_cmd_trigger_iopf_pasid (self -> device_id , pasid , fault_fd );
3279+
3280+ /*
3281+ * Replace with s2_hwpt_id for pasid 2048, should
3282+ * succeed, and have valid domain.
3283+ */
3284+ test_cmd_pasid_replace (pasid , s2_hwpt_id );
3285+ ASSERT_EQ (0 ,
3286+ test_cmd_pasid_check_hwpt (self -> fd , self -> stdev_id ,
3287+ pasid , s2_hwpt_id ));
3288+
3289+ /* cleanup pasid 2048 */
3290+ test_cmd_pasid_detach (pasid );
3291+
3292+ test_ioctl_destroy (iopf_hwpt_id );
3293+ close (fault_fd );
3294+ test_ioctl_destroy (fault_id );
3295+
3296+ /* Detach the s2_hwpt_id from RID */
3297+ test_cmd_mock_domain_replace (self -> stdev_id , self -> ioas_id );
3298+ }
3299+
29993300TEST_HARNESS_MAIN
0 commit comments