[PATCH umr v2] Add PCI device based GPU selection with --pci

Jean-Francois Thibert jfthibert at google.com
Fri Jun 23 20:33:38 UTC 2017


This allows selecting the GPU by its PCI device both with and
without kernel mode support. The instance is populated automatically
so that the proper corresponding debugfs files are used if present.

Signed-off-by: Jean-Francois Thibert <jfthibert at google.com>
---
 doc/umr.1          |  4 +++
 src/app/main.c     |  9 ++++++
 src/lib/discover.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/umr.h          |  6 ++++
 4 files changed, 103 insertions(+), 3 deletions(-)

diff --git a/doc/umr.1 b/doc/umr.1
index 5c4bd01..a03dfb8 100644
--- a/doc/umr.1
+++ b/doc/umr.1
@@ -17,6 +17,10 @@ Select a GFX INSTANCE/SH/SE bank in decimal.  Can use 'x' to denote a broadcast
 .IP "--force -f <number>"
 Force a PCIE Device ID in hex or by asic name.  This is used in case the amdgpu driver
 is not yet loaded or a display is not yet attached.
+.IP "--pci <device>"
+Force a specific PCI device using the domain:bus:slot.function format in hex.
+This is useful when more than one GPU is available. If the amdgpu driver is
+loaded the corresponding instance will be automatically detected.
 .IP "--print, -p"
 Enable scanning and printing all registers.  Defaults to off as it can
 be very verbose.
diff --git a/src/app/main.c b/src/app/main.c
index 1d9ef9e..067b472 100644
--- a/src/app/main.c
+++ b/src/app/main.c
@@ -174,6 +174,15 @@ int main(int argc, char **argv)
 				printf("--force requires a number/name\n");
 				return EXIT_FAILURE;
 			}
+		} else if (!strcmp(argv[i], "--pci")) {
+			if (i + 1 < argc && sscanf(argv[i+1], "%04x:%02x:%02x.%01x",
+				&options.pci.domain, &options.pci.bus, &options.pci.slot,
+				&options.pci.func ) >= 4) {
+				++i;
+			} else {
+				printf("--pci requires domain:bus:slot.function\n");
+				return EXIT_FAILURE;
+			}
 		} else if (!strcmp(argv[i], "--print") || !strcmp(argv[i], "-p")) {
 			options.print = 1;
 			options.need_scan = 1;
diff --git a/src/lib/discover.c b/src/lib/discover.c
index 9662d05..a95fe57 100644
--- a/src/lib/discover.c
+++ b/src/lib/discover.c
@@ -22,6 +22,9 @@
  * Authors: Tom St Denis <tom.stdenis at amd.com>
  *
  */
+#include <dirent.h>
+#include <sys/types.h>
+
 #include "umr.h"
 
 static int is_did_match(struct umr_asic *asic, unsigned did)
@@ -44,6 +47,44 @@ static int is_did_match(struct umr_asic *asic, unsigned did)
 	return r;
 }
 
+static int find_pci_instance(const char* pci_string) {
+	DIR* dir;
+	dir = opendir("/sys/kernel/debug/dri");
+	if (dir == NULL) {
+		perror("Couldn't open DRI under debugfs");
+		return -1;
+	}
+	struct dirent *dir_entry;
+	while ((dir_entry = readdir(dir)) != NULL) {
+		char device[256], name[256];
+		int parsed_device;
+		// ignore . and ..
+		if (strcmp(dir_entry->d_name, ".") == 0 || strcmp(dir_entry->d_name,
+			"..") == 0) {
+			continue;
+		}
+		snprintf(name, sizeof(name), "/sys/kernel/debug/dri/%s/name",
+			dir_entry->d_name);
+		FILE *f = fopen(name, "r");
+		if (!f) {
+			continue;
+		}
+		device[sizeof(device) - 1] = 0;
+		parsed_device = fscanf(f, "%*s %255s", device);
+		fclose(f);
+		if (parsed_device != 1)
+			continue;
+		// strip off dev= for kernels > 4.7
+		if (strstr(device, "dev="))
+			memmove(device, device+4, strlen(device)-3);
+		if (strcmp(pci_string, device) == 0) {
+			closedir(dir);
+			return atoi(dir_entry->d_name);
+		}
+	}
+	closedir(dir);
+	return -1;
+}
 
 struct umr_asic *umr_discover_asic(struct umr_options *options)
 {
@@ -53,6 +94,30 @@ struct umr_asic *umr_discover_asic(struct umr_options *options)
 	struct umr_asic *asic;
 	long trydid = options->forcedid;
 
+	// Try to map to instance if we have a specific pci device
+	if (options->pci.domain || options->pci.bus ||
+		options->pci.slot || options->pci.func) {
+		char pci_string[16];
+		int parsed_did;
+		snprintf(pci_string, sizeof(pci_string), "%04x:%02x:%02x.%x",
+			options->pci.domain, options->pci.bus, options->pci.slot,
+			options->pci.func);
+		if (!options->no_kernel) {
+			options->instance = find_pci_instance(pci_string);
+		}
+		snprintf(driver, sizeof(driver), "/sys/bus/pci/devices/%s/device", pci_string);
+		f = fopen(driver, "r");
+		if (!f) {
+			if (!options->quiet) perror("Cannot open PCI device name under sysfs (is a display attached?)");
+			return NULL;
+		}
+		parsed_did = fscanf(f, "0x%04lx", &trydid);
+		fclose(f);
+		if (parsed_did != 1) {
+			if (!options->quiet) printf("Could not read device id");
+			return NULL;
+		}
+	}
 	// try to scan via debugfs
 	asic = calloc(1, sizeof *asic);
 	if (asic) {
@@ -64,7 +129,6 @@ struct umr_asic *umr_discover_asic(struct umr_options *options)
 		umr_free_asic(asic);
 		asic = NULL;
 	}
-
 	if (trydid < 0) {
 		snprintf(name, sizeof(name)-1, "/sys/kernel/debug/dri/%d/name", options->instance);
 		f = fopen(name, "r");
@@ -86,8 +150,12 @@ struct umr_asic *umr_discover_asic(struct umr_options *options)
 			}
 			return NULL;
 		}
-		fscanf(f, "%s %s %s\n", driver, name, driver);
+		int parsed_pci_id = fscanf(f, "%*s %s", name);
 		fclose(f);
+		if (parsed_pci_id != 1) {
+			if (!options->quiet) printf("Cannot read pci device id\n");
+			return NULL;
+		}
 
 		// strip off dev= for kernels > 4.7
 		if (strstr(name, "dev="))
@@ -99,8 +167,12 @@ struct umr_asic *umr_discover_asic(struct umr_options *options)
 			if (!options->quiet) perror("Cannot open PCI device name under sysfs (is a display attached?)");
 			return NULL;
 		}
-		fscanf(f, "0x%04x", &did);
+		int parsed_did = fscanf(f, "0x%04x", &did);
 		fclose(f);
+		if (parsed_did != 1) {
+			if (!options->quiet) printf("Could not read device id");
+			return NULL;
+		}
 		asic = umr_discover_asic_by_did(options, did);
 	} else {
 		if (options->dev_name[0])
@@ -158,6 +230,15 @@ struct umr_asic *umr_discover_asic(struct umr_options *options)
 			}
 			do {
 				asic->pci.pdevice = pci_device_next(pci_iter);
+				if (options->pci.domain || options->pci.bus || options->pci.slot || options->pci.func) {
+					while (asic->pci.pdevice && (
+						options->pci.domain != asic->pci.pdevice->domain ||
+						options->pci.bus != asic->pci.pdevice->bus ||
+						options->pci.slot != asic->pci.pdevice->dev ||
+						options->pci.func != asic->pci.pdevice->func)) {
+						asic->pci.pdevice = pci_device_next(pci_iter);
+					}
+				}
 			} while (asic->pci.pdevice && !(asic->pci.pdevice->vendor_id == 0x1002 && is_did_match(asic, asic->pci.pdevice->device_id)));
 
 			if (!asic->pci.pdevice) {
diff --git a/src/umr.h b/src/umr.h
index ccfac5d..2a69017 100644
--- a/src/umr.h
+++ b/src/umr.h
@@ -181,6 +181,12 @@ struct umr_options {
 	long forcedid;
 	char *scanblock;
 	char dev_name[32];
+	struct {
+		int domain,
+		    bus,
+		    slot,
+		    func;
+	} pci;
 };
 
 struct umr_asic {
-- 
2.13.1.611.g7e3b11ae1-goog



More information about the amd-gfx mailing list