@@ -44,6 +44,7 @@ TESTS_progs = \
gem_linear_blits \
gem_vmap_blits \
gem_threaded_access_tiled \
+ gem_seqno_wrap \
gem_tiled_blits \
gem_tiled_fence_blits \
gem_largeobject \
new file mode 100644
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012 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:
+ * Mika Kuoppala <mika.kuoppala@intel.com>
+ */
+
+/*
+ * This test runs gem_stress test multiple times while setting the
+ * next_seqno close to wrapping point. Driver can only handle INT_MAX-1
+ * increments to seqno.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <limits.h>
+
+#include "drmtest.h"
+#include "i915_drm.h"
+#include "intel_bufmgr.h"
+
+#define NUM_WRAPS 3
+
+static int verbose = 0;
+
+static int run_gem_stress(int times)
+{
+ int pid;
+ int r = -1;
+ int status = 0;
+
+ pid = fork();
+ if (pid == 0) {
+ char *argv[3];
+ char cmd[32];
+ char opt1[32];
+ char path[PATH_MAX];
+ char full_path[PATH_MAX];
+
+ strncpy(cmd, "gem_stress", sizeof(cmd));
+ argv[0] = cmd;
+ argv[1] = opt1;
+ argv[2] = NULL;
+
+ assert(snprintf(opt1, sizeof(opt1), "-o%d", times) > 0);
+
+ if (getcwd(path, PATH_MAX) == NULL)
+ perror("getcwd");
+
+ assert(snprintf(full_path, PATH_MAX, "%s/%s", path, argv[0]) > 0);
+
+ if (!verbose) {
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ }
+
+ r = execv(full_path, argv);
+ if (r == -1)
+ perror("execv failed");
+ } else {
+ int waitcount = 20;
+
+ while(waitcount-- > 0) {
+ r = waitpid(pid, &status, WNOHANG);
+ if (r == pid) {
+ if(WIFEXITED(status)) {
+ if (WEXITSTATUS(status))
+ fprintf(stderr, "child returned with %d\n", WEXITSTATUS(status));
+ return WEXITSTATUS(status);
+ }
+ } else if (r != 0) {
+ perror("waitpid");
+ return -errno;
+ }
+
+ sleep(1);
+ }
+
+ kill(pid, SIGKILL);
+ return -ETIMEDOUT;
+ }
+
+ return r;
+}
+
+static const char *debug_fs_entry = "/sys/kernel/debug/dri/0/i915_next_seqno";
+
+static int read_seqno(uint32_t *seqno)
+{
+ int fh;
+ char buf[32];
+ int r;
+ char *p;
+ unsigned long int tmp;
+
+ fh = open(debug_fs_entry, O_RDWR);
+ if (fh == -1) {
+ perror("open");
+ fprintf(stderr, "no %s found, too old kernel?\n", debug_fs_entry);
+ return -errno;
+ }
+
+ r = read(fh, buf, sizeof(buf) - 1);
+ if (r < 0) {
+ perror("read");
+ close(fh);
+ return -errno;
+ }
+
+ close(fh);
+ buf[r] = 0;
+
+ p = strstr(buf, "0x");
+ if (!p)
+ p = buf;
+
+ tmp = strtoul(p, NULL, 0);
+ if (tmp == ULONG_MAX) {
+ perror("strtoul");
+ return -errno;
+ }
+
+ *seqno = tmp;
+
+ return 0;
+}
+
+static int write_seqno(uint32_t seqno)
+{
+ int fh;
+ char buf[32];
+ int r;
+
+ fh = open(debug_fs_entry, O_RDWR);
+ if (fh == -1) {
+ perror("open");
+ return -errno;
+ }
+
+ assert(snprintf(buf, sizeof(buf), "0x%x", seqno) > 0);
+
+ r = write(fh, buf, strnlen(buf, sizeof(buf)));
+ if (r < 0)
+ return r;
+
+ assert(r == strnlen(buf, sizeof(buf)));
+
+ close(fh);
+
+ return 0;
+}
+
+static int run_once(void)
+{
+ int r;
+ uint32_t seqno = 0;
+ uint32_t seqno_after = 0;
+ uint32_t incr;
+
+ r = read_seqno(&seqno);
+ assert(r == 0);
+
+ incr = (UINT32_MAX >> 1) - 0x1000;
+ if (seqno + incr < seqno)
+ seqno = UINT32_MAX - 0x1000;
+ else
+ seqno += incr;
+
+ seqno++;
+
+ r = write_seqno(seqno);
+ if (r < 0) {
+ fprintf(stderr, "write_seqno returned %d\n", r);
+ return r;
+ }
+
+ // XXX we lose drm auth/master if we are too hasty to reopen /dev/dri wtf?!
+ // usleep(200*1000);
+ r = run_gem_stress(1);
+ if (r != 0) {
+ fprintf(stderr, "run_gem_stress returned %d\n", r);
+ return -1;
+ }
+
+ r = read_seqno(&seqno_after);
+ assert(r == 0);
+
+ if (seqno > seqno_after)
+ return 1;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+
+ int wraps = 0;
+ int wr;
+ int r;
+
+ if (argc > 1)
+ wr = atoi(argv[1]);
+ else
+ wr = NUM_WRAPS;
+
+ while(wraps < wr) {
+ r = run_once();
+ if (r < 0) {
+ if (verbose) fprintf(stderr, "run once returned %d\n", r);
+ return r;
+ }
+
+ wraps += r;
+ }
+
+ if (wraps == wr) {
+ if (verbose)
+ printf("done %d wraps successfully\n", wraps);
+
+ return 0;
+ }
+
+ return -1;
+}
This test uses debugfs entry to set next_seqno close to a wrapping point and then creates a load with gem_stress to induce the wrap. Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com> --- tests/Makefile.am | 1 + tests/gem_seqno_wrap.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) create mode 100644 tests/gem_seqno_wrap.c