This flag allows umr to perform some operations it would normally need the kernel for in userspace. This is useful if the kernel driver is misbehaving. Don't use this on a healthy system as it could invoke race conditions. This flag enables userland activities such as - reading/writing MMIO registers (with bank selection) - reading wave status and SGPR registers Signed-off-by: Tom St Denis <tom.stdenis at amd.com> --- doc/umr.1 | 5 +++ src/app/main.c | 5 ++- src/app/scan.c | 6 +++- src/app/set_bit.c | 4 +++ src/app/set_reg.c | 4 +++ src/lib/discover.c | 49 +++++++++++++++++---------- src/lib/mmio.c | 57 ++++++++++++++++++++++++++++++- src/lib/read_sgpr.c | 58 +++++++++++++++++++++++++------- src/lib/wave_status.c | 92 ++++++++++++++++++++++++++++++++++++++++++--------- src/umr.h | 23 +++++++++++-- 10 files changed, 252 insertions(+), 51 deletions(-) diff --git a/doc/umr.1 b/doc/umr.1 index 90be2d6316ce..50ce03330b5c 100644 --- a/doc/umr.1 +++ b/doc/umr.1 @@ -138,6 +138,11 @@ separated strings. Enable colour output for --top command, scales from blue, green, yellow, to red. Also accepted is 'use_color'. +.B no_kernel + Disable using kernel files to access the device. Implies ''use_pci''. This is meant to + be used only if the KMD is hung or otherwise not working correctly. Using it on live systems + may result in race conditions. + .SH "Notes" - The "Waves" field in the DRM section of --top only works if GFX PG has been disabled. Otherwise, diff --git a/src/app/main.c b/src/app/main.c index 96a790cbec7c..1d9ef9edceb8 100644 --- a/src/app/main.c +++ b/src/app/main.c @@ -109,6 +109,9 @@ static void parse_options(char *str) options.quiet = 1; } else if (!strcmp(option, "follow_ib")) { options.follow_ib = 1; + } else if (!strcmp(option, "no_kernel")) { + options.no_kernel = 1; + options.use_pci = 1; } else { printf("error: Unknown option [%s]\n", option); exit(EXIT_FAILURE); @@ -413,7 +416,7 @@ int main(int argc, char **argv) "\n\t\tRead 'size' bytes (in hex) from a given address (in hex) to stdout. Optionally" "\n\t\tspecify the VMID (in decimal) treating the address as a virtual address instead.\n" "\n\t--option -O <string>[,<string>,...]\n\t\tEnable various flags: risky, bits, bitsfull, empty_log, follow, named, many," - "\n\t\tuse_pci, use_colour, read_smc, quiet.\n" + "\n\t\tuse_pci, use_colour, read_smc, quiet, no_kernel.\n" "\n\n", UMR_BUILD_VER, UMR_BUILD_REV); exit(EXIT_SUCCESS); } else { diff --git a/src/app/scan.c b/src/app/scan.c index e91fbd4649c8..3320509f8be2 100644 --- a/src/app/scan.c +++ b/src/app/scan.c @@ -88,7 +88,11 @@ int umr_scan_asic(struct umr_asic *asic, char *asicname, char *ipname, char *reg goto error; } } else if (asic->blocks[i]->regs[j].type == REG_MMIO) { - asic->blocks[i]->regs[j].value = asic->pci.mem[asic->blocks[i]->regs[j].addr]; + if (options.use_bank && options.no_kernel) + umr_grbm_select_index(asic, options.se_bank, options.sh_bank, options.instance_bank); + asic->blocks[i]->regs[j].value = umr_read_reg(asic, asic->blocks[i]->regs[j].addr * 4); + if (options.use_bank && options.no_kernel) + umr_grbm_select_index(asic, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); } if (regname[0]) { if (options.named) diff --git a/src/app/set_bit.c b/src/app/set_bit.c index bed7ee858b6a..49f6c4750b8a 100644 --- a/src/app/set_bit.c +++ b/src/app/set_bit.c @@ -96,9 +96,13 @@ int umr_set_register_bit(struct umr_asic *asic, char *regpath, char *regvalue) } } } else if (asic->blocks[i]->regs[j].type == REG_MMIO) { + if (options.use_bank && options.no_kernel) + umr_grbm_select_index(asic, options.se_bank, options.sh_bank, options.instance_bank); copy = asic->pci.mem[asic->blocks[i]->regs[j].addr] & ~mask; copy |= (value << asic->blocks[i]->regs[j].bits[k].start) & mask; asic->pci.mem[asic->blocks[i]->regs[j].addr] = copy; + if (options.use_bank && options.no_kernel) + umr_grbm_select_index(asic, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); if (!options.quiet) printf("%s <= 0x%08lx\n", regpath, (unsigned long)copy); } return 0; diff --git a/src/app/set_reg.c b/src/app/set_reg.c index ed8f708e977f..acc8228cf421 100644 --- a/src/app/set_reg.c +++ b/src/app/set_reg.c @@ -84,7 +84,11 @@ int umr_set_register(struct umr_asic *asic, char *regpath, char *regvalue) } } } else if (asic->blocks[i]->regs[j].type == REG_MMIO) { + if (options.use_bank && options.no_kernel) + umr_grbm_select_index(asic, options.se_bank, options.sh_bank, options.instance_bank); asic->pci.mem[asic->blocks[i]->regs[j].addr] = value; + if (options.use_bank && options.no_kernel) + umr_grbm_select_index(asic, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); } return 0; } diff --git a/src/lib/discover.c b/src/lib/discover.c index c9c2f74a4818..5a6d7e47b0c2 100644 --- a/src/lib/discover.c +++ b/src/lib/discover.c @@ -111,24 +111,37 @@ struct umr_asic *umr_discover_asic(struct umr_options *options) if (asic) { memcpy(&asic->options, options, sizeof(*options)); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs", asic->instance); - asic->fd.mmio = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs_didt", asic->instance); - asic->fd.didt = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs_pcie", asic->instance); - asic->fd.pcie = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs_smc", asic->instance); - asic->fd.smc = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_sensors", asic->instance); - asic->fd.sensors = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_wave", asic->instance); - asic->fd.wave = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_vram", asic->instance); - asic->fd.vram = open(fname, O_RDWR); - snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_gpr", asic->instance); - asic->fd.gpr = open(fname, O_RDWR); - asic->fd.drm = -1; // default to closed - // if appending to the fd list remember to update close_asic() and discover_by_did()... + if (!asic->options.no_kernel) { + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs", asic->instance); + asic->fd.mmio = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs_didt", asic->instance); + asic->fd.didt = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs_pcie", asic->instance); + asic->fd.pcie = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_regs_smc", asic->instance); + asic->fd.smc = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_sensors", asic->instance); + asic->fd.sensors = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_wave", asic->instance); + asic->fd.wave = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_vram", asic->instance); + asic->fd.vram = open(fname, O_RDWR); + snprintf(fname, sizeof(fname)-1, "/sys/kernel/debug/dri/%d/amdgpu_gpr", asic->instance); + asic->fd.gpr = open(fname, O_RDWR); + asic->fd.drm = -1; // default to closed + // if appending to the fd list remember to update close_asic() and discover_by_did()... + } else { + // no files open! + asic->fd.mmio = -1; + asic->fd.didt = -1; + asic->fd.pcie = -1; + asic->fd.smc = -1; + asic->fd.sensors = -1; + asic->fd.wave = -1; + asic->fd.vram = -1; + asic->fd.gpr = -1; + asic->fd.drm = -1; + } if (options->use_pci) { // init PCI mapping diff --git a/src/lib/mmio.c b/src/lib/mmio.c index 5d7cdd3191a1..ca812817e018 100644 --- a/src/lib/mmio.c +++ b/src/lib/mmio.c @@ -85,9 +85,64 @@ uint32_t umr_bitslice_reg(struct umr_asic *asic, struct umr_reg *reg, char *bitn return 0; } +uint32_t umr_bitslice_compose_value(struct umr_asic *asic, struct umr_reg *reg, char *bitname, uint32_t regvalue) +{ + int i; + for (i = 0; i < reg->no_bits; i++) { + if (!strcmp(bitname, reg->bits[i].regname)) { + regvalue &= (1UL << (reg->bits[i].stop - reg->bits[i].start + 1)) - 1; + regvalue <<= reg->bits[i].start; + return regvalue; + } + } + fprintf(stderr, "BUG: Bitfield [%s] not found in reg [%s] on asic [%s]\n", bitname, reg->regname, asic->asicname); + return 0; +} + uint32_t umr_bitslice_reg_by_name(struct umr_asic *asic, char *regname, char *bitname, uint32_t regvalue) { struct umr_reg *reg; reg = umr_find_reg_data(asic, regname); - return umr_bitslice_reg(asic, reg, bitname, regvalue); + if (reg) + return umr_bitslice_reg(asic, reg, bitname, regvalue); + else + return 0; +} + +uint32_t umr_bitslice_compose_value_by_name(struct umr_asic *asic, char *regname, char *bitname, uint32_t regvalue) +{ + struct umr_reg *reg; + reg = umr_find_reg_data(asic, regname); + if (reg) + return umr_bitslice_compose_value(asic, reg, bitname, regvalue); + else + return 0; +} + +int umr_grbm_select_index(struct umr_asic *asic, uint32_t se, uint32_t sh, uint32_t instance) +{ + struct umr_reg *grbm_idx; + uint32_t data = 0; + + grbm_idx = umr_find_reg_data(asic, "mmGRBM_GFX_INDEX"); + if (grbm_idx) { + if (instance == 0xFFFFFFFF) { + data |= umr_bitslice_compose_value(asic, grbm_idx, "INSTANCE_BROADCAST_WRITES", 1); + } else { + data |= umr_bitslice_compose_value(asic, grbm_idx, "INSTANCE_INDEX", instance); + } + if (se == 0xFFFFFFFF) { + data |= umr_bitslice_compose_value(asic, grbm_idx, "SE_BROADCAST_WRITES", 1); + } else { + data |= umr_bitslice_compose_value(asic, grbm_idx, "SE_INDEX", instance); + } + if (sh == 0xFFFFFFFF) { + data |= umr_bitslice_compose_value(asic, grbm_idx, "SH_BROADCAST_WRITES", 1); + } else { + data |= umr_bitslice_compose_value(asic, grbm_idx, "SH_INDEX", instance); + } + return umr_write_reg(asic, grbm_idx->addr * 4, data); + } else { + return -1; + } } diff --git a/src/lib/read_sgpr.c b/src/lib/read_sgpr.c index f12983edcb04..8f799175b7ff 100644 --- a/src/lib/read_sgpr.c +++ b/src/lib/read_sgpr.c @@ -24,6 +24,33 @@ */ #include "umr.h" +static void wave_read_regs_via_mmio(struct umr_asic *asic, uint32_t simd, + uint32_t wave, uint32_t thread, + uint32_t regno, uint32_t num, uint32_t *out) +{ + struct umr_reg *ind_index, *ind_data; + uint32_t data; + + ind_index = umr_find_reg_data(asic, "mmSQ_IND_INDEX"); + ind_data = umr_find_reg_data(asic, "mmSQ_IND_DATA"); + + if (ind_index && ind_data) { + data = umr_bitslice_compose_value(asic, ind_index, "WAVE_ID", wave); + data |= umr_bitslice_compose_value(asic, ind_index, "SIMD_ID", simd); + data |= umr_bitslice_compose_value(asic, ind_index, "INDEX", regno); + data |= umr_bitslice_compose_value(asic, ind_index, "THREAD_ID", thread); + data |= umr_bitslice_compose_value(asic, ind_index, "FORCE_READ", 1); + data |= umr_bitslice_compose_value(asic, ind_index, "AUTO_INCR", 1); + umr_write_reg(asic, ind_index->addr * 4, data); + while (num--) + *(out++) = umr_read_reg(asic, ind_data->addr * 4); + } else { + fprintf(stderr, "[BUG] The required SQ_IND_{INDEX,DATA} registers are not found on the asic <%s>\n", asic->asicname); + return; + } +} + + int umr_read_sgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t *dst) { uint64_t addr, shift; @@ -33,16 +60,23 @@ int umr_read_sgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t * else shift = 4; // on VI allocations are in 16-dword blocks - addr = - (1ULL << 60) | // reading SGPRs - ((uint64_t)ws->gpr_alloc.sgpr_base << shift) | // starting address to read from - ((uint64_t)ws->hw_id.se_id << 12) | - ((uint64_t)ws->hw_id.sh_id << 20) | - ((uint64_t)ws->hw_id.cu_id << 28) | - ((uint64_t)ws->hw_id.wave_id << 36) | - ((uint64_t)ws->hw_id.simd_id << 44) | - (0ULL << 52); // thread_id - - lseek(asic->fd.gpr, addr, SEEK_SET); - return read(asic->fd.gpr, dst, 4 * ((ws->gpr_alloc.sgpr_size + 1) << shift)); + if (!asic->options.no_kernel) { + addr = + (1ULL << 60) | // reading SGPRs + ((uint64_t)ws->gpr_alloc.sgpr_base << shift) | // starting address to read from + ((uint64_t)ws->hw_id.se_id << 12) | + ((uint64_t)ws->hw_id.sh_id << 20) | + ((uint64_t)ws->hw_id.cu_id << 28) | + ((uint64_t)ws->hw_id.wave_id << 36) | + ((uint64_t)ws->hw_id.simd_id << 44) | + (0ULL << 52); // thread_id + + lseek(asic->fd.gpr, addr, SEEK_SET); + return read(asic->fd.gpr, dst, 4 * ((ws->gpr_alloc.sgpr_size + 1) << shift)); + } else { + umr_grbm_select_index(asic, ws->hw_id.se_id, ws->hw_id.sh_id, ws->hw_id.cu_id); + wave_read_regs_via_mmio(asic, ws->hw_id.simd_id, ws->hw_id.wave_id, ws->gpr_alloc.sgpr_base << shift, 0, (ws->gpr_alloc.sgpr_size + 1) << shift, dst); + umr_grbm_select_index(asic, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + return 0; + } } diff --git a/src/lib/wave_status.c b/src/lib/wave_status.c index 695a1bb836d1..22f92c2caad5 100644 --- a/src/lib/wave_status.c +++ b/src/lib/wave_status.c @@ -49,20 +49,75 @@ static int umr_get_wave_sq_info_vi(struct umr_asic *asic, unsigned se, unsigned return 0; } +static uint32_t wave_read_ind(struct umr_asic *asic, uint32_t simd, uint32_t wave, uint32_t address) +{ + struct umr_reg *ind_index, *ind_data; + uint32_t data; + + ind_index = umr_find_reg_data(asic, "mmSQ_IND_INDEX"); + ind_data = umr_find_reg_data(asic, "mmSQ_IND_DATA"); + + if (ind_index && ind_data) { + data = umr_bitslice_compose_value(asic, ind_index, "WAVE_ID", wave); + data |= umr_bitslice_compose_value(asic, ind_index, "SIMD_ID", simd); + data |= umr_bitslice_compose_value(asic, ind_index, "INDEX", address); + data |= umr_bitslice_compose_value(asic, ind_index, "FORCE_READ", 1); + umr_write_reg(asic, ind_index->addr * 4, data); + return umr_read_reg(asic, ind_data->addr * 4); + } else { + fprintf(stderr, "[BUG] The required SQ_IND_{INDEX,DATA} registers are not found on the asic <%s>\n", asic->asicname); + return -1; + } +} + + +static int read_wave_status_via_mmio(struct umr_asic *asic, uint32_t simd, uint32_t wave, uint32_t *dst, int *no_fields) +{ + /* type 0/1 wave data */ + dst[(*no_fields)++] = (asic->family <= FAMILY_VI) ? 0 : 1; + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_STATUS")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_PC_LO")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_PC_HI")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_EXEC_LO")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_EXEC_HI")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_HW_ID")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_INST_DW0")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_INST_DW1")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_GPR_ALLOC")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_LDS_ALLOC")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_TRAPSTS")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_IB_STS")->addr); + if (asic->family <= FAMILY_VI) { + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_TBA_LO")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_TBA_HI")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_TMA_LO")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_TMA_HI")->addr); + } + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_IB_DBG0")->addr); + dst[(*no_fields)++] = wave_read_ind(asic, simd, wave, umr_find_reg_data(asic, "ixSQ_WAVE_M0")->addr); + + return 0; +} + static int umr_get_wave_status_vi(struct umr_asic *asic, unsigned se, unsigned sh, unsigned cu, unsigned simd, unsigned wave, struct umr_wave_status *ws) { uint32_t x, value, buf[32]; memset(buf, 0, sizeof buf); - lseek(asic->fd.wave, - 0 | - ((uint64_t)se << 7) | - ((uint64_t)sh << 15) | - ((uint64_t)cu << 23) | - ((uint64_t)wave << 31) | - ((uint64_t)simd << 37), SEEK_SET); - read(asic->fd.wave, &buf, 32*4); + if (!asic->options.no_kernel) { + lseek(asic->fd.wave, + 0 | + ((uint64_t)se << 7) | + ((uint64_t)sh << 15) | + ((uint64_t)cu << 23) | + ((uint64_t)wave << 31) | + ((uint64_t)simd << 37), SEEK_SET); + read(asic->fd.wave, &buf, 32*4); + } else { + int n = 0; + read_wave_status_via_mmio(asic, simd, wave, &buf[0], &n); + } if (buf[0] != 0) { fprintf(stderr, "Was expecting type 0 wave data on a CZ/VI part!\n"); @@ -152,14 +207,19 @@ static int umr_get_wave_status_next(struct umr_asic *asic, unsigned se, unsigned memset(buf, 0, sizeof buf); - lseek(asic->fd.wave, - 0 | - ((uint64_t)se << 7) | - ((uint64_t)sh << 15) | - ((uint64_t)cu << 23) | - ((uint64_t)wave << 31) | - ((uint64_t)simd << 37), SEEK_SET); - read(asic->fd.wave, &buf, 32*4); + if (!asic->options.no_kernel) { + lseek(asic->fd.wave, + 0 | + ((uint64_t)se << 7) | + ((uint64_t)sh << 15) | + ((uint64_t)cu << 23) | + ((uint64_t)wave << 31) | + ((uint64_t)simd << 37), SEEK_SET); + read(asic->fd.wave, &buf, 32*4); + } else { + int n = 0; + read_wave_status_via_mmio(asic, simd, wave, &buf[0], &n); + } if (buf[0] != 1) { fprintf(stderr, "Was expecting type 1 wave data on a FAMILY_AI part!\n"); diff --git a/src/umr.h b/src/umr.h index 27d0015d17a3..b0b8fcb4cc72 100644 --- a/src/umr.h +++ b/src/umr.h @@ -171,7 +171,8 @@ struct umr_options { use_colour, read_smc, quiet, - follow_ib; + follow_ib, + no_kernel; unsigned instance_bank, se_bank, @@ -453,15 +454,33 @@ int umr_read_sgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t * int umr_read_sensor(struct umr_asic *asic, int sensor, void *dst, int *size); /* mmio helpers */ +// init the mmio lookup table +int umr_create_mmio_accel(struct umr_asic *asic); + +// find the word address of a register uint32_t umr_find_reg(struct umr_asic *asic, char *regname); + +// find the register data for a register struct umr_reg *umr_find_reg_data(struct umr_asic *asic, char *regname); + +// read/write a 32-bit register given a BYTE address uint32_t umr_read_reg(struct umr_asic *asic, uint64_t addr); int umr_write_reg(struct umr_asic *asic, uint64_t addr, uint32_t value); + +// read/write a register given a name 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); + +// slice a full register into bits (shifted into LSB) 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); + +// compose a 32-bit register with a value and a bitfield +uint32_t umr_bitslice_compose_value(struct umr_asic *asic, struct umr_reg *reg, char *bitname, uint32_t regvalue); +uint32_t umr_bitslice_compose_value_by_name(struct umr_asic *asic, char *reg, char *bitname, uint32_t regvalue); + +// select a GRBM_GFX_IDX +int umr_grbm_select_index(struct umr_asic *asic, uint32_t se, uint32_t sh, uint32_t instance); /* IB/ring decoding/dumping/etc */ void umr_print_decode(struct umr_asic *asic, struct umr_ring_decoder *decoder, uint32_t ib); -- 2.12.0