Skip to content

Commit d57a1fb

Browse files
yiliu1765jgunthorpe
authored andcommitted
iommufd/selftest: Add coverage for iommufd pasid attach/detach
This tests iommufd pasid attach/replace/detach. Link: https://patch.msgid.link/r/[email protected] Signed-off-by: Yi Liu <[email protected]> Tested-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent c1b52b0 commit d57a1fb

File tree

3 files changed

+437
-10
lines changed

3 files changed

+437
-10
lines changed

tools/testing/selftests/iommu/iommufd.c

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
29993300
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)