diff options
Diffstat (limited to 'lib/drmtest.c')
-rw-r--r-- | lib/drmtest.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/lib/drmtest.c b/lib/drmtest.c new file mode 100644 index 0000000..ee5c123 --- /dev/null +++ b/lib/drmtest.c @@ -0,0 +1,378 @@ +/* + * Copyright © 2007, 2011, 2013 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. + * + * Authors: + * Eric Anholt <eric@anholt.net> + * Daniel Vetter <daniel.vetter@ffwll.ch> + * + */ + +#ifndef ANDROID +#define _GNU_SOURCE +#else +#include <libgen.h> +#endif +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <string.h> +#include <sys/mman.h> +#include <signal.h> +#include <pciaccess.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/utsname.h> +#include <termios.h> + +#include "drmtest.h" +#include "i915_drm.h" +#include "intel_chipset.h" +#include "intel_io.h" +#include "igt_gt.h" +#include "igt_debugfs.h" +#include "version.h" +#include "config.h" +#include "intel_reg.h" +#include "ioctl_wrappers.h" + +/** + * SECTION:drmtest + * @short_description: Base library for drm tests and tools + * @title: drmtest + * @include: drmtest.h + * + * This library contains the basic support for writing tests, with the most + * important part being the helper function to open drm device nodes. + * + * But there's also a bit of other assorted stuff here. + * + * Note that this library's header pulls in the [i-g-t core](intel-gpu-tools-i-g-t-core.html) + * and [batchbuffer](intel-gpu-tools-intel-batchbuffer.html) libraries as dependencies. + */ + +uint16_t __drm_device_id; + +static int is_i915_device(int fd) +{ + drm_version_t version; + char name[5] = ""; + + memset(&version, 0, sizeof(version)); + version.name_len = 4; + version.name = name; + + if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) + return 0; + + return strcmp("i915", name) == 0; +} + +static int +is_intel(int fd) +{ + struct drm_i915_getparam gp; + int devid = 0; + + memset(&gp, 0, sizeof(gp)); + gp.param = I915_PARAM_CHIPSET_ID; + gp.value = &devid; + + if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp, sizeof(gp))) + return 0; + + if (!IS_INTEL(devid)) + return 0; + + __drm_device_id = devid; + return 1; +} + +static void check_stop_rings(void) +{ + enum stop_ring_flags flags; + flags = igt_get_stop_rings(); + igt_warn_on_f(flags != 0, + "i915_ring_stop flags on exit 0x%x, can't quiescent gpu cleanly\n", + flags); + + if (flags) + igt_set_stop_rings(STOP_RING_NONE); +} + +#define LOCAL_I915_EXEC_VEBOX (4 << 0) +/** + * gem_quiescent_gpu: + * @fd: open i915 drm file descriptor + * + * Ensure the gpu is idle by launching a nop execbuf and stalling for it. This + * is automatically run when opening a drm device node and is also installed as + * an exit handler to have the best assurance that the test is run in a pristine + * and controlled environment. + * + * This function simply allows tests to make additional calls in-between, if so + * desired. + */ +void gem_quiescent_gpu(int fd) +{ + uint32_t batch[2] = {MI_BATCH_BUFFER_END, 0}; + uint32_t handle; + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 gem_exec[1]; + + check_stop_rings(); + + handle = gem_create(fd, 4096); + gem_write(fd, handle, 0, batch, sizeof(batch)); + + gem_exec[0].handle = handle; + gem_exec[0].relocation_count = 0; + gem_exec[0].relocs_ptr = 0; + gem_exec[0].alignment = 0; + gem_exec[0].offset = 0; + gem_exec[0].flags = 0; + gem_exec[0].rsvd1 = 0; + gem_exec[0].rsvd2 = 0; + + execbuf.buffers_ptr = (uintptr_t)gem_exec; + execbuf.buffer_count = 1; + execbuf.batch_start_offset = 0; + execbuf.batch_len = 8; + execbuf.cliprects_ptr = 0; + execbuf.num_cliprects = 0; + execbuf.DR1 = 0; + execbuf.DR4 = 0; + execbuf.flags = 0; + i915_execbuffer2_set_context_id(execbuf, 0); + execbuf.rsvd2 = 0; + + do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + + if (gem_has_blt(fd)) { + execbuf.flags = I915_EXEC_BLT; + do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + } + + if (gem_has_bsd(fd)) { + execbuf.flags = I915_EXEC_BSD; + do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + } + + if (gem_has_vebox(fd)) { + execbuf.flags = LOCAL_I915_EXEC_VEBOX; + do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); + } + + gem_sync(fd, handle); + igt_drop_caches_set(DROP_RETIRE); + gem_close(fd, handle); +} + +/** + * drm_get_card: + * + * Get an i915 drm card index number for use in /dev or /sys. The minor index of + * the legacy node is returned, not of the control or render node. + * + * Returns: + * The i915 drm index or -1 on error + */ +int drm_get_card(void) +{ + char *name; + int i, fd; + + for (i = 0; i < 16; i++) { + int ret; + + ret = asprintf(&name, "/dev/dri/card%u", i); + igt_assert(ret != -1); + + fd = open(name, O_RDWR); + free(name); + + if (fd == -1) + continue; + + if (!is_i915_device(fd) || !is_intel(fd)) { + close(fd); + continue; + } + + close(fd); + return i; + } + + igt_skip("No intel gpu found\n"); + + return -1; +} + +/** Open the first DRM device we can find, searching up to 16 device nodes */ +int __drm_open_any(void) +{ + for (int i = 0; i < 16; i++) { + char name[80]; + int fd; + + sprintf(name, "/dev/dri/card%u", i); + fd = open(name, O_RDWR); + if (fd == -1) + continue; + + if (is_i915_device(fd) && is_intel(fd)) + return fd; + + close(fd); + } + + igt_skip("No intel gpu found\n"); + return -1; +} + +static int __drm_open_any_render(void) +{ + char *name; + int i, fd; + + for (i = 128; i < (128 + 16); i++) { + int ret; + + ret = asprintf(&name, "/dev/dri/renderD%u", i); + igt_assert(ret != -1); + + fd = open(name, O_RDWR); + free(name); + + if (fd == -1) + continue; + + if (!is_i915_device(fd) || !is_intel(fd)) { + close(fd); + fd = -1; + continue; + } + + return fd; + } + + return fd; +} + +static int at_exit_drm_fd = -1; +static int at_exit_drm_render_fd = -1; + +static void quiescent_gpu_at_exit(int sig) +{ + if (at_exit_drm_fd < 0) + return; + + check_stop_rings(); + gem_quiescent_gpu(at_exit_drm_fd); + close(at_exit_drm_fd); + at_exit_drm_fd = -1; +} + +static void quiescent_gpu_at_exit_render(int sig) +{ + if (at_exit_drm_render_fd < 0) + return; + + check_stop_rings(); + gem_quiescent_gpu(at_exit_drm_render_fd); + close(at_exit_drm_render_fd); + at_exit_drm_render_fd = -1; +} + +/** + * drm_open_any: + * + * Open an i915 drm legacy device node. This function always returns a valid + * file descriptor. + * + * Returns: a i915 drm file descriptor + */ +int drm_open_any(void) +{ + static int open_count; + int fd = __drm_open_any(); + + igt_require(fd >= 0); + + if (__sync_fetch_and_add(&open_count, 1)) + return fd; + + gem_quiescent_gpu(fd); + at_exit_drm_fd = __drm_open_any(); + igt_install_exit_handler(quiescent_gpu_at_exit); + + return fd; +} + +/** + * drm_open_any_master: + * + * Open an i915 drm legacy device node and ensure that it is drm master. + * + * Returns: + * The i915 drm file descriptor or -1 on error + */ +int drm_open_any_master(void) +{ + int fd = drm_open_any(); + + igt_require(fd >= 0); + igt_require_f(drmSetMaster(fd) == 0, "Can't become DRM master, " + "please check if no other DRM client is running.\n"); + + return fd; +} + +/** + * drm_open_any_render: + * + * Open an i915 drm render device node. + * + * Returns: + * The i915 drm file descriptor or -1 on error + */ +int drm_open_any_render(void) +{ + static int open_count; + int fd = __drm_open_any_render(); + + /* no render nodes, fallback to drm_open_any() */ + if (fd == -1) + return drm_open_any(); + + if (__sync_fetch_and_add(&open_count, 1)) + return fd; + + at_exit_drm_render_fd = __drm_open_any(); + gem_quiescent_gpu(fd); + igt_install_exit_handler(quiescent_gpu_at_exit_render); + + return fd; +} |