diff options
author | Tom St Denis <tom.stdenis@amd.com> | 2017-02-04 13:28:35 -0500 |
---|---|---|
committer | Tom St Denis <tom.stdenis@amd.com> | 2017-02-04 13:28:35 -0500 |
commit | d0db3474f11d8dcc1dac6c6c078b6a7483fc45e5 (patch) | |
tree | 7c09cd4993cc061bee6c53cb49324cdd591f1784 | |
parent | eb346e17d5213f91f3e5a5d3abb1c04e0608660a (diff) |
Add support for rev3 config data, accelerate logscan
Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 6 | ||||
-rw-r--r-- | src/app/scan.c | 7 | ||||
-rw-r--r-- | src/app/scan_log.c | 93 | ||||
-rw-r--r-- | src/app/set_bit.c | 1 | ||||
-rw-r--r-- | src/app/set_reg.c | 1 | ||||
-rw-r--r-- | src/lib/close_asic.c | 31 | ||||
-rw-r--r-- | src/lib/create_mmio_accel.c | 55 | ||||
-rw-r--r-- | src/lib/discover.c | 17 | ||||
-rw-r--r-- | src/lib/scan_config.c | 11 | ||||
-rw-r--r-- | src/umr.h | 16 |
11 files changed, 195 insertions, 45 deletions
@@ -23,7 +23,7 @@ src/lib/bitfield_print.o src/lib/close_asic.o src/lib/create_asic_helper.o \ src/lib/discover_by_did.o src/lib/discover_by_name.o src/lib/discover.o src/lib/dump_ib.o \ src/lib/find_reg.o src/lib/mmio.o src/lib/query_drm.o \ src/lib/read_sgpr.o src/lib/read_vram.o src/lib/ring_decode.o src/lib/scan_config.o \ -src/lib/wave_status.o \ +src/lib/wave_status.o src/lib/create_mmio_accel.o \ \ src/lib/ip/bif30.o src/lib/ip/bif41.o src/lib/ip/bif50.o src/lib/ip/bif51.o \ \ @@ -10,7 +10,11 @@ the AMDGPU kernel driver with limited support for driverless debugging The tool allows reading/writing MMIO registers, analyzing wavefronts, ring contents, as well as performance tracking. It supports hardware -from SI based hardware onwards. +from SI based hardware onwards and requires a v4.10 kernel or newer +to function correctly. Older kernels (not older than v4.8) may work +but with limited functionality/stability. Older kernels are not supported +officially so please refrain from submitting bug reports in relation +to them. The tool is open source and hosted at diff --git a/src/app/scan.c b/src/app/scan.c index 436c2e0..afcadc4 100644 --- a/src/app/scan.c +++ b/src/app/scan.c @@ -37,8 +37,13 @@ int umr_scan_asic(struct umr_asic *asic, char *asicname, char *ipname, char *reg if (!ipname[0] || !strcmp(ipname, asic->blocks[i]->ipname)) { if (asic->blocks[i]->grant) { r = asic->blocks[i]->grant(asic); - if (r) + if (r) { + if (ipname[0]) { + fprintf(stderr, "[ERROR] Must specify at least one 'risky' option before scanning specific blocks.\n"); + exit(EXIT_FAILURE); + } continue; + } } for (j = 0; j < asic->blocks[i]->no_regs; j++) { if (!regname[0] || !strcmp(regname, "*") || !strcmp(regname, asic->blocks[i]->regs[j].regname) || diff --git a/src/app/scan_log.c b/src/app/scan_log.c index 3401be9..3610ac6 100644 --- a/src/app/scan_log.c +++ b/src/app/scan_log.c @@ -24,12 +24,46 @@ */ #include "umrapp.h" +#define LIST_SIZE (1UL << 18) + +int umr_create_mmio_accel(struct umr_asic *asic) +{ + int i, j; + + // create flat array of registers + asic->mmio_accel.reglist = calloc(LIST_SIZE, sizeof *asic->mmio_accel.reglist); + asic->mmio_accel.iplist = calloc(LIST_SIZE, sizeof *asic->mmio_accel.iplist); + if (!asic->mmio_accel.reglist || !asic->mmio_accel.iplist) { + free(asic->mmio_accel.iplist); + free(asic->mmio_accel.reglist); + asic->mmio_accel.iplist = NULL; + asic->mmio_accel.reglist = NULL; + return -1; + } + + for (i = 0; i < asic->no_blocks; i++) { + for (j = 0; j < asic->blocks[i]->no_regs; j++) { + if (asic->blocks[i]->regs[j].type == REG_MMIO) { + if (asic->blocks[i]->regs[j].addr >= LIST_SIZE) { + fprintf(stderr, "[BUG] Register address width too large for scan_log\n"); + continue; + } + asic->mmio_accel.reglist[asic->blocks[i]->regs[j].addr] = &asic->blocks[i]->regs[j]; + asic->mmio_accel.iplist[asic->blocks[i]->regs[j].addr] = asic->blocks[i]; + } + } + } + return 0; +} + void umr_scan_log(struct umr_asic *asic) { char line[256], *chr; FILE *f; - int i, j, k, found; + int k, found; unsigned long delta, did, regno, value, write; + struct umr_reg **reglist; + struct umr_ip_block **iplist; f = fopen("/sys/kernel/debug/tracing/trace", "r"); if (!f) { @@ -37,6 +71,15 @@ void umr_scan_log(struct umr_asic *asic) return; } + if (!asic->mmio_accel.reglist) { + if (umr_create_mmio_accel(asic)) { + return; + } + } + + reglist = asic->mmio_accel.reglist; + iplist = asic->mmio_accel.iplist; + while (fgets(line, sizeof(line), f)) { found = 0; delta = 0; @@ -54,32 +97,28 @@ void umr_scan_log(struct umr_asic *asic) if (did == asic->did) { do { - // try to find reg in asic profile - for (i = 0; i < asic->no_blocks; i++) - for (j = 0; j < asic->blocks[i]->no_regs; j++) - if (asic->blocks[i]->regs[j].type == REG_MMIO && - asic->blocks[i]->regs[j].addr == regno) { - // bingo - if (write) - printf("%s.%s.%s +0x%04lx <= 0x%08lx\n", - asic->asicname, asic->blocks[i]->ipname, asic->blocks[i]->regs[j].regname, - (unsigned long)delta, - (unsigned long)value); - else - printf("%s.%s.%s +0x%04lx => 0x%08lx\n", - asic->asicname, asic->blocks[i]->ipname, asic->blocks[i]->regs[j].regname, - (unsigned long)delta, - (unsigned long)value); - if (options.bitfields) - for (k = 0; k < asic->blocks[i]->regs[j].no_bits; k++) { - uint32_t v; - v = (1UL << (asic->blocks[i]->regs[j].bits[k].stop + 1 - asic->blocks[i]->regs[j].bits[k].start)) - 1; - v &= (value >> asic->blocks[i]->regs[j].bits[k].start); - asic->blocks[i]->regs[j].bits[k].bitfield_print(asic, asic->asicname, asic->blocks[i]->ipname, asic->blocks[i]->regs[j].regname, asic->blocks[i]->regs[j].bits[k].regname, asic->blocks[i]->regs[j].bits[k].start, asic->blocks[i]->regs[j].bits[k].stop, v); - } - found = 1; - goto out; - } + if (reglist[regno] != NULL) { + // bingo + if (write) + printf("%s.%s.%s +0x%04lx <= 0x%08lx\n", + asic->asicname, iplist[regno]->ipname, reglist[regno]->regname, + (unsigned long)delta, + (unsigned long)value); + else + printf("%s.%s.%s +0x%04lx => 0x%08lx\n", + asic->asicname, iplist[regno]->ipname, reglist[regno]->regname, + (unsigned long)delta, + (unsigned long)value); + if (options.bitfields) + for (k = 0; k < reglist[regno]->no_bits; k++) { + uint32_t v; + v = (1UL << (reglist[regno]->bits[k].stop + 1 - reglist[regno]->bits[k].start)) - 1; + v &= (value >> reglist[regno]->bits[k].start); + reglist[regno]->bits[k].bitfield_print(asic, asic->asicname, iplist[regno]->ipname, reglist[regno]->regname, reglist[regno]->bits[k].regname, reglist[regno]->bits[k].start, reglist[regno]->bits[k].stop, v); + } + found = 1; + goto out; + } out: regno -= 1; delta += 1; diff --git a/src/app/set_bit.c b/src/app/set_bit.c index bd9ee2b..899bf1a 100644 --- a/src/app/set_bit.c +++ b/src/app/set_bit.c @@ -66,6 +66,7 @@ int umr_set_register_bit(struct umr_asic *asic, char *regpath, char *regvalue) } if (asic->blocks[i]->grant) { if (asic->blocks[i]->grant(asic)) { + fprintf(stderr, "[ERROR] Must specify at least one 'risky' before writing to this block.\n"); return -1; } } diff --git a/src/app/set_reg.c b/src/app/set_reg.c index c3a44b5..8c5060f 100644 --- a/src/app/set_reg.c +++ b/src/app/set_reg.c @@ -63,6 +63,7 @@ int umr_set_register(struct umr_asic *asic, char *regpath, char *regvalue) if (asic->blocks[i]->grant) { if (asic->blocks[i]->grant(asic)) { + fprintf(stderr, "[ERROR] Must specify at least one 'risky' before writing to this block.\n"); return -1; } } diff --git a/src/lib/close_asic.c b/src/lib/close_asic.c index e1d5916..c36bdaa 100644 --- a/src/lib/close_asic.c +++ b/src/lib/close_asic.c @@ -26,9 +26,26 @@ #define cond_close(x) do { if ((x) >= 0) close((x)); } while(0); -void umr_close_asic(struct umr_asic *asic) +void umr_free_asic(struct umr_asic *asic) { int x; + if (asic->pci.mem != NULL) { + // free PCI mapping + pci_device_unmap_range(asic->pci.pdevice, asic->pci.mem, asic->pci.pdevice->regions[asic->pci.region].size); + pci_system_cleanup(); + } + for (x = 0; x < asic->no_blocks; x++) { + free(asic->blocks[x]->regs); + free(asic->blocks[x]); + } + free(asic->blocks); + free(asic->mmio_accel.reglist); + free(asic->mmio_accel.iplist); + free(asic); +} + +void umr_close_asic(struct umr_asic *asic) +{ if (asic) { cond_close(asic->fd.mmio); cond_close(asic->fd.didt); @@ -39,16 +56,6 @@ void umr_close_asic(struct umr_asic *asic) cond_close(asic->fd.vram); cond_close(asic->fd.gpr); cond_close(asic->fd.drm); - if (asic->pci.mem != NULL) { - // free PCI mapping - pci_device_unmap_range(asic->pci.pdevice, asic->pci.mem, asic->pci.pdevice->regions[asic->pci.region].size); - pci_system_cleanup(); - } - for (x = 0; x < asic->no_blocks; x++) { - free(asic->blocks[x]->regs); - free(asic->blocks[x]); - } - free(asic->blocks); - free(asic); + umr_free_asic(asic); } } diff --git a/src/lib/create_mmio_accel.c b/src/lib/create_mmio_accel.c new file mode 100644 index 0000000..08fc8eb --- /dev/null +++ b/src/lib/create_mmio_accel.c @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Tom St Denis <tom.stdenis@amd.com> + * + */ +#include "umr.h" + +#define LIST_SIZE (1UL << 18) + +int umr_create_mmio_accel(struct umr_asic *asic) +{ + int i, j; + + // create flat array of registers + asic->mmio_accel.reglist = calloc(LIST_SIZE, sizeof *asic->mmio_accel.reglist); + asic->mmio_accel.iplist = calloc(LIST_SIZE, sizeof *asic->mmio_accel.iplist); + if (!asic->mmio_accel.reglist || !asic->mmio_accel.iplist) { + free(asic->mmio_accel.iplist); + free(asic->mmio_accel.reglist); + return -1; + } + + for (i = 0; i < asic->no_blocks; i++) { + for (j = 0; j < asic->blocks[i]->no_regs; j++) { + if (asic->blocks[i]->regs[j].type == REG_MMIO) { + if (asic->blocks[i]->regs[j].addr >= LIST_SIZE) { + fprintf(stderr, "[BUG] Register address width too large for scan_log\n"); + continue; + } + asic->mmio_accel.reglist[asic->blocks[i]->regs[j].addr] = &asic->blocks[i]->regs[j]; + asic->mmio_accel.iplist[asic->blocks[i]->regs[j].addr] = asic->blocks[i]; + } + } + } + return 0; +} diff --git a/src/lib/discover.c b/src/lib/discover.c index b58d3cc..52cb96f 100644 --- a/src/lib/discover.c +++ b/src/lib/discover.c @@ -51,8 +51,21 @@ struct umr_asic *umr_discover_asic(struct umr_options *options) FILE *f; unsigned did; struct umr_asic *asic; + long trydid = options->forcedid; - if (options->forcedid < 0) { + // try to scan via debugfs + asic = calloc(1, sizeof *asic); + if (asic) { + asic->instance = options->instance; + asic->options = *options; + umr_scan_config(asic); + if (asic->config.pci.device) + trydid = asic->config.pci.device; + 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"); if (!f) { @@ -93,7 +106,7 @@ struct umr_asic *umr_discover_asic(struct umr_options *options) if (options->dev_name[0]) asic = umr_discover_asic_by_name(options, options->dev_name); else - asic = umr_discover_asic_by_did(options, options->forcedid); + asic = umr_discover_asic_by_did(options, trydid); } if (asic) { diff --git a/src/lib/scan_config.c b/src/lib/scan_config.c index 85865f9..2d9f0f4 100644 --- a/src/lib/scan_config.c +++ b/src/lib/scan_config.c @@ -68,6 +68,15 @@ static void parse_rev2(struct umr_asic *asic, uint32_t *data, int *r) asic->config.gfx.external_rev_id = data[(*r)++]; } +static void parse_rev3(struct umr_asic *asic, uint32_t *data, int *r) +{ + parse_rev2(asic, data, r); + asic->config.pci.device = data[(*r)++]; + asic->config.pci.revision = data[(*r)++]; + asic->config.pci.subsystem_device = data[(*r)++]; + asic->config.pci.subsystem_vendor = data[(*r)++]; +} + void umr_scan_config(struct umr_asic *asic) { uint32_t data[512]; @@ -106,6 +115,8 @@ gca_config: break; case 2: parse_rev2(asic, data, &r); break; + case 3: parse_rev3(asic, data, &r); + break; default: printf("Invalid gca config data header\n"); } @@ -122,6 +122,13 @@ struct umr_gfx_config { unsigned external_rev_id; }; +struct umr_pci_config { + unsigned device; + unsigned revision; + unsigned subsystem_device; + unsigned subsystem_vendor; +}; + struct umr_fw_config { char name[16]; uint32_t feature_version, @@ -165,6 +172,7 @@ struct umr_asic { struct { struct umr_gfx_config gfx; struct umr_fw_config fw[UMR_MAX_FW]; + struct umr_pci_config pci; } config; struct { int mmio, @@ -183,6 +191,10 @@ struct umr_asic { int region; } pci; struct umr_options options; + struct { + struct umr_ip_block **iplist; + struct umr_reg **reglist; + } mmio_accel; }; struct umr_wave_status { @@ -387,7 +399,8 @@ struct umr_asic *umr_create_verde(struct umr_options *options); struct umr_asic *umr_discover_asic(struct umr_options *options); struct umr_asic *umr_discover_asic_by_did(struct umr_options *options, long did); struct umr_asic *umr_discover_asic_by_name(struct umr_options *options, char *name); -void umr_close_asic(struct umr_asic *asic); +void umr_free_asic(struct umr_asic *asic); +void umr_close_asic(struct umr_asic *asic); // call this to close a fully open asic int umr_query_drm(struct umr_asic *asic, int field, uint64_t *ret); void umr_enumerate_devices(void); @@ -405,6 +418,7 @@ uint32_t umr_read_reg_by_name(struct umr_asic *asic, char *name); int umr_write_reg_by_name(struct umr_asic *asic, char *name, uint32_t value); uint32_t umr_bitslice_reg(struct umr_asic *asic, struct umr_reg *reg, char *bitname, uint32_t regvalue); uint32_t umr_bitslice_reg_by_name(struct umr_asic *asic, char *regname, char *bitname, uint32_t regvalue); +int umr_create_mmio_accel(struct umr_asic *asic); /* IB/ring decoding/dumping/etc */ void umr_print_decode(struct umr_asic *asic, struct umr_ring_decoder *decoder, uint32_t ib); |