[igt-dev] [PATCH i-g-t 2/2] tests: add i915 query tests
Lionel Landwerlin
lionel.g.landwerlin at intel.com
Thu Feb 15 12:03:08 UTC 2018
v2: Complete invalid cases (Chris)
Some styling (to_user_pointer, etc...) (Chris)
New error check, through item.length (Chris)
v3: Update for new uAPI iteration (Lionel)
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
---
tests/Makefile.sources | 1 +
tests/i915_query.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
3 files changed, 302 insertions(+)
create mode 100644 tests/i915_query.c
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 870c9093..d8e55e8b 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -166,6 +166,7 @@ TESTS_progs = \
gen3_render_tiledy_blits \
gen7_forcewake_mt \
gvt_basic \
+ i915_query \
kms_3d \
kms_addfb_basic \
kms_atomic \
diff --git a/tests/i915_query.c b/tests/i915_query.c
new file mode 100644
index 00000000..aba7b082
--- /dev/null
+++ b/tests/i915_query.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+
+#include <limits.h>
+
+IGT_TEST_DESCRIPTION("Testing the i915 query uAPI.");
+
+static int
+__i915_query(int fd, struct drm_i915_query *q)
+{
+ return igt_ioctl(fd, DRM_IOCTL_I915_QUERY, q);
+}
+
+static int
+__i915_query_item(int fd, struct drm_i915_query_item *items, uint32_t n_items)
+{
+ struct drm_i915_query q = {
+ .num_items = n_items,
+ .items_ptr = to_user_pointer(items),
+ };
+ return __i915_query(fd, &q);
+}
+
+#define i915_query_item(fd, items, n_items) do { \
+ igt_assert_eq(__i915_query_item(fd, items, n_items), 0); \
+ errno = 0; \
+ } while (0)
+#define i915_query_item_err(fd, items, n_items, err) do { \
+ igt_assert_eq(__i915_query_item(fd, items, n_items), -1); \
+ igt_assert_eq(errno, err); \
+ } while (0)
+
+static bool has_query_supports(int fd)
+{
+ struct drm_i915_query query = {};
+
+ return __i915_query(fd, &query) == 0;
+}
+
+static void test_query_garbage(int fd)
+{
+ struct drm_i915_query_item items[2];
+ struct drm_i915_query_item *items_ptr;
+ int i, len;
+
+ i915_query_item_err(fd, (void *) ULONG_MAX, 1, EFAULT);
+
+ i915_query_item_err(fd, (void *) 0, 1, EFAULT);
+
+ memset(items, 0, sizeof(items));
+ i915_query_item_err(fd, items, 1, EINVAL);
+
+ memset(items, 0, sizeof(items));
+ items[0].query_id = ULONG_MAX;
+ items[1].query_id = ULONG_MAX - 2;
+ i915_query_item(fd, items, 2);
+ igt_assert_eq(items[0].length, -EINVAL);
+ igt_assert_eq(items[1].length, -EINVAL);
+
+ memset(items, 0, sizeof(items));
+ items[0].query_id = DRM_I915_QUERY_TOPOLOGY_INFO;
+ items[1].query_id = DRM_I915_QUERY_TOPOLOGY_INFO;
+ items[1].length = sizeof(struct drm_i915_query_topology_info) - 1;
+ i915_query_item(fd, items, 2);
+ igt_assert_lte(0, items[0].length);
+ igt_assert_eq(items[1].length, -EINVAL);
+
+ items_ptr = mmap(0, 4096, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ items_ptr[0].query_id = DRM_I915_QUERY_TOPOLOGY_INFO;
+ i915_query_item(fd, items_ptr, 1);
+ igt_assert(items_ptr[0].length >= sizeof(struct drm_i915_query_topology_info));
+ munmap(items_ptr, 4096);
+ i915_query_item_err(fd, items_ptr, 1, EFAULT);
+
+ len = sizeof(struct drm_i915_query_item) * 10;
+ items_ptr = mmap(0, len, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ for (i = 0; i < 10; i++)
+ items_ptr[i].query_id = DRM_I915_QUERY_TOPOLOGY_INFO;
+ igt_assert_eq(__i915_query_item(fd, items_ptr,
+ INT_MAX / sizeof(struct drm_i915_query_item) + 1), -1);
+ igt_assert(errno == EFAULT || errno == EINVAL);
+ munmap(items_ptr, len);
+}
+
+static bool query_topology_supported(int fd)
+{
+ struct drm_i915_query_item item = {
+ .query_id = DRM_I915_QUERY_TOPOLOGY_INFO,
+ };
+
+ return __i915_query_item(fd, &item, 1) == 0 && item.length > 0;
+}
+
+static void test_query_topology_pre_gen8(int fd)
+{
+ struct drm_i915_query_item item = {
+ .query_id = DRM_I915_QUERY_TOPOLOGY_INFO,
+ };
+
+ i915_query_item(fd, &item, 1);
+ igt_assert_eq(item.length, -ENODEV);
+}
+
+#define DIV_ROUND_UP(val, div) (ALIGN(val, div) / div)
+
+static bool
+slice_available(const struct drm_i915_query_topology_info *topo_info,
+ int s)
+{
+ return (topo_info->data[s / 8] >> (s % 8)) & 1;
+}
+
+static bool
+subslice_available(const struct drm_i915_query_topology_info *topo_info,
+ int s, int ss)
+{
+ return (topo_info->data[topo_info->subslice_offset +
+ s * DIV_ROUND_UP(topo_info->max_subslices, 8) +
+ ss / 8] >> (ss % 8)) & 1;
+}
+
+static bool
+eu_available(const struct drm_i915_query_topology_info *topo_info,
+ int s, int ss, int eu)
+{
+ return (topo_info->data[topo_info->eu_offset +
+ s * topo_info->max_subslices * DIV_ROUND_UP(topo_info->max_eus_per_subslice, 8) +
+ ss * DIV_ROUND_UP(topo_info->max_eus_per_subslice, 8) +
+ eu / 8] >> (eu % 8)) & 1;
+}
+
+static void
+test_query_topology_coherent_slice_mask(int fd)
+{
+ struct drm_i915_query_item item;
+ struct drm_i915_query_topology_info *topo_info;
+ drm_i915_getparam_t gp;
+ int slice_mask, subslice_mask;
+ int s, topology_slices, topology_subslices_slice0;
+
+ gp.param = I915_PARAM_SLICE_MASK;
+ gp.value = &slice_mask;
+ do_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+
+ gp.param = I915_PARAM_SUBSLICE_MASK;
+ gp.value = &subslice_mask;
+ do_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+
+ /* Slices */
+ memset(&item, 0, sizeof(item));
+ item.query_id = DRM_I915_QUERY_TOPOLOGY_INFO;
+ i915_query_item(fd, &item, 1);
+ igt_assert(item.length > 0);
+
+ topo_info = (struct drm_i915_query_topology_info *) calloc(1, item.length);
+
+ item.data_ptr = to_user_pointer(topo_info);
+ i915_query_item(fd, &item, 1);
+ igt_assert(item.length > 0);
+
+ topology_slices = 0;
+ for (s = 0; s < topo_info->max_slices; s++) {
+ if (slice_available(topo_info, s))
+ topology_slices |= 1UL << s;
+ }
+
+ igt_debug("slice mask getparam=0x%x / query=0x%x\n",
+ slice_mask, topology_slices);
+
+ /* These 2 should always match. */
+ igt_assert(slice_mask == topology_slices);
+
+ topology_subslices_slice0 = 0;
+ for (s = 0; s < topo_info->max_subslices; s++) {
+ if (subslice_available(topo_info, 0, s))
+ topology_subslices_slice0 |= 1UL << s;
+ }
+
+ igt_debug("subslice mask getparam=0x%x / query=0x%x\n",
+ subslice_mask, topology_subslices_slice0);
+
+ /* I915_PARAM_SUBSLICE_MASK returns the value for slice0, we
+ * should match the values for the first slice of the
+ * topology.
+ */
+ igt_assert(subslice_mask == topology_subslices_slice0);
+
+ free(topo_info);
+}
+
+static void
+test_query_topology_matches_eu_total(int fd)
+{
+ struct drm_i915_query_item item;
+ struct drm_i915_query_topology_info *topo_info;
+ drm_i915_getparam_t gp;
+ int n_eus, n_eus_topology, s;
+
+ gp.param = I915_PARAM_EU_TOTAL;
+ gp.value = &n_eus;
+ do_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ igt_debug("n_eus=%i\n", n_eus);
+
+ memset(&item, 0, sizeof(item));
+ item.query_id = DRM_I915_QUERY_TOPOLOGY_INFO;
+ i915_query_item(fd, &item, 1);
+
+ topo_info = (struct drm_i915_query_topology_info *) calloc(1, item.length);
+
+ item.data_ptr = to_user_pointer(topo_info);
+ i915_query_item(fd, &item, 1);
+
+ igt_debug("max_slices=%u max_subslices=%u max_eus_per_subslice=%u\n",
+ topo_info->max_slices, topo_info->max_subslices,
+ topo_info->max_eus_per_subslice);
+
+ n_eus_topology = 0;
+ for (s = 0; s < topo_info->max_slices; s++) {
+ int ss;
+
+ igt_debug("slice%i:\n", s);
+
+ for (ss = 0; ss < topo_info->max_subslices; ss++) {
+ int eu, n_subslice_eus = 0;
+
+ igt_debug("\tsubslice: %i\n", ss);
+
+ igt_debug("\t\teu_mask: 0b");
+ for (eu = 0; eu < topo_info->max_eus_per_subslice; eu++) {
+ uint8_t val = eu_available(topo_info, s, ss,
+ topo_info->max_eus_per_subslice - 1 - eu);
+ igt_debug("%hhi", val);
+ n_subslice_eus += __builtin_popcount(val);
+ n_eus_topology += __builtin_popcount(val);
+ }
+ igt_debug(" (%i)\n", n_subslice_eus);
+ }
+ }
+
+ igt_assert(n_eus_topology == n_eus);
+}
+
+igt_main
+{
+ int fd = -1;
+ int devid;
+
+ igt_fixture {
+ fd = drm_open_driver(DRIVER_INTEL);
+ igt_require(has_query_supports(fd));
+ devid = intel_get_drm_devid(fd);
+ }
+
+ igt_subtest("query-garbage")
+ test_query_garbage(fd);
+
+ igt_subtest("query-topology-pre-gen8") {
+ igt_require(intel_gen(devid) < 8);
+ igt_require(query_topology_supported(fd));
+ test_query_topology_pre_gen8(fd);
+ }
+
+ igt_subtest("query-topology-coherent-slice-mask") {
+ igt_require(AT_LEAST_GEN(devid, 8));
+ igt_require(query_topology_supported(fd));
+ test_query_topology_coherent_slice_mask(fd);
+ }
+
+ igt_subtest("query-topology-matches-eu-total") {
+ igt_require(AT_LEAST_GEN(devid, 8));
+ igt_require(query_topology_supported(fd));
+ test_query_topology_matches_eu_total(fd);
+ }
+
+ igt_fixture {
+ close(fd);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 521a4c42..28058320 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -144,6 +144,7 @@ test_progs = [
'gen3_render_tiledy_blits',
'gen7_forcewake_mt',
'gvt_basic',
+ 'i915_query',
'kms_3d',
'kms_addfb_basic',
'kms_atomic',
--
2.16.1
More information about the igt-dev
mailing list