We can verify that topology is consistent with previous getparam like EU_TOTAL/SLICE_MASK/SUBSLICE_MASK. We also verify that CS timestamp frequency is always filled. Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx> --- tests/Makefile.sources | 1 + tests/intel_device_info.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 3 files changed, 326 insertions(+) create mode 100644 tests/intel_device_info.c diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 2313c12b..c7538cb6 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -168,6 +168,7 @@ TESTS_progs = \ gen3_render_tiledy_blits \ gen7_forcewake_mt \ gvt_basic \ + intel_device_info \ kms_3d \ kms_addfb_basic \ kms_atomic \ diff --git a/tests/intel_device_info.c b/tests/intel_device_info.c new file mode 100644 index 00000000..31e26cee --- /dev/null +++ b/tests/intel_device_info.c @@ -0,0 +1,324 @@ +/* + * 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 <stdbool.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> + +#include "igt.h" + +IGT_TEST_DESCRIPTION("Test device information retrieving through i915_getparam."); + +static int drm_fd; +static int devid; + +#ifndef I915_PARAM_SLICE_MASK +#define I915_PARAM_SLICE_MASK 46 +#endif + +#ifndef I915_PARAM_SUBSLICE_MASK +#define I915_PARAM_SUBSLICE_MASK 47 +#endif + +#ifndef I915_PARAM_CS_TIMESTAMP_FREQUENCY +#define I915_PARAM_CS_TIMESTAMP_FREQUENCY 50 +#endif + +#ifndef I915_PARAM_EU_TOPOLOGY +#define I915_PARAM_EU_TOPOLOGY 51 +/* List of active slices, subslices & execution units. Starting with CNL we + * can have asynmetric slices (for example 3 subslices in slice0 and 2 + * subslices in slice1+). This means we cannot rely on PARAM_SUBSLICE_MASK + * anymore. + * + * When using this parameter, getparam value should point to a structure of + * type drm_i915_eus_enabled_t. Call this once with n_slices, + * n_subslices_per_slice, & n_eus_per_subslice set to 0 and the kernel will + * fill out only those fields. You can then allocate the + * drm_i915_eu_topology_t properly to have enough space to store the full + * topology. + */ +#define I915_PARAM_EU_TOPOLOGY 51 +typedef struct drm_i915_eu_topology { + uint32_t n_slices; + uint32_t n_subslices_per_slice; + uint32_t n_eus_per_subslice; + + /* We define the following : + * + * slice_mask_size = ALIGN(n_slices, 8) / 8 + * subslices_mask_offset = slice_mask_size + * sublisces_mask_stride = ALIGN(n_subslices_per_slice, 8) / 8 + * subslices_mask_size = n_slices * sublisces_mask_stride + * eu_mask_offset = slice_mask_size + subslices_mask_size + * eu_subslice_stride = ALIGN(n_eus_per_subslice, 8) / 8 + * eu_slice_stride = n_subslices_per_slice * eu_subslice_stride + * eu_mask_size = n_slices * eu_slice_stride + * data_size = slice_mask_size + subslices_mask_size + eu_mask_size + * + * When called with n_slices, n_subslices_per_slice & + * n_eus_per_subslice filled out with the kernel values, the length of + * data should be data_size. + * + * The kernel will write the following into data : + * + * data[0 .. slice_mask_size - 1] : + * + * Where each bit represent slices available. + * + * data[slice_mask_offset .. slice_mask_offset + subslices_mask_size - 1] : + * + * Where each bit represent the subslices available for each + * slice. Formula to tell if sliceX-subsliceY is enabled : + * + * ((data[slice_mask_offset + X * sublisces_mask_stride + Y / 8] >> (Y % 8)) & 1) + * + * data[eu_mask_offset .. eu_mask_offset + eu_mask_size - 1] : + * + * Where each bit reports the status of one execution unit. User + * should use eu_slice_stride & eu_subslice_stride to through the + * different subslices. Formula to tell if sliceX-subsliceY-euZ + * is enabled : + * + * ((data[eu_mask_offset + X * eu_slice_stride + Y * eu_subslice_stride + Z / 8] >> (Z % 8)) & 1) + */ + uint8_t data[]; +} drm_i915_eu_topology_t; +#endif /* I915_PARAM_EU_TOPOLOGY */ + +static bool +topology_supported(void) +{ + drm_i915_eu_topology_t topology; + drm_i915_getparam_t gp; + + memset(&topology, 0, sizeof(topology)); + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) &topology; + + return ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0; +} + +static void +test_topology_pre_gen8(void) +{ + drm_i915_eu_topology_t topology; + drm_i915_getparam_t gp; + + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) &topology; + do_ioctl_err(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp, ENODEV); +} + +static void +test_topology_invalid_params(void) +{ + drm_i915_eu_topology_t topology; + drm_i915_getparam_t gp; + + memset(&topology, 0, sizeof(topology)); + + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) &topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology.n_slices++; + + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) &topology; + do_ioctl_err(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp, EINVAL); +} + +static void +test_topology_coherent_slice_mask(void) +{ + drm_i915_eu_topology_t topology; + drm_i915_getparam_t gp; + int slice_mask, subslice_mask; + + gp.param = I915_PARAM_SLICE_MASK; + gp.value = &slice_mask; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + gp.param = I915_PARAM_SUBSLICE_MASK; + gp.value = &subslice_mask; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + memset(&topology, 0, sizeof(topology)); + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) &topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + igt_debug("slice_mask=0x%x subslice_mask=0x%x n_slices=%u n_subslices_per_slice=%u\n", + slice_mask, subslice_mask, topology.n_slices, topology.n_subslices_per_slice); + + igt_assert(__builtin_popcount(slice_mask) <= topology.n_slices); + igt_assert(__builtin_popcount(subslice_mask) <= topology.n_subslices_per_slice); +} + +static void +test_topology_matches_eu_total(void) +{ + drm_i915_eu_topology_t *topology = calloc(1, sizeof(*topology)); + drm_i915_getparam_t gp; + int i, n_eus, n_eus_topology, s; + int slice_mask_size, subslices_mask_offset, sublisces_mask_stride, + subslices_mask_size, eu_mask_offset, eu_subslice_stride, + eu_slice_stride, eu_mask_size, data_size; + + gp.param = I915_PARAM_EU_TOTAL; + gp.value = &n_eus; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + igt_debug("n_eus=%i\n", n_eus); + + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + igt_debug("topology.n_slices=%i\n", topology->n_slices); + igt_debug("topology.n_subslices_per_slice=%i\n", topology->n_subslices_per_slice); + igt_debug("topology.n_eus_per_subslice=%i\n", topology->n_eus_per_subslice); + + slice_mask_size = ALIGN(topology->n_slices, 8) / 8; + subslices_mask_offset = slice_mask_size; + sublisces_mask_stride = ALIGN(topology->n_subslices_per_slice, 8) / 8; + subslices_mask_size = topology->n_slices * sublisces_mask_stride; + eu_mask_offset = slice_mask_size + subslices_mask_size; + eu_subslice_stride = ALIGN(topology->n_eus_per_subslice, 8) / 8; + eu_slice_stride = topology->n_subslices_per_slice * eu_subslice_stride; + eu_mask_size = topology->n_slices * eu_slice_stride; + data_size = slice_mask_size + subslices_mask_size + eu_mask_size; + + topology = realloc(topology, sizeof(*topology) + data_size); + memset(topology->data, 0, data_size); + + gp.param = I915_PARAM_EU_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + igt_debug("data:"); + for (i = 0; i < data_size; i++) + igt_debug(" 0x%hhx", topology->data[i]); + igt_debug("\n"); + + n_eus_topology = 0; + for (i = eu_mask_offset; i < data_size; i++) + n_eus_topology += __builtin_popcount(topology->data[i]); + + igt_debug("slice_mask:"); + for (i = 0; i < slice_mask_size; i++) + igt_debug(" 0x%hhx", topology->data[i]); + igt_debug("\n"); + + for (s = 0; s < topology->n_slices; s++) { + int ss; + + igt_debug("slice%i:\n", s); + igt_debug("\tsubslice_mask: 0x%hhx (%i)\n", + topology->data[subslices_mask_offset + s], + __builtin_popcount(topology->data[s])); + + for (ss = 0; ss < topology->n_subslices_per_slice; ss++) { + int eu, n_subslice_eus = 0; + + igt_debug("\tsubslice: %i\n", ss); + + igt_debug("\t\teu_mask:"); + for (eu = 0; eu < ALIGN(topology->n_eus_per_subslice, 8) / 8; eu++) { + uint8_t val = + topology->data[eu_mask_offset + + s * eu_slice_stride + + ss * eu_subslice_stride + eu]; + igt_debug(" 0x%hhx", val); + n_subslice_eus += __builtin_popcount(val); + } + igt_debug(" (%i)\n", n_subslice_eus); + } + } + + igt_assert(n_eus_topology == n_eus); +} + +static void +test_cs_timestamp_frequency(void) +{ + drm_i915_getparam_t gp; + int frequency, ret; + + gp.param = I915_PARAM_CS_TIMESTAMP_FREQUENCY; + gp.value = &frequency; + + /* Not supported? */ + ret = ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + igt_skip_on(ret != 0); + + igt_debug("cs_timestamp_frequency=%i\n", frequency); + + /* This should be available on all platforms. */ + igt_assert_neq(frequency, 0); +} + +igt_main +{ + igt_skip_on_simulation(); + igt_fixture { + drm_fd = drm_open_driver_render(DRIVER_INTEL); + devid = intel_get_drm_devid(drm_fd); + } + + igt_subtest("topology-pre-gen8") { + igt_require(intel_gen(devid) < 8); + test_topology_pre_gen8(); + } + + igt_subtest("topology-invalid-params") { + igt_require(AT_LEAST_GEN(devid, 8)); + igt_require(topology_supported()); + test_topology_invalid_params(); + } + + igt_subtest("topology-coherent-slice-mask") { + igt_require(AT_LEAST_GEN(devid, 8)); + igt_require(topology_supported()); + test_topology_coherent_slice_mask(); + } + + igt_subtest("topology-matches-eu-total") { + igt_require(AT_LEAST_GEN(devid, 8)); + igt_require(topology_supported()); + test_topology_matches_eu_total(); + } + + igt_subtest("cs-timestamp-frequency") { + test_cs_timestamp_frequency(); + } + + igt_exit(); +} diff --git a/tests/meson.build b/tests/meson.build index c3d5372f..54592339 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -20,6 +20,7 @@ test_progs = [ 'drv_module_reload', 'drv_selftest', 'drv_suspend', + 'intel_device_info', 'gem_bad_reloc', 'gem_basic', 'gem_busy', -- 2.15.0.rc2 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx