All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marius Vlad <marius.c.vlad@intel.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH i-g-t 1/4 v7] lib/igt_kmod: New library to support driver loading/unloading and additional helpers.
Date: Thu,  1 Dec 2016 14:23:55 +0200	[thread overview]
Message-ID: <20161201122358.1124-2-marius.c.vlad@intel.com> (raw)
In-Reply-To: <20161201122358.1124-1-marius.c.vlad@intel.com>

lib/igt_aux: Added igt_pkill and igt_lsof helper.
lib/igt_kmod: Added load/unload kmod helpers.

v7:
- document the case where leaving stray fd from drm_open_driver()
might fail reloading the driver.
- list also current opened files from /dev/dri in case we could not
unload the driver.
- convert igt_info to igt_warn (Chris Wilson)
- added KMOD_|PROCPS CFLAGS (Chris Wilson)

v6:
- include latest modifications from tests/drv_module_reload:
display all loaded modules and list information about opened
files by processes (Petri Latvala)

v5:
- added igt_i915_driver_{load/unload}.
- added kick_snd_hda_intel() to match current
tests/drv_module_reload_basic and integrated into
igt_i915_driver_load/unload.
- added gtk-doc section for lib/igt_kmod

v4:
- decided to split libkmod helpers into their own file as there's
another user lib/igt_gvt or tests/gvt_basic.
- fixed some gtk-doc documentation.

v3:
- return -errno (igt_pkill()) in case of failure (Cris Wilson)
- return bool for igt_kmod_is_loaded(), replaced strncasecmp with strncmp
(Chris Wilson)
- use igt_debug() instead of igt_info() for igt_kmod_load()/
igt_kmod_unload() and return -err directly from libkmod (Chris Wilson)

v2:
- Renamed libkmod helpers (Chris Wilson)
- Removed SIGTERM/SIGKILL case where we repeatedly tried to terminate the
process: just call kill(2) once (Chris Wilson)
- Removed redundant check in igt_kmod_unload(), igt_module_in_use() (Chris
Wilson)
- Pass flags to igt_kmod_unload() from the caller (Chris Wilson)
- Removed useless function igt_kill() which acts just as kill(2) (Chris
Wilson)

Signed-off-by: Marius Vlad <marius.c.vlad@intel.com>
---
 configure.ac                                       |   2 +
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.am                                    |   5 +-
 lib/Makefile.sources                               |   2 +
 lib/igt_aux.c                                      | 260 ++++++++++++++++
 lib/igt_aux.h                                      |   3 +
 lib/igt_gvt.c                                      |  43 +--
 lib/igt_kmod.c                                     | 328 +++++++++++++++++++++
 lib/igt_kmod.h                                     |  39 +++
 lib/igt_sysfs.c                                    | 106 +++++++
 lib/igt_sysfs.h                                    |   3 +
 11 files changed, 750 insertions(+), 42 deletions(-)
 create mode 100644 lib/igt_kmod.c
 create mode 100644 lib/igt_kmod.h

diff --git a/configure.ac b/configure.ac
index e181c83..cba312f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -121,6 +121,8 @@ AC_SUBST(ASSEMBLER_WARN_CFLAGS)
 
 PKG_CHECK_MODULES(DRM, [libdrm])
 PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10])
+PKG_CHECK_MODULES(KMOD, [libkmod])
+PKG_CHECK_MODULES(PROCPS, [libprocps])
 
 case "$target_cpu" in
 	x86*|i?86)
diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..39061a8 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -22,6 +22,7 @@
     <xi:include href="xml/igt_sysfs.xml"/>
     <xi:include href="xml/igt_draw.xml"/>
     <xi:include href="xml/igt_kms.xml"/>
+    <xi:include href="xml/igt_kmod.xml"/>
     <xi:include href="xml/igt_fb.xml"/>
     <xi:include href="xml/igt_aux.xml"/>
     <xi:include href="xml/igt_gt.xml"/>
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 4c0893d..5eec207 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -23,7 +23,8 @@ if !HAVE_LIBDRM_INTEL
 endif
 
 AM_CPPFLAGS = -I$(top_srcdir)
-AM_CFLAGS = $(CWARNFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(LIBUNWIND_CFLAGS) $(DEBUG_CFLAGS) \
+AM_CFLAGS = $(CWARNFLAGS) $(DRM_CFLAGS) $(PCIACCESS_CFLAGS) $(LIBUNWIND_CFLAGS) \
+	    $(DEBUG_CFLAGS) $(KMOD_CFLAGS) $(PROCPS_CFLAGS) \
 	    -DIGT_SRCDIR=\""$(abs_top_srcdir)/tests"\" \
 	    -DIGT_DATADIR=\""$(pkgdatadir)"\" \
 	    -DIGT_LOG_DOMAIN=\""$(subst _,-,$*)"\" \
@@ -34,6 +35,8 @@ AM_CFLAGS += $(CAIRO_CFLAGS)
 libintel_tools_la_LIBADD = \
 	$(DRM_LIBS) \
 	$(PCIACCESS_LIBS) \
+	$(PROCPS_LIBS) \
+	$(KMOD_LIBS) \
 	$(CAIRO_LIBS) \
 	$(LIBUDEV_LIBS) \
 	$(LIBUNWIND_LIBS) \
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..2205c86 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -77,6 +77,8 @@ lib_source_list =	 	\
 	igt_pm.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
+	igt_kmod.c		\
+	igt_kmod.h		\
 	$(NULL)
 
 .PHONY: version.h.tmp
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 421f6d4..a4ac44b 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -51,6 +51,8 @@
 #include <termios.h>
 #include <assert.h>
 
+#include <proc/readproc.h>
+
 #include "drmtest.h"
 #include "i915_drm.h"
 #include "intel_chipset.h"
@@ -65,6 +67,10 @@
 #include "igt_stats.h"
 #include "igt_sysfs.h"
 
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>   /* for dirname() */
+#endif
+
 /**
  * SECTION:igt_aux
  * @short_description: Auxiliary libraries and support functions
@@ -1193,6 +1199,260 @@ void igt_set_module_param_int(const char *name, int val)
 	igt_set_module_param(name, str);
 }
 
+/**
+ * igt_pkill:
+ * @sig: Signal to send
+ * @comm: Name of process in the form found in /proc/pid/comm (limited to 15
+ * chars)
+ *
+ * Returns: 0 in case the process is not found running or the signal has been
+ * sent successfully or -errno otherwise.
+ *
+ * This function sends the signal @sig for a process found in process table
+ * with name @comm.
+ */
+int
+igt_pkill(int sig, const char *comm)
+{
+	PROCTAB *proc;
+	proc_t *proc_info;
+	int err = 0;
+
+	proc = openproc(PROC_FILLCOM | PROC_FILLSTAT | PROC_FILLARG);
+	igt_assert(proc != NULL);
+
+	while ((proc_info = readproc(proc, NULL))) {
+		if (!strncasecmp(proc_info->cmd, comm, sizeof(proc_info->cmd))) {
+
+			if (kill(proc_info->tid, sig) < 0)
+				err = -errno;
+
+			freeproc(proc_info);
+			break;
+		}
+		freeproc(proc_info);
+	}
+
+	closeproc(proc);
+	return err;
+}
+
+struct pinfo {
+	pid_t pid;
+	const char *comm;
+	const char *fn;
+};
+
+static void
+__igt_show_stat(struct pinfo *info)
+{
+	const char *comm, *fn;
+	const char *type = "";
+	struct stat st;
+
+	pid_t pid = info->pid;
+	igt_assert((comm = info->comm));
+	igt_assert((fn = info->fn));
+
+	if (lstat(fn, &st) == -1)
+		return;
+
+	igt_info("%20.20s ", comm);
+	igt_info("%10d ", pid);
+
+	switch (st.st_mode & S_IFMT) {
+	case S_IFBLK:
+		type = "block";
+		break;
+	case S_IFCHR:
+		type = "character";
+		break;
+	case S_IFDIR:
+		type = "directory";
+		break;
+	case S_IFIFO:
+		type = "FIFO/pipe";
+		break;
+	case S_IFLNK:
+		type = "symlink";
+		break;
+	case S_IFREG:
+		type = "file";
+		break;
+	case S_IFSOCK:
+		type = "socket";
+		break;
+	default:
+		type = "unknown?";
+		break;
+	}
+	igt_info("%20.20s ", type);
+
+	igt_info("%10ld%10ld ", (long) st.st_uid, (long) st.st_gid);
+
+	igt_info("%15lld bytes ", (long long) st.st_size);
+	igt_info("%30.30s", fn);
+	igt_info("\n");
+
+}
+
+
+static void
+igt_show_stat_header(void)
+{
+	igt_info("%20.20s%11.11s%21.21s%11.11s%10.10s%22.22s%31.31s\n",
+		"COMM", "PID", "Type", "UID", "GID", "Size", "Filename");
+
+}
+
+static void
+igt_show_stat(proc_t *info, int *state, const char *fn)
+{
+	if (!*state)
+		igt_show_stat_header();
+
+	__igt_show_stat(&(struct pinfo) {.pid = info->tid,
+					 .comm = info->cmd, .fn = fn });
+	(*state)++;
+}
+
+static void
+__igt_lsof_fds(proc_t *proc_info, int *state, char *proc_path, const char *dir)
+{
+	struct dirent *d;
+	struct stat st;
+	char path[PATH_MAX];
+	char *fd_lnk;
+
+	/* default fds or kernel threads */
+	const char *default_fds[] = { "/dev/pts", "/dev/null" };
+
+	DIR *dp = opendir(proc_path);
+	igt_assert(dp);
+again:
+	while ((d = readdir(dp))) {
+		char *copy_fd_lnk;
+		char *dirn;
+
+		unsigned int i;
+		ssize_t read;
+
+		if (*d->d_name == '.')
+			continue;
+
+		memset(path, 0, sizeof(path));
+		snprintf(path, sizeof(path), "%s/%s", proc_path, d->d_name);
+
+		if (lstat(path, &st) == -1)
+			continue;
+
+		fd_lnk = malloc(st.st_size + 1);
+
+		igt_assert((read = readlink(path, fd_lnk, st.st_size + 1)));
+		fd_lnk[read] = '\0';
+
+		for (i = 0; i < ARRAY_SIZE(default_fds); ++i) {
+			if (!strncmp(default_fds[i],
+				     fd_lnk,
+				     strlen(default_fds[i]))) {
+				free(fd_lnk);
+				goto again;
+			}
+		}
+
+		copy_fd_lnk = strdup(fd_lnk);
+		dirn = dirname(copy_fd_lnk);
+
+		if (!strncmp(dir, dirn, strlen(dir)))
+			igt_show_stat(proc_info, state, fd_lnk);
+
+		free(copy_fd_lnk);
+		free(fd_lnk);
+	}
+}
+
+
+/*
+ * This functions verifies, for each process running on the machine, if the
+ * current working directory or the fds matches the one supplied in dir.
+ */
+static void
+__igt_lsof(const char *dir)
+{
+	PROCTAB *proc;
+	proc_t *proc_info;
+
+	char path[PATH_MAX];
+	char *name_lnk;
+	struct stat st;
+	int state = 0;
+
+	proc = openproc(PROC_FILLCOM | PROC_FILLSTAT | PROC_FILLARG);
+	igt_assert(proc != NULL);
+
+	while ((proc_info = readproc(proc, NULL))) {
+		ssize_t read;
+
+		/* check current working directory */
+		memset(path, 0, sizeof(path));
+		snprintf(path, sizeof(path), "/proc/%d/cwd", proc_info->tid);
+
+		if (stat(path, &st) == -1)
+			continue;
+
+		name_lnk = malloc(st.st_size + 1);
+
+		igt_assert((read = readlink(path, name_lnk, st.st_size + 1)));
+		name_lnk[read] = '\0';
+
+		if (!strncmp(dir, name_lnk, strlen(dir)))
+			igt_show_stat(proc_info, &state, name_lnk);
+
+		/* check also fd, seems that lsof(8) doesn't look here */
+		memset(path, 0, sizeof(path));
+		snprintf(path, sizeof(path), "/proc/%d/fd", proc_info->tid);
+
+		__igt_lsof_fds(proc_info, &state, path, dir);
+
+		free(name_lnk);
+		freeproc(proc_info);
+	}
+
+	closeproc(proc);
+}
+
+/**
+ * igt_lsof: Lists information about files opened by processes.
+ * @dpath: Path to look under. A valid directory is required.
+ *
+ * This function mimics (a restrictive form of) lsof(8), but also shows
+ * information about opened fds.
+ */
+void
+igt_lsof(const char *dpath)
+{
+	struct stat st;
+	size_t len = strlen(dpath);
+	char *sanitized;
+
+	if (stat(dpath, &st) == -1)
+		return;
+
+	if (!S_ISDIR(st.st_mode)) {
+		igt_info("%s not a directory!\n", dpath);
+		return;
+	}
+
+	sanitized = strdup(dpath);
+	/* remove last '/' so matching is easier */
+	if (len > 1 && dpath[len - 1] == '/')
+		sanitized[len - 1] = '\0';
+
+	__igt_lsof(sanitized);
+
+	free(sanitized);
+}
+
 static struct igt_siglatency {
 	timer_t timer;
 	struct timespec target;
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index d30196b..4162527 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -264,4 +264,7 @@ double igt_stop_siglatency(struct igt_mean *result);
 void igt_set_module_param(const char *name, const char *val);
 void igt_set_module_param_int(const char *name, int val);
 
+int igt_pkill(int sig, const char *comm);
+void igt_lsof(const char *dpath);
+
 #endif /* IGT_AUX_H */
diff --git a/lib/igt_gvt.c b/lib/igt_gvt.c
index 0f332d1..8bbf9bd 100644
--- a/lib/igt_gvt.c
+++ b/lib/igt_gvt.c
@@ -23,6 +23,7 @@
 
 #include "igt.h"
 #include "igt_gvt.h"
+#include "igt_sysfs.h"
 
 #include <dirent.h>
 #include <unistd.h>
@@ -46,49 +47,9 @@ static bool is_gvt_enabled(void)
 	return enabled;
 }
 
-static void unbind_fbcon(void)
-{
-	char buf[128];
-	const char *path = "/sys/class/vtconsole";
-	DIR *dir;
-	struct dirent *vtcon;
-
-	dir = opendir(path);
-	if (!dir)
-		return;
-
-	while ((vtcon = readdir(dir))) {
-		int fd, len;
-
-		if (strncmp(vtcon->d_name, "vtcon", 5))
-			continue;
-
-		sprintf(buf, "%s/%s/name", path, vtcon->d_name);
-		fd = open(buf, O_RDONLY);
-		if (fd < 0)
-			continue;
-
-		len = read(fd, buf, sizeof(buf) - 1);
-		close(fd);
-		if (len >= 0)
-			buf[len] = '\0';
-
-		if (strstr(buf, "frame buffer device")) {
-			sprintf(buf, "%s/%s/bind", path, vtcon->d_name);
-			fd = open(buf, O_WRONLY);
-			if (fd != -1) {
-				igt_ignore_warn(write(fd, "1\n", 2));
-				close(fd);
-			}
-			break;
-		}
-	}
-	closedir(dir);
-}
-
 static void unload_i915(void)
 {
-	unbind_fbcon();
+	kick_fbcon(false);
 	/* pkill alsact */
 
 	igt_ignore_warn(system("/sbin/modprobe -s -r i915"));
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
new file mode 100644
index 0000000..afa1a11
--- /dev/null
+++ b/lib/igt_kmod.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright © 2016 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 "igt_core.h"
+#include "igt_sysfs.h"
+#include "igt_kmod.h"
+
+#include <signal.h>
+
+/**
+ * SECTION:igt_kmod
+ * @short_description: Wrappers around libkmod for module loading/unloading
+ * @title: kmod
+ * @include: igt.h
+ *
+ * This library provides helpers to load/unload module driver.
+ *
+ * Note on loading/reloading:
+ *
+ * Loading/unload/reloading the driver requires that resources to /dev/dri to
+ * be released (closed). A potential mistake would be to submit commands to the
+ * GPU by having a fd returned by @drm_open_driver, which is closed by atexit
+ * signal handler so reloading/unloading the driver will fail if performed
+ * afterwards. One possible solution to this issue is to use
+ * @__drm_open_driver() or use @igt_set_module_param() to set module parameters
+ * dynamically.
+ */
+
+
+/**
+ * igt_kmod_is_loaded:
+ * @mod_name: The name of the module.
+ *
+ * Returns: True in case the module has been found or false otherwise.
+ *
+ * Function to check the existance of module @mod_name in list of loaded kernel
+ * modules.
+ *
+ */
+bool
+igt_kmod_is_loaded(const char *mod_name)
+{
+	struct kmod_list *mod, *list;
+	struct kmod_ctx *ctx;
+	bool ret = false;
+
+	ctx = kmod_new(NULL, NULL);
+	igt_assert(ctx != NULL);
+
+	if (kmod_module_new_from_loaded(ctx, &list) < 0) {
+		goto out;
+	}
+
+	kmod_list_foreach(mod, list) {
+		struct kmod_module *kmod = kmod_module_get_module(mod);
+		const char *kmod_name = kmod_module_get_name(kmod);
+
+		if (!strncmp(kmod_name, mod_name, strlen(kmod_name))) {
+			kmod_module_unref(kmod);
+			ret = true;
+			break;
+		}
+		kmod_module_unref(kmod);
+	}
+	kmod_module_unref_list(list);
+out:
+	kmod_unref(ctx);
+
+	return ret;
+}
+
+/**
+ * igt_kmod_load:
+ * @mod_name: The name of the module
+ * @opts: Parameters for the module. NULL in case no parameters
+ * are to be passed, or a '\0' terminated string otherwise.
+ *
+ * Returns: 0 in case of success or -errno in case the module could not
+ * be loaded.
+ *
+ * This function loads a kernel module using the name specified in @mod_name.
+ *
+ * @Note: This functions doesn't automatically resolve other module
+ * dependencies so make make sure you load the dependencies module(s) before
+ * this one.
+ */
+int
+igt_kmod_load(const char *mod_name, const char *opts)
+{
+	struct kmod_ctx *ctx;
+	struct kmod_module *kmod;
+	int err = 0;
+
+	ctx = kmod_new(NULL, NULL);
+	igt_assert(ctx != NULL);
+
+	err = kmod_module_new_from_name(ctx, mod_name, &kmod);
+	if (err < 0) {
+		goto out;
+	}
+
+	err = kmod_module_insert_module(kmod, 0, opts);
+	if (err < 0) {
+		switch (err) {
+		case -EEXIST:
+			igt_debug("Module %s already inserted\n",
+				 kmod_module_get_name(kmod));
+			break;
+		case -ENOENT:
+			igt_debug("Unknown symbol in module %s or "
+				 "unknown parameter\n",
+				 kmod_module_get_name(kmod));
+			break;
+		default:
+			igt_debug("Could not insert %s (%s)\n",
+				 kmod_module_get_name(kmod), strerror(-err));
+			break;
+		}
+	}
+out:
+	kmod_module_unref(kmod);
+	kmod_unref(ctx);
+
+	return -err ? err < 0 : err;
+}
+
+
+/**
+ * igt_kmod_unload:
+ * @mod_name: Module name.
+ * @flags: flags are passed directly to libkmod and can be:
+ * KMOD_REMOVE_FORCE or KMOD_REMOVE_NOWAIT.
+ *
+ * Returns: 0 in case of success or -errno otherwise.
+ *
+ * Removes the module @mod_name.
+ *
+ */
+int
+igt_kmod_unload(const char *mod_name, unsigned int flags)
+{
+	struct kmod_ctx *ctx;
+	struct kmod_module *kmod;
+	int err = 0;
+
+	ctx = kmod_new(NULL, NULL);
+	igt_assert(ctx != NULL);
+
+	err = kmod_module_new_from_name(ctx, mod_name, &kmod);
+	if (err < 0) {
+		igt_debug("Could not use module %s (%s)\n", mod_name,
+				strerror(-err));
+		goto out;
+	}
+
+	err = kmod_module_remove_module(kmod, flags);
+	if (err < 0) {
+		igt_debug("Could not remove module %s (%s)\n", mod_name,
+				strerror(-err));
+	}
+
+out:
+	kmod_module_unref(kmod);
+	kmod_unref(ctx);
+
+	return -err ? err < 0 : err;
+}
+
+/**
+ *
+ * igt_kmod_list_loaded: List all modules currently loaded.
+ *
+ */
+void
+igt_kmod_list_loaded(void)
+{
+	struct kmod_list *module, *list;
+	struct kmod_ctx *ctx;
+
+	ctx = kmod_new(NULL, NULL);
+	igt_assert(ctx != NULL);
+
+	if (kmod_module_new_from_loaded(ctx, &list) < 0) {
+		kmod_unref(ctx);
+		return;
+	}
+
+	igt_info("Module\t\t      Used by\n");
+
+	kmod_list_foreach(module, list) {
+		struct kmod_module *kmod = kmod_module_get_module(module);
+		struct kmod_list *module_deps, *module_deps_list;
+
+		igt_info("%-24s", kmod_module_get_name(kmod));
+		module_deps_list = kmod_module_get_holders(kmod);
+		if (module_deps_list) {
+
+			kmod_list_foreach(module_deps, module_deps_list) {
+				struct kmod_module *kmod_dep;
+
+				kmod_dep = kmod_module_get_module(module_deps);
+				igt_info("%s",
+					kmod_module_get_name(kmod_dep));
+
+				if (kmod_list_next(module_deps_list, module_deps))
+					igt_info(",");
+
+				kmod_module_unref(kmod_dep);
+			}
+		}
+		kmod_module_unref_list(module_deps_list);
+
+		igt_info("\n");
+		kmod_module_unref(kmod);
+	}
+
+	kmod_module_unref_list(list);
+	kmod_unref(ctx);
+}
+
+/**
+ * igt_i915_driver_load:
+ * @opts: options to pass to i915 driver
+ *
+ * Loads the i915 driver and its dependencies.
+ *
+ */
+int
+igt_i915_driver_load(const char *opts)
+{
+	if (opts)
+		igt_info("Reloading i915 with %s\n\n", opts);
+
+	/* we do not have automatic loading of dependencies */
+	igt_kmod_load("drm", NULL);
+	igt_kmod_load("drm_kms_helper", NULL);
+
+	if (igt_kmod_load("i915", opts)) {
+		igt_warn("Could not load i915\n");
+		return IGT_EXIT_FAILURE;
+	}
+
+	kick_fbcon(true);
+	igt_kmod_load("snd_hda_intel", NULL);
+
+	return IGT_EXIT_SUCCESS;
+}
+
+/**
+ * igt_i915_driver_unload:
+ *
+ * Unloads the i915 driver and its dependencies.
+ *
+ */
+int
+igt_i915_driver_unload(void)
+{
+	/* unbind vt */
+	kick_fbcon(false);
+
+	if (igt_kmod_is_loaded("snd_hda_intel")) {
+		igt_pkill(SIGTERM, "alsactl");
+
+		/* unbind snd_hda_intel */
+		kick_snd_hda_intel();
+
+		if (igt_kmod_unload("snd_hda_intel", 0)) {
+			igt_warn("Could not unload snd_hda_intel\n");
+			igt_kmod_list_loaded();
+			igt_lsof("/dev/snd");
+			return IGT_EXIT_FAILURE;
+		}
+	}
+
+	/* gen5 */
+	if (igt_kmod_is_loaded("intel_ips")) {
+		igt_kmod_unload("intel_ips", 0);
+	}
+
+	if (igt_kmod_is_loaded("i915")) {
+		if (igt_kmod_unload("i915", 0)) {
+			igt_warn("Could not unload i915\n");
+			igt_kmod_list_loaded();
+			igt_lsof("/dev/dri");
+			return IGT_EXIT_SKIP;
+		} else {
+			igt_info("i915.ko has been unloaded!\n");
+		}
+	}
+
+	if (igt_kmod_is_loaded("intel-gtt")) {
+		igt_kmod_unload("intel-gtt", 0);
+	}
+
+	igt_kmod_unload("drm_kms_helper", 0);
+	igt_kmod_unload("drm", 0);
+
+	if (igt_kmod_is_loaded("i915")) {
+		igt_warn("i915.ko still loaded!\n");
+		return IGT_EXIT_FAILURE;
+	} else {
+		igt_info("module successfully unloaded\n");
+	}
+
+
+	return IGT_EXIT_SUCCESS;
+}
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
new file mode 100644
index 0000000..dcf8f67
--- /dev/null
+++ b/lib/igt_kmod.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2016 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.
+ */
+
+#ifndef IGT_KMOD_H
+#define IGT_KMOD_H
+
+#include <libkmod.h>
+
+bool igt_kmod_is_loaded(const char *mod_name);
+void igt_kmod_list_loaded(void);
+
+int igt_kmod_load(const char *mod_name, const char *opts);
+int igt_kmod_unload(const char *mod_name, unsigned int flags);
+
+int igt_i915_driver_load(const char *opts);
+int igt_i915_driver_unload(void);
+
+
+#endif /* IGT_KMOD_H */
diff --git a/lib/igt_sysfs.c b/lib/igt_sysfs.c
index c19821d..570329d 100644
--- a/lib/igt_sysfs.c
+++ b/lib/igt_sysfs.c
@@ -34,7 +34,11 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <i915_drm.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
 
+#include "igt_core.h"
 #include "igt_sysfs.h"
 
 /**
@@ -392,3 +396,105 @@ bool igt_sysfs_set_boolean(int dir, const char *attr, bool value)
 {
 	return igt_sysfs_printf(dir, attr, "%d", value) == 1;
 }
+
+/**
+ * kick_fbcon:
+ * @enable: boolean value
+ *
+ * This functions enables/disables the text console running on top of the
+ * framebuffer device.
+ */
+void kick_fbcon(bool enable)
+{
+	char buf[128];
+	const char *path = "/sys/class/vtconsole";
+	DIR *dir;
+	struct dirent *vtcon;
+
+	dir = opendir(path);
+	if (!dir)
+		return;
+
+	while ((vtcon = readdir(dir))) {
+		int fd, len;
+
+		if (strncmp(vtcon->d_name, "vtcon", 5))
+			continue;
+
+		sprintf(buf, "%s/%s/name", path, vtcon->d_name);
+		fd = open(buf, O_RDONLY);
+		if (fd < 0)
+			continue;
+
+		len = read(fd, buf, sizeof(buf) - 1);
+		close(fd);
+		if (len >= 0)
+			buf[len] = '\0';
+
+		if (strstr(buf, "frame buffer device")) {
+			sprintf(buf, "%s/%s/bind", path, vtcon->d_name);
+			fd = open(buf, O_WRONLY);
+			if (fd != -1) {
+				if (enable)
+					igt_ignore_warn(write(fd, "1\n", 2));
+				else
+					igt_ignore_warn(write(fd, "0\n", 2));
+				close(fd);
+			}
+			break;
+		}
+	}
+	closedir(dir);
+}
+
+/**
+ * kick_snd_hda_intel:
+ *
+ * This functions unbinds the snd_hda_intel driver so the module cand be
+ * unloaded.
+ *
+ */
+void kick_snd_hda_intel(void)
+{
+	DIR *dir;
+	struct dirent *snd_hda;
+	int fd; size_t len;
+
+	const char *dpath = "/sys/bus/pci/drivers/snd_hda_intel";
+	const char *path = "/sys/bus/pci/drivers/snd_hda_intel/unbind";
+	const char *devid = "0000:";
+
+	fd = open(path, O_WRONLY);
+	if (fd < 0) {
+		return;
+	}
+
+	dir = opendir(dpath);
+	if (!dir)
+		goto out;
+
+	len = strlen(devid);
+	while ((snd_hda = readdir(dir))) {
+		struct stat st;
+		char fpath[PATH_MAX];
+
+		if (*snd_hda->d_name == '.')
+			continue;
+
+		snprintf(fpath, sizeof(fpath), "%s/%s", dpath, snd_hda->d_name);
+		if (lstat(fpath, &st))
+			continue;
+
+		if (!S_ISLNK(st.st_mode))
+			continue;
+
+		if (!strncmp(devid, snd_hda->d_name, len)) {
+			igt_ignore_warn(write(fd, snd_hda->d_name,
+					strlen(snd_hda->d_name)));
+		}
+	}
+
+	closedir(dir);
+out:
+	close(fd);
+}
diff --git a/lib/igt_sysfs.h b/lib/igt_sysfs.h
index 4820066..69b2e5e 100644
--- a/lib/igt_sysfs.h
+++ b/lib/igt_sysfs.h
@@ -43,4 +43,7 @@ bool igt_sysfs_set_u32(int dir, const char *attr, uint32_t value);
 bool igt_sysfs_get_boolean(int dir, const char *attr);
 bool igt_sysfs_set_boolean(int dir, const char *attr, bool value);
 
+void kick_fbcon(bool enable);
+void kick_snd_hda_intel(void);
+
 #endif /* __IGT_SYSFS_H__ */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  reply	other threads:[~2016-12-01 12:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-01 12:23 [PATCH i-g-t 0/4 v7] Convert sh scripts to C variants Marius Vlad
2016-12-01 12:23 ` Marius Vlad [this message]
2016-12-01 12:23 ` [PATCH i-g-t 2/4 v7] lib/igt_gvt: Make use of libkmod helpers and fix reading gvt parameter Marius Vlad
2016-12-01 12:23 ` [PATCH i-g-t 3/4 v7] tests/drv_module_reload: Convert sh script to C version Marius Vlad
2016-12-01 12:23 ` [PATCH i-g-t 4/4 v7] tests/kms_sysfs_edid_timing: Convert sh " Marius Vlad
2016-12-01 23:43 ` [PATCH i-g-t 0/4 v7] Convert sh scripts to C variants Chris Wilson
2016-12-02 14:35   ` Petri Latvala

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161201122358.1124-2-marius.c.vlad@intel.com \
    --to=marius.c.vlad@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.