[igt-dev] [PATCH i-g-t v5 2/2] Add device selection for IGT

Zbigniew Kempczyński
2019-08-23T07:32:01Z

New IGT command line argument --device, IGT_DEVICE enviroment
and .igtrc Common::Device were added to allow selecting device
using device selection API.

Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Petri Latvala <petri.latvala@intel.com>
---
docs/chamelium.txt | 3 +
lib/drmtest.c | 188 ++++++++++++++++++++++++++++++++++++++++++++-
lib/drmtest.h | 9 +++
lib/igt_core.c | 34 ++++++++
4 files changed, 232 insertions(+), 2 deletions(-)

diff --git a/docs/chamelium.txt b/docs/chamelium.txt
index 32c296f7..d3a379d3 100644
--- a/docs/chamelium.txt
+++ b/docs/chamelium.txt
@@ -84,6 +84,9 @@ example (only Chamelium.URL is mandatory):
# The path to dump frames that fail comparison checks
FrameDumpPath=/root/

+ # Device selection filter
+ Device=pci:vendor=8086,card=0;vgem:
+
# The following section is used for configuring the Device Under Test.
# It is not mandatory and allows overriding default values.
[DUT]
diff --git a/lib/drmtest.c b/lib/drmtest.c
index c379a7b7..c01a88a9 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -55,6 +55,7 @@
#include "igt_gt.h"
#include "igt_kmod.h"
#include "igt_sysfs.h"
+#include "igt_device_scan.h"
#include "version.h"
#include "config.h"
#include "intel_reg.h"
@@ -289,25 +290,208 @@ static int __open_driver(const char *base, int offset, unsigned int chipset)
return __search_and_open(base, offset, chipset);
}

+static int __open_driver_exact(const char *name, unsigned int chipset)
+{
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ int fd;
+
+ fd = open_device(name, chipset);
+ if (fd != -1)
+ return fd;
+
+ pthread_mutex_lock(&mutex);
+ for (const struct module *m = modules; m->module; m++) {
+ if (chipset & m->bit) {
+ if (m->modprobe)
+ m->modprobe(m->module);
+ else
+ modprobe(m->module);
+ }
+ }
+ pthread_mutex_unlock(&mutex);
+
+ return open_device(name, chipset);
+}
+
+/*
+ * For compatibility mode when multiple --device argument were passed
+ * this function tries to be smart enough to handle tests which opens
+ * more than single device. It iterates over filter list and
+ * compares requested chipset to card chipset (or any).
+ *
+ * Returns:
+ * True if card according to filters added and chipset was found,
+ * false othwerwise.
+ */
+static bool __find_card_with_chipset(int chipset, struct igt_device_card *card)
+{
+ int i, n = igt_device_filter_count();
+ const char *filter;
+ bool match;
+
+ for (i = 0; i < n; i++) {
+ filter = igt_device_filter_get(i);
+ match = igt_device_card_match(filter, card);
+ if (match && (card->chipset == chipset ||
+ card->chipset == DRIVER_ANY)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* __drm_open_driver:
* @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
*
- * Open the first DRM device we can find, searching up to 16 device nodes
+ * Function opens device in the following order:
+ * 1. when --device arguments are present device scanning will be executed,
+ * then filter argument is used to find matching one.
+ * 2. compatibility mode - open the first DRM device we can find,
+ * searching up to 16 device nodes.
*
* Returns:
* An open DRM fd or -1 on error
*/
int __drm_open_driver(int chipset)
{
+ int n = igt_device_filter_count();
+
+ if (n) {
+ bool found;
+ struct igt_device_card card;
+
+ found = __find_card_with_chipset(chipset, &card);
+ if (!found || !strlen(card.card))
+ return -1;
+
+ return __open_driver_exact(card.card, chipset);
+ }
+
return __open_driver("/dev/dri/card", 0, chipset);
}

-static int __drm_open_driver_render(int chipset)
+int __drm_open_driver_render(int chipset)
{
+ int n = igt_device_filter_count();
+
+ if (n) {
+ bool found;
+ struct igt_device_card card;
+
+ found = __find_card_with_chipset(chipset, &card);
+ if (!found || !strlen(card.render))
+ return -1;
+
+ return __open_driver_exact(card.render, chipset);
+ }
+
return __open_driver("/dev/dri/renderD", 128, chipset);
}

+static int __drm_open_with_nth_filter(int num, int chipset, bool open_render)
+{
+ struct igt_device_card card;
+ const char *filter, *devname;
+ bool match;
+ int n = igt_device_filter_count();
+
+ if (!n || num < 0 || num >= n) {
+ igt_warn("No device filter num == %d passed\n", num);
+ return -1;
+ }
+
+ filter = igt_device_filter_get(num);
+ match = igt_device_card_match(filter, &card);
+ if (!match) {
+ igt_warn("No device match filter: %s\n", filter);
+ return -1;
+ }
+
+ if (!strlen(card.card) && !strlen(card.render))
+ return -1;
+
+ devname = open_render ? card.render : card.card;
+ if (!strlen(devname)) {
+ igt_warn("No %s node matching filter: %s\n",
+ open_render ? "render" : "card", filter);
+ return -1;
+ }
+ return __open_driver_exact(devname, chipset);
+}
+
+/**
+ * drm_open_card_with_nth_filter:
+ * @num: number of --device argument
+ * @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
+ *
+ * Open /dev/dri/cardX device using multi-device selection API.
+ * When test require to open more than one device selection uses filter
+ * passed as --device argument. Arguments @num indicate filter number
+ * and @chipset expected device card chipset.
+ *
+ * An open DRM fd or -1 on error
+ */
+int drm_open_card_with_nth_filter(int num, int chipset)
+{
+ return __drm_open_with_nth_filter(num, chipset, false);
+}
+
+/**
+ * drm_open_render_with_nth_filter:
+ * @num: number of --device argument
+ * @chipset: OR'd flags for each chipset to search, eg. #DRIVER_INTEL
+ *
+ * Open /dev/dri/renderDX device using multi-device selection API.
+ *
+ * When test require to open more than one device selection uses filter
+ * passed as --device argument. Arguments @num indicate filter number
+ * and @chipset expected device card chipset.
+ *
+ * An open DRM fd or -1 on error
+ */
+int drm_open_render_with_nth_filter(int num, int chipset)
+{
+ return __drm_open_with_nth_filter(num, chipset, true);
+}
+
+/**
+ * drm_open_card:
+ * @card: pointer to igt_device_card structure
+ *
+ * Open /dev/dri/cardX device using multi-device selection API.
+ *
+ * Require filled @card argument (see igt_device_card_match() function).
+ *
+ * An open DRM fd or -1 on error
+ */
+int drm_open_card(struct igt_device_card *card)
+{
+ if (!card || !strlen(card->card))
+ return -1;
+
+ return __open_driver_exact(card->card, card->chipset);
+}
+
+/**
+ * drm_open_render:
+ * @card: pointer to igt_device_card structure
+ *
+ * Open /dev/dri/renderDX device using multi-device selection API.
+ * Require filled @card argument (see igt_device_card_match() function).
+ *
+ * An open DRM fd or -1 on error
+ */
+int drm_open_render(struct igt_device_card *card)
+{
+ if (!card || !strlen(card->render))
+ return -1;
+
+ return __open_driver_exact(card->render, card->chipset);
+}
+
+
static int at_exit_drm_fd = -1;
static int at_exit_drm_render_fd = -1;

diff --git a/lib/drmtest.h b/lib/drmtest.h
index 614f57e6..fc2a0b57 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -50,6 +50,7 @@
#define DRIVER_AMDGPU (1 << 3)
#define DRIVER_V3D (1 << 4)
#define DRIVER_PANFROST (1 << 5)
+
/*
* Exclude DRVER_VGEM from DRIVER_ANY since if you run on a system
* with vgem as well as a supported driver, you can end up with a
@@ -81,6 +82,14 @@ int drm_open_driver(int chipset);
int drm_open_driver_master(int chipset);
int drm_open_driver_render(int chipset);
int __drm_open_driver(int chipset);
+int __drm_open_driver_render(int chipset);
+
+/* Multi device API */
+int drm_open_card_with_nth_filter(int num, int chipset);
+int drm_open_render_with_nth_filter(int num, int chipset);
+struct igt_device_card;
+int drm_open_card(struct igt_device_card *card);
+int drm_open_render(struct igt_device_card *card);

void gem_quiescent_gpu(int fd);

diff --git a/lib/igt_core.c b/lib/igt_core.c
index 1cbb09f9..a8a11b5c 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -71,6 +71,7 @@
#include "igt_sysrq.h"
#include "igt_rc.h"
#include "igt_list.h"
+#include "igt_device_scan.h"

#define UNW_LOCAL_ONLY
#include <libunwind.h>
@@ -245,6 +246,9 @@
* [Common]
* FrameDumpPath=/tmp # The path to dump frames that fail comparison checks
*
+ * &num; Device selection filter
+ * Device=pci:vendor=8086,card=0;vgem:
+ *
* &num; The following section is used for configuring the Device Under Test.
* &num; It is not mandatory and allows overriding default values.
* [DUT]
@@ -304,6 +308,7 @@ enum {
OPT_DEBUG,
OPT_INTERACTIVE_DEBUG,
OPT_SKIP_CRC,
+ OPT_DEVICE,
OPT_HELP = 'h'
};

@@ -320,6 +325,7 @@ static pthread_mutex_t log_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
GKeyFile *igt_key_file;

char *igt_frame_dump_path;
+char *igt_rc_device;

static bool stderr_needs_sentinel = false;

@@ -624,6 +630,7 @@ static void print_usage(const char *help_str, bool output_on_stderr)
" --skip-crc-compare\n"
" --help-description\n"
" --describe\n"
+ " --device filter\n"
" --help|-h\n");
if (help_str)
fprintf(f, "%s\n", help_str);
@@ -688,6 +695,16 @@ static void common_init_config(void)
if (ret != 0)
igt_set_autoresume_delay(ret);

+ /* No IGT_DEVICE and no --device passed, try .igtrc Common::Device */
+ if (!igt_rc_device)
+ igt_rc_device =
+ g_key_file_get_string(igt_key_file, "Common",
+ "Device", &error);
+ if (igt_rc_device && !igt_device_filter_count())
+ igt_device_filter_add(igt_rc_device);
+
+ g_clear_error(&error);
+
out:
if (!key_file_env && key_file_loc)
free(key_file_loc);
@@ -725,6 +742,11 @@ static void common_init_env(void)
if (env) {
__set_forced_driver(env);
}
+
+ env = getenv("IGT_DEVICE");
+ if (env) {
+ igt_device_filter_add(env);
+ }
}

static int common_init(int *argc, char **argv,
@@ -743,6 +765,7 @@ static int common_init(int *argc, char **argv,
{"debug", optional_argument, NULL, OPT_DEBUG},
{"interactive-debug", optional_argument, NULL, OPT_INTERACTIVE_DEBUG},
{"skip-crc-compare", no_argument, NULL, OPT_SKIP_CRC},
+ {"device", required_argument, NULL, OPT_DEVICE},
{"help", no_argument, NULL, OPT_HELP},
{0, 0, 0, 0}
};
@@ -865,6 +888,17 @@ static int common_init(int *argc, char **argv,
case OPT_SKIP_CRC:
igt_skip_crc_compare = true;
goto out;
+ case OPT_DEVICE:
+ assert(optarg);
+ /* We need to free all devices passed in
+ * IGT_DEVICE environment variable.
+ */
+ if (getenv("IGT_DEVICE") && igt_device_filter_count()) {
+ unsetenv("IGT_DEVICE");
+ igt_device_filter_free_all();
+ }
+ igt_device_filter_add(optarg);
+ break;
case OPT_HELP:
print_usage(help_str, false);
ret = -1;
--
2.21.0