Creating an ASIC Instance¶
Most libumr API calls require a struct umr_asic instance in order to operate. This structure contains information about the ASIC being used such as which family it belongs to, configuration data, PCI mappings (if any), and pointers to the register database.
Typically, this is accomplished through the following function:
struct umr_asic *umr_discover_asic(struct umr_options *options, umr_err_output errout);
Where the options control how the instance is created. The options are as follows:
struct umr_options {
int forced_instance,
instance,
bitfields,
bitfields_full,
empty_log,
use_bank,
many,
use_pci,
use_colour,
read_smc,
quiet,
no_follow_ib,
no_follow_chained_ib,
no_follow_shader,
no_follow_loadx,
verbose,
show_regs,
halt_waves,
no_kernel,
no_disasm,
disasm_early_term,
use_xgmi,
disasm_anyways,
skip_gprs,
wave64,
full_shader,
context_reg_bank,
no_fold_vm_decode,
pg_lock,
test_log,
vm_partition,
is_virtual,
force_asic_file,
export_model,
vgpr_granularity,
use_v1_regs_debugfs,
trap_unsorted_db,
filter_shader_registers,
use_full_user_queue,
aql_heuristic,
is_devcoredump,
no_backtrace;
// hs/gs shaders can be opaque depending on circumstances on gfx9+ platforms
struct {
int
enable_ps_shader,
enable_vs_shader,
enable_gs_shader,
enable_hs_shader,
enable_es_shader,
enable_ls_shader,
enable_es_ls_swap,
enable_comp_shader;
} shader_enable;
union {
struct {
uint32_t
instance,
se,
sh;
} grbm;
struct {
uint32_t
me,
queue,
pipe,
vmid;
} srbm;
} bank;
long forcedid;
char
*scanblock,
dev_name[64],
hub_name[32],
ring_name[32],
desired_path[256],
database_path[256];
struct umr_pci_addr pci;
struct {
FILE *test_log_fd;
struct umr_test_harness *th;
};
struct {
char **data;
uint32_t n_lines;
/* ring dump. */
int no_ring_dumps;
struct umr_devcoredump_ring_data* ring_dumps;
/* register values. */
int no_registers;
struct devcoredump_reg *registers;
int no_ibs;
struct umr_devcoredump_ib_data* ibs;
} devcoredump;
// is this a rumr client?
int rumr_active;
// user mode queue client support
// this structure has (several) nested structures that represent various sources of information
// ultimately the goal is to connect to a user supply queue to see the command submission and it's contents.
struct umr_user_queue user_queue;
// Optional pre-read raw VM context registers, bound by a caller so repeated
// VM page walks (e.g. dumping many wave shaders) reuse them instead of
// reading the context registers from (possibly remote) MMIO on every
// translation. When active, umr_access_vram_ai() takes the raw registers
// from table[vmid] for gfxhub VMIDs marked in 'valid' and recomputes the
// derived walk parameters locally; misses fall back to a live read.
struct {
int active; // caller enabled prefetch reuse
uint32_t valid; // bitmask of gfxhub VMIDs present in table[]
struct umr_vm_context_registers *table; // caller-owned array[UMR_VM_CTX_BOUND_MAX]
} vm_ctx_bound;
};
Where the following parameters are relevant to creating an ASIC instance:
instance (default: 0)
use_pci (default: 0)
no_kernel (default: 0)
dev_name (default: empty string)
database_path
The
pcistructure (default to all 0, empty string)
The database_path string instructs umr where to search for
IP and SOC15 files. In a default state the function will
attempt to create an ASIC based on the debugfs files found in:
/sys/kernel/debug/dri/0/...
Creating a Virtual Device¶
The first option checked is the dev_name to see if it begins with
a . which indicates a virtual device is desired. For instance:
struct umr_options options;
struct umr_asic *asic;
memset(&options, 0, sizeof options);
strcpy(options.dev_name, ".vega10");
asic = umr_discover_asic(&options, err_printf);
will create a virtual ASIC device for the vega10 ASIC. Virtual
ASICs can only be used with a subset of all supported commands
since no debugfs file handles or PCI mappings are created. The API
uses a callback for error messages that is essentially based on the
printf() format. Here is an example callback:
int err_printf(const char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vfprintf(stderr, fmt, ap);
fflush(stderr);
va_end(ap);
return r;
}
Creating a device based on PCI mapping¶
If the dev_name field does not begin with a . then the discover
function will next see if any one of the ‘pci’ members have a non
zero value. If they do then it will construct the pci.name
field and then search the PCI registry for a device that matches.
If it finds one it will update the instance field to indicate
which instance is being sought.
Note that using these fields does not imply the option use_pci which
must be independently asserted if direct MMIO access is desired.
An example usage is:
struct umr_options options;
struct umr_asic *asic;
memset(&options, 0, sizeof options);
options.pci.domain = 0x0000;
options.pci.bus = 0x00;
options.pci.slot = 0x01;
options.pci.func = 0x00; // look for 0000:00:01.0
asic = umr_discover_asic(&options, err_printf);
Which on an APU system (like a Carrizo) would typically point to the Carrizo GPU.
The following can be added before the call to umr_discover_asic()
to request PCI MMIO access:
options.use_pci = 1;
Using PCI mode with use_pci as well allows access to the device
without a loaded kernel module which is useful for work on NTI
projects. With use_pci set to zero you can bind to a device by
the PCI address while still using debugfs to access the device much the way
the --by-pci command line option works.
Creating a device based on Instance mapping¶
If the dev_name field does not being with a . and all of the
pci fields are zero then discovery of a device based on the
instance field.
An example usage is:
struct umr_options options;
struct umr_asic *asic;
memset(&options, 0, sizeof options);
options.instance = 3; // use the 4'th GPU
asic = umr_discover_asic(&options, err_printf);
Creating a device based on a PCI Device ID¶
If the dev_name field is empty, all of the pci fields are zero,
and the instance value is negative (e.g., -1) then a device can be
created by specifying a value in forcedid field.
An example usage is:
struct umr_options options;
struct umr_asic *asic;
memset(&options, 0, sizeof options);
options.instance = -1;
options.forcedid = 0x9874; // find the first device which is a Carrizo
asic = umr_discover_asic(&options, err_printf);
Further reading¶
To plug in your own register, memory, wave, or ring accessors instead of the default Linux implementations, see ASIC callbacks (MMIO, memory, waves).