summaryrefslogtreecommitdiff
path: root/lib/igt_kmod.c
diff options
context:
space:
mode:
authorMarius Vlad <marius.c.vlad@intel.com>2016-12-01 21:45:47 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2016-12-01 21:45:47 +0000
commit0268d73b0b267c6f5acdd4bf40ae917b3afff96c (patch)
treecc5f3c23378db20553bb2087cf5c7f0b1fe1cd49 /lib/igt_kmod.c
parent4d8f3b2c8034f1bdf64d65d484e5d5cd18410fb7 (diff)
lib/igt_kmod: New library to support driver loading/unloading and additional helpers.
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) 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>
Diffstat (limited to 'lib/igt_kmod.c')
-rw-r--r--lib/igt_kmod.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
new file mode 100644
index 00000000..9fb66919
--- /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_terminate_process(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;
+}