@@ -2996,4 +2996,305 @@ TEST_F(iommufd_viommu, vdevice_cache)
2996
2996
}
2997
2997
}
2998
2998
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
+
2999
3300
TEST_HARNESS_MAIN
0 commit comments