[PATCH i-g-t v2] lib/igt_kmod: Rewrite xe unload logic

Lucas De Marchi lucas.demarchi at intel.com
Thu Sep 19 15:11:30 UTC 2024


Stop trying to unload possibly-dependent modules. Loading a module and
probing a module are 2 different things, although the Linux kernel will
by default probe devices when a module is loaded (for pci, configurable
in /sys/bus/pci/drivers_autoprobe).

For the unloading part we can simplify: instead of trying to unload
the modules directly (which may complain that module is already in use)
we just unplug the HW first.  For each possible device bound.

This will become part of libkmod in future, but we don't need to wait:
we can implement it in igt too as it's straightforward.

For now this only switches the unload path for xe, but if it works well,
we can switch others in future too.

v2:
- Rename function since now it works for any PCI driver
- Move function so it will be available for i915 too.

Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/2362
Reviewed-by: Jonathan Cavitt <jonathan.cavitt at intel.com>
Signed-off-by: Lucas De Marchi <lucas.demarchi at intel.com>
---
 lib/igt_kmod.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_kmod.h |  5 +----
 2 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 464c0dcf4..75a0d057c 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -660,6 +660,51 @@ int __igt_intel_driver_unload(char **who, const char *driver)
 	return 0;
 }
 
+/*
+ * Unbind driver from devices. Currently supports only PCI bus
+ */
+static int unbind(const char *driver)
+{
+	char path[PATH_MAX];
+	struct dirent *de;
+	int dirlen;
+	DIR *dir;
+
+	dirlen = snprintf(path, sizeof(path), "/sys/module/%s/drivers/pci:%s/",
+			  driver, driver);
+	igt_assert(dirlen < sizeof(path));
+
+	dir = opendir(path);
+
+	/* Module may be loaded, but without any device bound */
+	if (!dir)
+		return 0;
+
+	while ((de = readdir(dir))) {
+		int devfd;
+		bool ret;
+
+		if (de->d_type != DT_LNK || !isdigit(de->d_name[0]))
+			continue;
+
+		devfd = openat(dirfd(dir), de->d_name, O_RDONLY | O_CLOEXEC);
+		igt_assert(devfd >= 0);
+
+		ret = igt_sysfs_set(devfd, "power/control", "auto");
+		igt_assert(ret);
+
+		ret = igt_sysfs_set(devfd, "driver/unbind", de->d_name);
+		igt_assert(ret);
+
+		close(devfd);
+		errno = 0;
+	}
+
+	igt_assert_eq(errno, 0);
+
+	return 0;
+}
+
 /**
  * igt_intel_driver_unload:
  *
@@ -697,6 +742,17 @@ igt_intel_driver_unload(const char *driver)
 	return 0;
 }
 
+int igt_xe_driver_unload(void)
+{
+	unbind("xe");
+
+	igt_kmod_unload("xe");
+	if (igt_kmod_is_loaded("xe"))
+		return IGT_EXIT_FAILURE;
+
+	return IGT_EXIT_SUCCESS;
+}
+
 /**
  * igt_amdgpu_driver_load:
  * @opts: options to pass to amdgpu driver
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index efb46da12..ee1719a8f 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -63,10 +63,7 @@ static inline int igt_xe_driver_load(const char *opts)
 }
 
 
-static inline int igt_xe_driver_unload(void)
-{
-	return igt_intel_driver_unload("xe");
-}
+int igt_xe_driver_unload(void);
 
 int igt_amdgpu_driver_load(const char *opts);
 int igt_amdgpu_driver_unload(void);
-- 
2.46.1



More information about the igt-dev mailing list