This is meant for NPI support only as publicly released designs can simply add to the static definitions. This is used by using the --force (-f) option with a filename that has a @ prefixed on, e.g. umr -O bits -f @demo/npi/newchip -lr gfx10 Will read the file 'newchip' and import the ip/reg/bit definitions and then can proceed as normal producing this output: [WARNING]: Should use --pci when using create_asic_from_script() new_chip.gfx10.mmSUPER_SECRET => 0x12345670 new_chip.gfx10.mmSUPER_SECRET.enable[0:0] You will need to use --pci to specify a precise device otherwise it won't be able to talk to it. Signed-off-by: Tom St Denis <tom.stdenis at amd.com> (v2): Added fakerizo demo and updated PCI detection logic to be more robust --- demo/npi/README | 2 + demo/npi/fakerizo | 26 ++++ demo/npi/new_chip | 2 + src/app/main.c | 1 + src/lib/CMakeLists.txt | 1 + src/lib/create_asic_from_script.c | 286 ++++++++++++++++++++++++++++++++++++++ src/lib/discover.c | 18 ++- src/lib/discover_by_name.c | 3 + src/umr.h | 3 + 9 files changed, 338 insertions(+), 4 deletions(-) create mode 100644 demo/npi/README create mode 100644 demo/npi/fakerizo create mode 100644 demo/npi/new_chip create mode 100644 src/lib/create_asic_from_script.c diff --git a/demo/npi/README b/demo/npi/README new file mode 100644 index 000000000000..4ada3e57a0f1 --- /dev/null +++ b/demo/npi/README @@ -0,0 +1,2 @@ +Added fakerizo which is a "fake" Carrizo so I could test the new +PCI detection logic which should be somewhat more future proof. diff --git a/demo/npi/fakerizo b/demo/npi/fakerizo new file mode 100644 index 000000000000..8ec3a18f7c57 --- /dev/null +++ b/demo/npi/fakerizo @@ -0,0 +1,26 @@ +reg gfx80 mmGRBM_STATUS mmio 0x801 +bit gfx80 mmGRBM_STATUS ME0PIPE0_CMDFIFO_AVAIL 0 3 +bit gfx80 mmGRBM_STATUS SRBM_RQ_PENDING 5 5 +bit gfx80 mmGRBM_STATUS ME0PIPE0_CF_RQ_PENDING 7 7 +bit gfx80 mmGRBM_STATUS ME0PIPE0_PF_RQ_PENDING 8 8 +bit gfx80 mmGRBM_STATUS GDS_DMA_RQ_PENDING 9 9 +bit gfx80 mmGRBM_STATUS DB_CLEAN 12 12 +bit gfx80 mmGRBM_STATUS CB_CLEAN 13 13 +bit gfx80 mmGRBM_STATUS TA_BUSY 14 14 +bit gfx80 mmGRBM_STATUS GDS_BUSY 15 15 +bit gfx80 mmGRBM_STATUS WD_BUSY_NO_DMA 16 16 +bit gfx80 mmGRBM_STATUS VGT_BUSY 17 17 +bit gfx80 mmGRBM_STATUS IA_BUSY_NO_DMA 18 18 +bit gfx80 mmGRBM_STATUS IA_BUSY 19 19 +bit gfx80 mmGRBM_STATUS SX_BUSY 20 20 +bit gfx80 mmGRBM_STATUS WD_BUSY 21 21 +bit gfx80 mmGRBM_STATUS SPI_BUSY 22 22 +bit gfx80 mmGRBM_STATUS BCI_BUSY 23 23 +bit gfx80 mmGRBM_STATUS SC_BUSY 24 24 +bit gfx80 mmGRBM_STATUS PA_BUSY 25 25 +bit gfx80 mmGRBM_STATUS DB_BUSY 26 26 +bit gfx80 mmGRBM_STATUS CP_COHERENCY_BUSY 28 28 +bit gfx80 mmGRBM_STATUS CP_BUSY 29 29 +bit gfx80 mmGRBM_STATUS CB_BUSY 30 30 +bit gfx80 mmGRBM_STATUS GUI_ACTIVE 31 31 + diff --git a/demo/npi/new_chip b/demo/npi/new_chip new file mode 100644 index 000000000000..deb4148b12d6 --- /dev/null +++ b/demo/npi/new_chip @@ -0,0 +1,2 @@ +reg gfx10 mmSUPER_SECRET mmio 0x12345670 +bit gfx10 mmSUPER_SECRET enable 0 0 diff --git a/src/app/main.c b/src/app/main.c index ac3c25e2937e..4fc26510be32 100644 --- a/src/app/main.c +++ b/src/app/main.c @@ -178,6 +178,7 @@ int main(int argc, char **argv) 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) { + options.use_pci = 1; // implied by the --pci option ++i; } else { printf("--pci requires domain:bus:slot.function\n"); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index dfdf44cf4ad2..217ae80cdfd7 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(umrcore STATIC bitfield_print.c close_asic.c create_asic_helper.c + create_asic_from_script.c create_mmio_accel.c discover_by_did.c discover_by_name.c diff --git a/src/lib/create_asic_from_script.c b/src/lib/create_asic_from_script.c new file mode 100644 index 000000000000..34c77870ec1c --- /dev/null +++ b/src/lib/create_asic_from_script.c @@ -0,0 +1,286 @@ +/* + * 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 at amd.com> + * + */ +#include "umr.h" + +static void skip_whitespace(char **t) +{ + while (*t[0] == ' ' || *t[0] == '\t' || + *t[0] == '\n' || *t[0] == '\r') + ++*t; +} + +static void grab_word(char *dst, char **t) +{ + skip_whitespace(t); + while (*t[0] && !(*t[0] == ' ' || *t[0] == '\t' || + *t[0] == '\n' || *t[0] == '\r')) { + *dst++ = *t[0]; + ++*t; + } + *dst = 0; +} + +static int add_reg(struct umr_asic *asic, char **t) +{ + char ipname[512], regname[512], type[512], offset[512]; + int i, j, itype; + uint64_t addr; + void *tmp; + + memset(ipname, 0, sizeof ipname); + memset(regname, 0, sizeof regname); + memset(type, 0, sizeof type); + memset(offset, 0, sizeof offset); + grab_word(ipname, t); + grab_word(regname, t); + grab_word(type, t); + grab_word(offset, t); + + // convert type to integer + if (!strcmp(type, "mmio")) { + itype = REG_MMIO; + } else if (!strcmp(type, "smc")) { + itype = REG_SMC; + } else if (!strcmp(type, "didt")) { + itype = REG_DIDT; + } else if (!strcmp(type, "pcie")) { + itype = REG_PCIE; + } else { + fprintf(stderr, "[ERROR]: Invalid register type <%s>\n", type); + return -1; + } + + // read address + if (!sscanf(offset, "%"SCNx64, &addr)) { + fprintf(stderr, "[ERROR]: Error parsing register address <%s>\n", offset); + return -1; + } + + // find ip block in asic + for (j = -1, i = 0; i < asic->no_blocks; i++) { + if (!strcmp(asic->blocks[i]->ipname, ipname)) { + j = i; + break; + } + } + + // if ip block doesn't exist let's add it + if (j == -1) { + // grow ip array if necessary + if (!(asic->no_blocks & 15)) { + tmp = realloc(asic->blocks, (asic->no_blocks + 16) * sizeof(asic->blocks[0])); + if (!tmp) + goto out_of_mem; + asic->blocks = tmp; + memset(&asic->blocks[asic->no_blocks], 0, 16 * sizeof(asic->blocks[0])); + } + + // allocate ip block and populate with basics + j = asic->no_blocks++; + asic->blocks[j] = calloc(1, sizeof(struct umr_ip_block)); + if (!asic->blocks[j] || !(asic->blocks[j]->ipname = strdup(ipname))) + goto out_of_mem; + } + + // j => ip block index. + // now add register + // grow if necessary + if (!(asic->blocks[j]->no_regs & 31)) { + tmp = realloc(asic->blocks[j]->regs, (asic->blocks[j]->no_regs + 32) * sizeof(asic->blocks[j]->regs[0])); + if (!tmp) + goto out_of_mem; + asic->blocks[j]->regs = tmp; + memset(&asic->blocks[j]->regs[asic->blocks[j]->no_regs], 0, 32 * sizeof(struct umr_reg)); + } + + i = asic->blocks[j]->no_regs++; + asic->blocks[j]->regs[i].addr = addr; + if (!(asic->blocks[j]->regs[i].regname = strdup(regname))) + goto out_of_mem; + asic->blocks[j]->regs[i].type = itype; + return 0; + +out_of_mem: + fprintf(stderr, "[ERROR]: Out of memory\n"); + return -1; +} + +static int add_bit(struct umr_asic *asic, char **t) +{ + char ipname[512], regname[512], bitname[512], start[512], stop[512]; + int i, j, k, istart, istop; + + memset(ipname, 0, sizeof ipname); + memset(regname, 0, sizeof regname); + memset(bitname, 0, sizeof bitname); + memset(start, 0, sizeof start); + memset(stop, 0, sizeof stop); + grab_word(ipname, t); + grab_word(regname, t); + grab_word(bitname, t); + grab_word(start, t); + grab_word(stop, t); + + // parse start/stop + if (!sscanf(start, "%d", &istart) || !sscanf(stop, "%d", &istop)) { + fprintf(stderr, "[ERROR]: Error parsing start/stop values\n"); + return -1; + } + + // find ip block + for (j = -1, i = 0; i < asic->no_blocks; i++) { + if (!strcmp(asic->blocks[i]->ipname, ipname)) { + j = i; + break; + } + } + i = j; + + if (i == -1) { + fprintf(stderr, "[ERROR]: Cannot add bit to IP block that is not defined\n"); + return -1; + } + + // find reg + for (k = -1, j = 0; j < asic->blocks[i]->no_regs; j++) { + if (!strcmp(asic->blocks[i]->regs[j].regname, regname)) { + k = j; + break; + } + } + j = k; + + if (j == -1) { + fprintf(stderr, "[ERROR]: Cannot add bit to register that is not defined\n"); + return -1; + } + + // allocate bit array if needed + if (!asic->blocks[i]->regs[j].no_bits) { + asic->blocks[i]->regs[j].bits = calloc(32, sizeof(struct umr_bitfield)); + if (!asic->blocks[i]->regs[j].bits) + goto out_of_mem; + } + + // add bit + k = asic->blocks[i]->regs[j].no_bits++; + if (!(asic->blocks[i]->regs[j].bits[k].regname = strdup(bitname))) + goto out_of_mem; + asic->blocks[i]->regs[j].bits[k].start = istart; + asic->blocks[i]->regs[j].bits[k].stop = istop; + asic->blocks[i]->regs[j].bits[k].bitfield_print = umr_bitfield_default; + + return 0; +out_of_mem: + fprintf(stderr, "[ERROR]: Out of memory\n"); + return -1; +} + + +// create an asic from a script with multiples of the following lines +// reg ${ipname} ${regname} ${type} ${addr} +// bit ${ipname} ${regname} ${bitname} ${start} ${stop} +// +// for soc15 devices you need to compute the linear offset for the register +// for that particular ASIC. +struct umr_asic *umr_create_asic_from_script(struct umr_options *options, char *name) +{ + struct umr_asic *asic; + char *txt, line[512]; + FILE *f; + int lineno = 1, i, j, k; + + if (!options->use_pci) + fprintf(stderr, "[WARNING]: Should use --pci when using create_asic_from_script()\n"); + + f = fopen(name, "r"); + if (!f) { + perror("Cannot open script file"); + return NULL; + } + + txt = name + strlen(name) - 1; + // walk back to start or first + while (txt != name) { + if (*txt == '/') { + ++txt; + break; + } + --txt; + } + + asic = calloc(1, sizeof *asic); + if (!asic || !(asic->asicname = strdup(txt))) { + fprintf(stderr, "[ERROR]: Out of memory\n"); + free(asic); + fclose(f); + return NULL; + } + asic->options = *options; + asic->family = FAMILY_NPI; + + while (fgets(line, sizeof(line)-1, f) != NULL) { + txt = &line[0]; + skip_whitespace(&txt); + if (!memcmp(txt, "reg", 3)) { + txt += 3; + if (add_reg(asic, &txt)) { + fprintf(stderr, "[ERROR]: Error adding register\n"); + goto error; + } + } else if (!memcmp(txt, "bit", 3)) { + txt += 3; + if (add_bit(asic, &txt)) { + fprintf(stderr, "[ERROR]: Error adding bit definition\n"); + goto error; + } + } else if (txt[0]) { + fprintf(stderr, "[ERROR]: Invalid script command <%s>\n", txt); + goto error; + } + ++lineno; + } + fclose(f); + return asic; +error: + fprintf(stderr, "[ERROR]: Parser error on line %d:\n\t\t%s\n", lineno, line); + fclose(f); + for (i = 0; i < asic->no_blocks; i++) { + for (j = 0; j < asic->blocks[i]->no_regs; j++) { + for (k = 0; k < asic->blocks[i]->regs[j].no_bits; k++) + free(asic->blocks[i]->regs[j].bits[k].regname); + free(asic->blocks[i]->regs[j].bits); + free(asic->blocks[i]->regs[j].regname); + } + free(asic->blocks[i]->regs); + free(asic->blocks[i]->ipname); + free(asic->blocks[i]); + } + free(asic->blocks); + free(asic->asicname); + free(asic); + + return NULL; +} diff --git a/src/lib/discover.c b/src/lib/discover.c index 5a7bfa4e6dac..0c4ee1c09ad8 100644 --- a/src/lib/discover.c +++ b/src/lib/discover.c @@ -101,6 +101,7 @@ struct umr_asic *umr_discover_asic(struct umr_options *options) unsigned did; struct umr_asic *asic; long trydid = options->forcedid; + int busmatch = 0; // Try to map to instance if we have a specific pci device if (options->pci.domain || options->pci.bus || @@ -254,8 +255,14 @@ struct umr_asic *umr_discover_asic(struct umr_options *options) options->pci.func != asic->pci.pdevice->func)) { asic->pci.pdevice = pci_device_next(pci_iter); } + + // indicate we found an exact match for the pci bus/slot + // this is used because NPI use cases won't have names to + // match against in is_did_match() + if (asic->pci.pdevice) + busmatch = 1; } - } while (asic->pci.pdevice && !(asic->pci.pdevice->vendor_id == 0x1002 && is_did_match(asic, asic->pci.pdevice->device_id))); + } while (asic->pci.pdevice && !(busmatch || (asic->pci.pdevice->vendor_id == 0x1002 && is_did_match(asic, asic->pci.pdevice->device_id)))); if (!asic->pci.pdevice) { fprintf(stderr, "[ERROR]: Could not find ASIC with DID of %04lx\n", (unsigned long)asic->did); @@ -282,11 +289,14 @@ struct umr_asic *umr_discover_asic(struct umr_options *options) } } - // scan for a 256K/512K region + // scan for a region 256K <= X <= 1024K which is 32-bit, non IO, non prefetchable if (use_region == 6) { for (use_region = 0; use_region < 6; use_region++) - if ((asic->family < FAMILY_AI && asic->pci.pdevice->regions[use_region].size == (256UL * 1024)) || - (asic->family >= FAMILY_AI && asic->pci.pdevice->regions[use_region].size == (512UL * 1024))) + if (asic->pci.pdevice->regions[use_region].is_64 == 0 && + asic->pci.pdevice->regions[use_region].is_prefetchable == 0 && + asic->pci.pdevice->regions[use_region].is_IO == 0 && + asic->pci.pdevice->regions[use_region].size >= (256UL * 1024) && + asic->pci.pdevice->regions[use_region].size <= (1024UL * 1024)) break; } diff --git a/src/lib/discover_by_name.c b/src/lib/discover_by_name.c index ffeffcc72369..4570929ef759 100644 --- a/src/lib/discover_by_name.c +++ b/src/lib/discover_by_name.c @@ -55,6 +55,9 @@ struct umr_asic *umr_discover_asic_by_name(struct umr_options *options, char *na unsigned x; struct umr_asic *asic, *tmp; + if (name[0] == '@') + return umr_create_asic_from_script(options, name + 1); + asic = NULL; for (x = 0; x < (sizeof(devices)/sizeof(devices[0])); x++) if (!strcmp(devices[x].name, name)) diff --git a/src/umr.h b/src/umr.h index f3d359172d03..265deec7eb68 100644 --- a/src/umr.h +++ b/src/umr.h @@ -55,6 +55,8 @@ enum chipfamily { FAMILY_VI, FAMILY_AI, FAMILY_RV, + + FAMILY_NPI, // reserves for new devices that are not public yet }; enum regclass { @@ -428,6 +430,7 @@ struct umr_ip_block *umr_create_bif51(struct umr_options *options); /* asic constructors */ struct umr_asic *umr_create_asic_helper(char *name, int family, ...); +struct umr_asic *umr_create_asic_from_script(struct umr_options *options, char *name); struct umr_asic *umr_create_bonaire(struct umr_options *options); struct umr_asic *umr_create_carrizo(struct umr_options *options); struct umr_asic *umr_create_fiji(struct umr_options *options); -- 2.12.0