We can verify that topology is consistent with previous getparam like EU_TOTAL. We also verify that CS timestamp frequency is always filled. v2: Use v2 of kernel uapi (Lionel) Fix Gen < 8 issue Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx> --- tests/Makefile.sources | 1 + tests/intel_device_info.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 3 files changed, 355 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..f5032f2c --- /dev/null +++ b/tests/intel_device_info.c @@ -0,0 +1,353 @@ +/* + * 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_TOPOLOGY +/* Query various aspects of the topology of the GPU. Below is a list of the + * currently supported queries. The motivation of this more detailed query + * mechanism is to expose asynmetric properties of the GPU. Starting with CNL, + * slices might have different sizes (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_topology_t. Call this once with query set to the relevant + * information to be queried and data_size set to 0. The kernel will then set + * params and data_size to the expected length of data[]. The should make sure + * memory is allocated to the right length before making a second getparam + * with data_size already set. The kernel will then populate data[]. The + * meaning of params[] elements is described for each query below. + */ +#define I915_PARAM_TOPOLOGY 51 +typedef struct drm_i915_topology { + __u32 query; + __u32 data_size; + + /* Query the availability of slices : + * + * params[0] : the maximum number of slices + * + * Each bit in data indicates whether a slice is available (1) or + * fused off (0). Formula to tell if slice X is available : + * + * (data[X / 8] >> (X % 8)) & 1 + */ +#define I915_PARAM_TOPOLOGY_QUERY_SLICE_MASK 0 + /* Query the availability of subslices : + * + * params[0] : slice stride + * + * Each bit in data indicates whether a subslice is available (1) or + * fused off (0). Formula to tell if slice X subslice Y is available : + * + * (data[(X * params[0]) + Y / 8] >> (Y % 8)) & 1 + */ +#define I915_PARAM_TOPOLOGY_QUERY_SUBSLICE_MASK 1 + /* Query the availability of EUs : + * + * params[0] : slice stride + * params[1] : subslice stride + * + * Each bit in data indicates whether a slice is available (1) or + * fused off (0). Formula to tell if slice X subslice Y eu Z is + * available : + * + * (data[X * params[0] + Y * params[1] + Z / 8] >> (Z % 8)) & 1 + */ +#define I915_PARAM_TOPOLOGY_QUERY_EU_MASK 2 + + __u32 params[10]; + + __u8 data[]; +} drm_i915_topology_t; +#endif /* I915_PARAM_TOPOLOGY */ + +static bool +topology_supported(void) +{ + drm_i915_topology_t topology; + drm_i915_getparam_t gp; + + memset(&topology, 0, sizeof(topology)); + topology.query = I915_PARAM_TOPOLOGY_QUERY_SLICE_MASK; + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) &topology; + + return ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0; +} + +static void +test_topology_pre_gen8(void) +{ + drm_i915_topology_t topology; + drm_i915_getparam_t gp; + + memset(&topology, 0, sizeof(topology)); + topology.query = I915_PARAM_TOPOLOGY_QUERY_SLICE_MASK; + + gp.param = I915_PARAM_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_topology_t topology; + drm_i915_getparam_t gp; + + /* Invalid query */ + memset(&topology, 0, sizeof(topology)); + topology.query = 0xffffffff; + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) &topology; + do_ioctl_err(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp, EINVAL); + + /* Invalid data_size */ + memset(&topology, 0, sizeof(topology)); + topology.query = I915_PARAM_TOPOLOGY_QUERY_SLICE_MASK; + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) &topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology.data_size += 1; + + gp.param = I915_PARAM_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_topology_t *topology; + drm_i915_getparam_t gp; + int slice_mask, subslice_mask; + int i, topology_slices, topology_subslices; + + 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); + + igt_debug("slice_mask=0x%x subslice_mask=0x%x\n", slice_mask, subslice_mask); + + /* Slices */ + topology = malloc(sizeof(*topology)); + memset(topology, 0, sizeof(*topology)); + topology->query = I915_PARAM_TOPOLOGY_QUERY_SLICE_MASK; + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology = realloc(topology, sizeof(*topology) + topology->data_size); + memset(topology->data, 0, topology->data_size); + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology_slices = 0; + for (i = 0; i < topology->data_size; i++) + topology_slices += __builtin_popcount(topology->data[i]); + + /* These 2 should always match. */ + igt_assert(__builtin_popcount(slice_mask) == topology_slices); + + free(topology); + + /* Subslices */ + topology = malloc(sizeof(*topology)); + memset(topology, 0, sizeof(*topology)); + topology->query = I915_PARAM_TOPOLOGY_QUERY_SUBSLICE_MASK; + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology = realloc(topology, sizeof(*topology) + topology->data_size); + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology_subslices = 0; + for (i = 0; i < topology->params[0]; i++) + topology_subslices += __builtin_popcount(topology->data[i]); + + /* I915_PARAM_SUBSLICE_MASK returns the value for slice0, we + * should match the values for the first slice of the + * topology. + */ + igt_assert(__builtin_popcount(subslice_mask) == topology_subslices); + + free(topology); +} + +static void +test_topology_matches_eu_total(void) +{ + drm_i915_topology_t *topology; + drm_i915_getparam_t gp; + int n_eus, n_eus_topology, s; + + 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); + + topology = malloc(sizeof(*topology)); + memset(topology, 0, sizeof(*topology)); + topology->query = I915_PARAM_TOPOLOGY_QUERY_EU_MASK; + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + topology = realloc(topology, sizeof(*topology) + topology->data_size); + memset(topology->data, 0, topology->data_size); + + gp.param = I915_PARAM_TOPOLOGY; + gp.value = (int *) topology; + do_ioctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp); + + n_eus_topology = 0; + for (s = 0; s < topology->data_size / topology->params[0]; s++) { + int ss; + + igt_debug("slice%i:\n", s); + + for (ss = 0; ss < topology->params[0] / topology->params[1]; ss++) { + int eu, n_subslice_eus = 0; + + igt_debug("\tsubslice: %i\n", ss); + + igt_debug("\t\teu_mask:"); + for (eu = 0; eu < topology->params[1]; eu++) { + uint8_t val = topology->data[s * topology->params[0] + + ss * topology->params[1] + eu]; + igt_debug(" 0x%hhx", 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); +} + +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); + igt_require(topology_supported()); + 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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx