Add option to specify engine for register read/write operation.
If engine is specified, use MI_LOAD_REGISTER_IMM and MI_STORE_REGISTER_IMM
to write and read register using a batch targeted at that engine.

v2: no MI_NOOP after BBE (Chris)
v3: use modern engine names (Chris), use global fd
v4: strcasecmp (Chris)
v5: use register definition format for engine (Jani)

Cc: Jani Nikula <jani.nik...@intel.com>
Cc: Chris Wilson <ch...@chris-wilson.co.uk>
CC: Joonas Lahtinen <joonas.lahti...@linux.intel.com>
Signed-off-by: Mika Kuoppala <mika.kuopp...@linux.intel.com>
Reviewed-by: Chris Wilson <ch...@chris-wilson.co.uk> (v4)
---
 man/intel_reg.rst      |   9 ++-
 tools/intel_reg.c      | 169 +++++++++++++++++++++++++++++++++++++++++++++++--
 tools/intel_reg_spec.h |   1 +
 3 files changed, 171 insertions(+), 8 deletions(-)

diff --git a/man/intel_reg.rst b/man/intel_reg.rst
index d1af178a..4ec24c4c 100644
--- a/man/intel_reg.rst
+++ b/man/intel_reg.rst
@@ -103,7 +103,7 @@ Display brief help.
 REGISTER REFERENCES
 ===================
 
-Registers are defined as [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR).
+Registers are defined as 
[(PORTNAME|PORTNUM|ENGINE|MMIO-OFFSET):](REGNAME|REGADDR).
 
 PORTNAME
     The register access method, most often MMIO, which is the default. The
@@ -120,6 +120,13 @@ PORTNUM
     Numbers above 0xff are automatically interpreted as MMIO offsets, not port
     numbers.
 
+ENGINE
+    Instead of cpu based MMIO, specified engine can be used for access method.
+    Batchbuffer will be targeted for the engine to do read/write. The list of
+    available engines is architecture specific and can be found with
+    "intel_reg help". Prefixing engine name with '-' uses non-privileged
+    batchbuffer for access.
+
 MMIO-OFFSET
     Use MMIO, and add this offset to the register address.
 
diff --git a/tools/intel_reg.c b/tools/intel_reg.c
index 00d2a4a1..ddff2794 100644
--- a/tools/intel_reg.c
+++ b/tools/intel_reg.c
@@ -33,6 +33,7 @@
 #include <unistd.h>
 
 #include "igt.h"
+#include "igt_gt.h"
 #include "intel_io.h"
 #include "intel_chipset.h"
 
@@ -73,6 +74,10 @@ struct config {
 
        /* register spec */
        char *specfile;
+
+       /* fd for engine access avoiding reopens */
+       int fd;
+
        struct reg *regs;
        ssize_t regcount;
 
@@ -236,13 +241,130 @@ static void dump_decode(struct config *config, struct 
reg *reg, uint32_t val)
        }
 }
 
+static const struct intel_execution_engine2 *find_engine(const char *name)
+{
+       const struct intel_execution_engine2 *e;
+
+       if (strlen(name) < 2)
+               return NULL;
+
+       if (name[0] == '-')
+               name++;
+
+       for (e = intel_execution_engines2; e->name; e++) {
+               if (!strcasecmp(e->name, name))
+                       return e;
+       }
+
+       return NULL;
+}
+
+static int register_srm(struct config *config, struct reg *reg,
+                       uint32_t *val_in)
+{
+       const int gen = intel_gen(config->devid);
+       const bool r64b = gen >= 8;
+       const uint32_t ctx = 0;
+       struct drm_i915_gem_exec_object2 obj[2];
+       struct drm_i915_gem_relocation_entry reloc[1];
+       struct drm_i915_gem_execbuffer2 execbuf;
+       uint32_t *batch, *r;
+       const struct intel_execution_engine2 *engine;
+       bool secure;
+       int fd, i;
+       uint32_t val;
+
+       if (config->fd == -1) {
+               config->fd = __drm_open_driver(DRIVER_INTEL);
+               if (config->fd == -1) {
+                       fprintf(stderr, "Error opening driver: %s",
+                               strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       fd = config->fd;
+       engine = find_engine(reg->engine);
+       if (engine == NULL)
+               exit(EXIT_FAILURE);
+
+       secure = reg->engine[0] != '-';
+
+       memset(obj, 0, sizeof(obj));
+       obj[0].handle = gem_create(fd, 4096);
+       obj[1].handle = gem_create(fd, 4096);
+       obj[1].relocs_ptr = to_user_pointer(reloc);
+       obj[1].relocation_count = 1;
+
+       batch = gem_mmap__cpu(fd, obj[1].handle, 0, 4096, PROT_WRITE);
+       gem_set_domain(fd, obj[1].handle,
+                      I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+
+       i = 0;
+       if (val_in) {
+               batch[i++] = MI_NOOP;
+               batch[i++] = MI_NOOP;
+
+               batch[i++] = MI_LOAD_REGISTER_IMM;
+               batch[i++] = reg->addr;
+               batch[i++] = *val_in;
+               batch[i++] = MI_NOOP;
+       }
+
+       batch[i++] = 0x24 << 23 | (1 + r64b); /* SRM */
+       batch[i++] = reg->addr;
+       reloc[0].target_handle = obj[0].handle;
+       reloc[0].presumed_offset = obj[0].offset;
+       reloc[0].offset = i * sizeof(uint32_t);
+       reloc[0].delta = 0;
+       reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
+       reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+       batch[i++] = reloc[0].delta;
+       if (r64b)
+               batch[i++] = 0;
+
+       batch[i++] = MI_BATCH_BUFFER_END;
+       munmap(batch, 4096);
+
+       memset(&execbuf, 0, sizeof(execbuf));
+       execbuf.buffers_ptr = to_user_pointer(obj);
+       execbuf.buffer_count = 2;
+       execbuf.flags = gem_class_instance_to_eb_flags(fd,
+                                                      engine->class,
+                                                      engine->instance);
+       if (secure)
+               execbuf.flags |= I915_EXEC_SECURE;
+
+       if (config->verbosity > 0)
+               printf("%s: using %sprivileged batch\n",
+                      engine->name,
+                      secure ? "" : "non-");
+
+       execbuf.rsvd1 = ctx;
+       gem_execbuf(fd, &execbuf);
+       gem_close(fd, obj[1].handle);
+
+       r = gem_mmap__cpu(fd, obj[0].handle, 0, 4096, PROT_READ);
+       gem_set_domain(fd, obj[0].handle, I915_GEM_DOMAIN_CPU, 0);
+
+       val = r[0];
+       munmap(r, 4096);
+
+       gem_close(fd, obj[0].handle);
+
+       return val;
+}
+
 static int read_register(struct config *config, struct reg *reg, uint32_t 
*valp)
 {
        uint32_t val = 0;
 
        switch (reg->port_desc.port) {
        case PORT_MMIO:
-               val = INREG(reg->mmio_offset + reg->addr);
+               if (reg->engine)
+                       val = register_srm(config, reg, NULL);
+               else
+                       val = INREG(reg->mmio_offset + reg->addr);
                break;
        case PORT_PORTIO_VGA:
                iopl(3);
@@ -299,7 +421,11 @@ static int write_register(struct config *config, struct 
reg *reg, uint32_t val)
 
        switch (reg->port_desc.port) {
        case PORT_MMIO:
-               OUTREG(reg->mmio_offset + reg->addr, val);
+               if (reg->engine) {
+                       register_srm(config, reg, &val);
+               } else {
+                       OUTREG(reg->mmio_offset + reg->addr, val);
+               }
                break;
        case PORT_PORTIO_VGA:
                if (val > 0xff) {
@@ -351,7 +477,25 @@ static int write_register(struct config *config, struct 
reg *reg, uint32_t val)
        return ret;
 }
 
-/* s has [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR) */
+static int parse_engine(struct reg *reg, const char *s)
+{
+       const struct intel_execution_engine2 *e;
+
+       e = find_engine(s);
+       if (e) {
+               reg->port_desc.port = PORT_MMIO;
+               reg->port_desc.name = strdup(s);
+               reg->port_desc.stride = 4;
+               reg->engine = strdup(s);
+               reg->mmio_offset = 0;
+       } else {
+               reg->engine = NULL;
+       }
+
+       return reg->engine == NULL;
+}
+
+/* s has [(PORTNAME|PORTNUM|ENGINE|MMIO-OFFSET):](REGNAME|REGADDR) */
 static int parse_reg(struct config *config, struct reg *reg, const char *s)
 {
        unsigned long addr;
@@ -367,7 +511,9 @@ static int parse_reg(struct config *config, struct reg 
*reg, const char *s)
        } else if (p) {
                char *port_name = strndup(s, p - s);
 
-               ret = parse_port_desc(reg, port_name);
+               ret = parse_engine(reg, port_name);
+               if (ret)
+                       ret = parse_port_desc(reg, port_name);
 
                free(port_name);
                p++;
@@ -616,6 +762,7 @@ static const struct command commands[] = {
 
 static int intel_reg_help(struct config *config, int argc, char *argv[])
 {
+       const struct intel_execution_engine2 *e;
        int i;
 
        printf("Intel graphics register multitool\n\n");
@@ -629,14 +776,18 @@ static int intel_reg_help(struct config *config, int 
argc, char *argv[])
 
        printf("\n");
        printf("REGISTER is defined as:\n");
-        printf("  [(PORTNAME|PORTNUM|MMIO-OFFSET):](REGNAME|REGADDR)\n");
+        printf("  
[(PORTNAME|PORTNUM|ENGINE|MMIO-OFFSET):](REGNAME|REGADDR)\n");
 
        printf("\n");
        printf("PORTNAME is one of:\n");
        intel_reg_spec_print_ports();
-       printf("\n");
+       printf("\n\n");
+
+       printf("ENGINE is one of:\n");
+       for (e = intel_execution_engines2; e->name; e++)
+               printf("%s -%s ", e->name, e->name);
+       printf("\n\n");
 
-       printf("\n");
        printf("OPTIONS common to most COMMANDS:\n");
        printf(" --spec=PATH    Read register spec from directory or file\n");
        printf(" --mmio=FILE    Use an MMIO snapshot\n");
@@ -771,6 +922,7 @@ int main(int argc, char *argv[])
        const struct command *command = NULL;
        struct config config = {
                .count = 1,
+               .fd = -1,
        };
        bool help = false;
 
@@ -898,5 +1050,8 @@ int main(int argc, char *argv[])
 
        free(config.mmiofile);
 
+       if (config.fd >= 0)
+               close(config.fd);
+
        return ret;
 }
diff --git a/tools/intel_reg_spec.h b/tools/intel_reg_spec.h
index dcb31430..c94c61ba 100644
--- a/tools/intel_reg_spec.h
+++ b/tools/intel_reg_spec.h
@@ -53,6 +53,7 @@ struct port_desc {
 
 struct reg {
        struct port_desc port_desc;
+       char *engine;
        uint32_t mmio_offset;
        uint32_t addr;
        char *name;
-- 
2.14.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to