This tests iommufd pasid attach/replace/detach.

Signed-off-by: Yi Liu <yi.l....@intel.com>
---
 tools/testing/selftests/iommu/iommufd.c       | 172 ++++++++++++++++++
 .../selftests/iommu/iommufd_fail_nth.c        |  28 ++-
 tools/testing/selftests/iommu/iommufd_utils.h |  78 ++++++++
 3 files changed, 274 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/iommu/iommufd.c 
b/tools/testing/selftests/iommu/iommufd.c
index 7cf06a4635d8..92e20a18bbea 100644
--- a/tools/testing/selftests/iommu/iommufd.c
+++ b/tools/testing/selftests/iommu/iommufd.c
@@ -2022,4 +2022,176 @@ TEST_F(vfio_compat_mock_domain, huge_map)
        }
 }
 
+FIXTURE(iommufd_device_pasid)
+{
+       int fd;
+       uint32_t ioas_id;
+       uint32_t hwpt_id;
+       uint32_t stdev_id;
+       uint32_t device_id;
+};
+
+FIXTURE_SETUP(iommufd_device_pasid)
+{
+       self->fd = open("/dev/iommu", O_RDWR);
+       ASSERT_NE(-1, self->fd);
+       test_ioctl_ioas_alloc(&self->ioas_id);
+
+       test_cmd_mock_domain(self->ioas_id, &self->stdev_id,
+                            &self->hwpt_id, &self->device_id);
+}
+
+FIXTURE_TEARDOWN(iommufd_device_pasid)
+{
+       teardown_iommufd(self->fd, _metadata);
+}
+
+TEST_F(iommufd_device_pasid, pasid_attach)
+{
+       if (self->device_id) {
+               struct iommu_hwpt_selftest data = {
+                       .iotlb =  IOMMU_TEST_IOTLB_DEFAULT,
+               };
+               uint32_t nested_hwpt_id[2] = {};
+               uint32_t parent_hwpt_id = 0;
+               uint32_t pasid = 100;
+               bool result;
+
+               /* Allocate two nested hwpts sharing one common parent hwpt */
+               test_cmd_hwpt_alloc(self->device_id, self->ioas_id,
+                                   IOMMU_HWPT_ALLOC_NEST_PARENT,
+                                   &parent_hwpt_id);
+
+               test_cmd_hwpt_alloc_nested(self->device_id, parent_hwpt_id, 0,
+                                          &nested_hwpt_id[0],
+                                          IOMMU_HWPT_TYPE_SELFTEST,
+                                          &data, sizeof(data));
+               test_cmd_hwpt_alloc_nested(self->device_id, parent_hwpt_id, 0,
+                                          &nested_hwpt_id[1],
+                                          IOMMU_HWPT_TYPE_SELFTEST,
+                                          &data, sizeof(data));
+
+               /*
+                * Attach ioas to pasid 100, should succeed, domain should
+                * be valid.
+                */
+               test_cmd_pasid_attach(pasid, self->ioas_id);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, self->hwpt_id,
+                                                     &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Try attach pasid 100 with self->ioas_id, should succeed
+                * as it is the same with existing hwpt.
+                */
+               test_cmd_pasid_attach(pasid, self->ioas_id);
+
+               /*
+                * Try attach pasid 100 with another hwpt, should FAIL
+                * as attach does not allow overwrite, use REPLACE instead.
+                */
+               test_err_cmd_pasid_attach(EINVAL, pasid, nested_hwpt_id[0]);
+
+               /*
+                * Detach hwpt from pasid 100, and check if the pasid 100
+                * has null domain. Should be done before the next attach.
+                */
+               test_cmd_pasid_detach(pasid);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, 0, &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Attach nested hwpt to pasid 100, should succeed, domain
+                * should be valid.
+                */
+               test_cmd_pasid_attach(pasid, nested_hwpt_id[0]);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, nested_hwpt_id[0],
+                                                     &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Detach hwpt from pasid 100, and check if the pasid 100
+                * has null domain
+                */
+               test_cmd_pasid_detach(pasid);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, 0, &result));
+               EXPECT_EQ(1, result);
+
+               /* Replace tests */
+               pasid = 200;
+
+               /*
+                * Replace pasid 200 without attaching it first, should
+                * fail with -EINVAL.
+                */
+               test_err_cmd_pasid_replace(EINVAL, pasid, parent_hwpt_id);
+
+               /*
+                * Attach a s2 hwpt to pasid 200, should succeed, domain should
+                * be valid.
+                */
+               test_cmd_pasid_attach(pasid, parent_hwpt_id);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, parent_hwpt_id,
+                                                     &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Replace pasid 200 with self->ioas_id, should succeed,
+                * and have valid domain.
+                */
+               test_cmd_pasid_replace(pasid, self->ioas_id);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, self->hwpt_id,
+                                                     &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Replace a nested hwpt for pasid 200, should succeed,
+                * and have valid domain.
+                */
+               test_cmd_pasid_replace(pasid, nested_hwpt_id[0]);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, nested_hwpt_id[0],
+                                                     &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Replace with another nested hwpt for pasid 200, should
+                * succeed, and have valid domain.
+                */
+               test_cmd_pasid_replace(pasid, nested_hwpt_id[1]);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, nested_hwpt_id[1],
+                                                     &result));
+               EXPECT_EQ(1, result);
+
+               /*
+                * Detach hwpt from pasid 200, and check if the pasid 200
+                * has null domain.
+                */
+               test_cmd_pasid_detach(pasid);
+               ASSERT_EQ(0,
+                         test_cmd_pasid_check_domain(self->fd, self->stdev_id,
+                                                     pasid, 0, &result));
+               EXPECT_EQ(1, result);
+
+               test_ioctl_destroy(nested_hwpt_id[0]);
+               test_ioctl_destroy(nested_hwpt_id[1]);
+               test_ioctl_destroy(parent_hwpt_id);
+       }
+}
+
 TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/iommu/iommufd_fail_nth.c 
b/tools/testing/selftests/iommu/iommufd_fail_nth.c
index d3f47f262c04..797f2b3103fc 100644
--- a/tools/testing/selftests/iommu/iommufd_fail_nth.c
+++ b/tools/testing/selftests/iommu/iommufd_fail_nth.c
@@ -206,12 +206,16 @@ FIXTURE(basic_fail_nth)
 {
        int fd;
        uint32_t access_id;
+       uint32_t stdev_id;
+       uint32_t pasid;
 };
 
 FIXTURE_SETUP(basic_fail_nth)
 {
        self->fd = -1;
        self->access_id = 0;
+       self->stdev_id = 0;
+       self->pasid = 0; //test should use a non-zero value
 }
 
 FIXTURE_TEARDOWN(basic_fail_nth)
@@ -223,6 +227,8 @@ FIXTURE_TEARDOWN(basic_fail_nth)
                rc = _test_cmd_destroy_access(self->access_id);
                assert(rc == 0);
        }
+       if (self->pasid && self->stdev_id)
+               _test_cmd_pasid_detach(self->fd, self->stdev_id, self->pasid);
        teardown_iommufd(self->fd, _metadata);
 }
 
@@ -579,7 +585,6 @@ TEST_FAIL_NTH(basic_fail_nth, device)
        struct iommu_test_hw_info info;
        uint32_t ioas_id;
        uint32_t ioas_id2;
-       uint32_t stdev_id;
        uint32_t idev_id;
        uint32_t hwpt_id;
        __u64 iova;
@@ -608,7 +613,7 @@ TEST_FAIL_NTH(basic_fail_nth, device)
 
        fail_nth_enable();
 
-       if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, NULL,
+       if (_test_cmd_mock_domain(self->fd, ioas_id, &self->stdev_id, NULL,
                                  &idev_id))
                return -1;
 
@@ -619,11 +624,26 @@ TEST_FAIL_NTH(basic_fail_nth, device)
                                 IOMMU_HWPT_TYPE_DEFAULT, 0, 0))
                return -1;
 
-       if (_test_cmd_mock_domain_replace(self->fd, stdev_id, ioas_id2, NULL))
+       if (_test_cmd_mock_domain_replace(self->fd, self->stdev_id, ioas_id2, 
NULL))
+               return -1;
+
+       if (_test_cmd_mock_domain_replace(self->fd, self->stdev_id, hwpt_id, 
NULL))
                return -1;
 
-       if (_test_cmd_mock_domain_replace(self->fd, stdev_id, hwpt_id, NULL))
+       self->pasid = 200;
+
+       /* Tests for pasid attach/replace/detach */
+       if (_test_cmd_pasid_attach(self->fd, self->stdev_id, self->pasid, 
ioas_id))
                return -1;
+
+       if (_test_cmd_pasid_replace(self->fd, self->stdev_id, self->pasid, 
ioas_id2))
+               return -1;
+
+       if (_test_cmd_pasid_detach(self->fd, self->stdev_id, self->pasid))
+               return -1;
+
+       self->pasid = 0;
+
        return 0;
 }
 
diff --git a/tools/testing/selftests/iommu/iommufd_utils.h 
b/tools/testing/selftests/iommu/iommufd_utils.h
index b75f168fca46..40d954a4cbc1 100644
--- a/tools/testing/selftests/iommu/iommufd_utils.h
+++ b/tools/testing/selftests/iommu/iommufd_utils.h
@@ -551,3 +551,81 @@ static int _test_cmd_unset_dev_data(int fd, __u32 
device_id)
 #define test_err_unset_dev_data(_errno, device_id) \
        EXPECT_ERRNO(_errno,                       \
                     _test_cmd_unset_dev_data(self->fd, device_id))
+
+static int _test_cmd_pasid_attach(int fd, __u32 stdev_id, __u32 pasid, __u32 
pt_id)
+{
+       struct iommu_test_cmd test_attach = {
+               .size = sizeof(test_attach),
+               .op = IOMMU_TEST_OP_PASID_ATTACH,
+               .id = stdev_id,
+               .pasid_attach = {
+                       .pasid = pasid,
+                       .pt_id = pt_id,
+               },
+       };
+
+       return ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_PASID_ATTACH), 
&test_attach);
+}
+
+#define test_cmd_pasid_attach(pasid, hwpt_id) \
+       ASSERT_EQ(0, _test_cmd_pasid_attach(self->fd, self->stdev_id, pasid, 
hwpt_id))
+
+#define test_err_cmd_pasid_attach(_errno, pasid, hwpt_id) \
+       EXPECT_ERRNO(_errno, \
+                    _test_cmd_pasid_attach(self->fd, self->stdev_id, pasid, 
hwpt_id))
+
+static int _test_cmd_pasid_replace(int fd, __u32 stdev_id, __u32 pasid, __u32 
pt_id)
+{
+       struct iommu_test_cmd test_replace = {
+               .size = sizeof(test_replace),
+               .op = IOMMU_TEST_OP_PASID_REPLACE,
+               .id = stdev_id,
+               .pasid_replace = {
+                       .pasid = pasid,
+                       .pt_id = pt_id,
+               },
+       };
+
+       return ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_PASID_REPLACE), 
&test_replace);
+}
+
+#define test_cmd_pasid_replace(pasid, hwpt_id) \
+       ASSERT_EQ(0, _test_cmd_pasid_replace(self->fd, self->stdev_id, pasid, 
hwpt_id))
+
+#define test_err_cmd_pasid_replace(_errno, pasid, hwpt_id) \
+       EXPECT_ERRNO(_errno, \
+                    _test_cmd_pasid_replace(self->fd, self->stdev_id, pasid, 
hwpt_id))
+
+static int _test_cmd_pasid_detach(int fd, __u32 stdev_id, __u32 pasid)
+{
+       struct iommu_test_cmd test_detach = {
+               .size = sizeof(test_detach),
+               .op = IOMMU_TEST_OP_PASID_DETACH,
+               .id = stdev_id,
+               .pasid_detach = {
+                       .pasid = pasid,
+               },
+       };
+
+       return ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_PASID_DETACH), 
&test_detach);
+}
+
+#define test_cmd_pasid_detach(pasid) \
+       ASSERT_EQ(0, _test_cmd_pasid_detach(self->fd, self->stdev_id, pasid))
+
+static int test_cmd_pasid_check_domain(int fd, __u32 stdev_id, __u32 pasid,
+                                      __u32 hwpt_id, bool *result)
+{
+       struct iommu_test_cmd test_pasid_check = {
+               .size = sizeof(test_pasid_check),
+               .op = IOMMU_TEST_OP_PASID_CHECK_DOMAIN,
+               .id = stdev_id,
+               .pasid_check = {
+                       .pasid = pasid,
+                       .hwpt_id = hwpt_id,
+                       .out_result_ptr = (__u64)result,
+               },
+       };
+
+       return ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_PASID_CHECK_DOMAIN), 
&test_pasid_check);
+}
-- 
2.34.1

Reply via email to