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> --- src/app/main.c | 9 ++++++ src/lib/discover.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/umr.h | 6 +++- 3 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/app/main.c b/src/app/main.c index 1d9ef9e..aa630f5 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..8ab321f 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,43 @@ 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) { + // ignore . and .. + if (strcmp(dir_entry->d_name, ".") == 0 || strcmp(dir_entry->d_name, + "..") == 0) { + continue; + } + char name[256]; + snprintf(name, sizeof(name) - 1, "/sys/kernel/debug/dri/%s/name", + dir_entry->d_name); + FILE *f = fopen(name, "r"); + if (!f) { + continue; + } + char device[256] = {}; + int 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 +93,29 @@ 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]; + snprintf(pci_string, sizeof(pci_string) - 1, "%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)-1, "/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; + } + int found_did = fscanf(f, "0x%04lx", &trydid); + fclose(f); + if (found_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 +127,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 +148,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 +165,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 +228,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..391c5e7 100644 --- a/src/umr.h +++ b/src/umr.h @@ -173,7 +173,11 @@ struct umr_options { read_smc, quiet, follow_ib, - no_kernel; + no_kernel, + pci_domain, + pci_bus, + pci_slot, + pci_func; unsigned instance_bank, se_bank, -- 2.13.1.611.g7e3b11ae1-goog