[igt-dev] [PATCH i-g-t 4/7] tools/xe_reg: Add Xe register read/write tool
Mauro Carvalho Chehab
mauro.chehab at linux.intel.com
Thu Feb 23 11:19:57 UTC 2023
On Tue, 21 Feb 2023 12:46:18 +0100
Zbigniew Kempczyński <zbigniew.kempczynski at intel.com> wrote:
Some description is needed here.
> Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
After adding a patch description, feel free to add:
Acked-by: Mauro Carvalho Chehab <mchehab at kernel.org>
> ---
> tools/meson.build | 1 +
> tools/xe_reg.c | 366 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 367 insertions(+)
> create mode 100644 tools/xe_reg.c
>
> diff --git a/tools/meson.build b/tools/meson.build
> index d2defec8..4c45f16b 100644
> --- a/tools/meson.build
> +++ b/tools/meson.build
> @@ -42,6 +42,7 @@ tools_progs = [
> 'intel_gvtg_test',
> 'dpcd_reg',
> 'lsgpu',
> + 'xe_reg',
> ]
> tool_deps = igt_deps
> tool_deps += zlib
> diff --git a/tools/xe_reg.c b/tools/xe_reg.c
> new file mode 100644
> index 00000000..1f7b384d
> --- /dev/null
> +++ b/tools/xe_reg.c
> @@ -0,0 +1,366 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2021 Intel Corporation
> + */
> +
> +#include "igt.h"
> +#include "igt_device_scan.h"
> +
> +#include "xe_drm.h"
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#define DECL_XE_MMIO_READ_FN(bits) \
> +static inline uint##bits##_t \
> +xe_mmio_read##bits(int fd, uint32_t reg) \
> +{ \
> + struct drm_xe_mmio mmio = { \
> + .addr = reg, \
> + .flags = DRM_XE_MMIO_READ | DRM_XE_MMIO_##bits##BIT, \
> + }; \
> +\
> + igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_MMIO, &mmio), 0); \
> +\
> + return mmio.value;\
> +}\
> +static inline void \
> +xe_mmio_write##bits(int fd, uint32_t reg, uint##bits##_t value) \
> +{ \
> + struct drm_xe_mmio mmio = { \
> + .addr = reg, \
> + .flags = DRM_XE_MMIO_WRITE | DRM_XE_MMIO_##bits##BIT, \
> + .value = value, \
> + }; \
> +\
> + igt_assert_eq(igt_ioctl(fd, DRM_IOCTL_XE_MMIO, &mmio), 0); \
> +}
> +
> +DECL_XE_MMIO_READ_FN(8)
> +DECL_XE_MMIO_READ_FN(16)
> +DECL_XE_MMIO_READ_FN(32)
> +DECL_XE_MMIO_READ_FN(64)
> +
> +static void print_help(FILE *fp)
> +{
> + fprintf(fp, "usage: xe_reg read REG1 [REG2]...\n");
> + fprintf(fp, " xe_reg write REG VALUE\n");
> +}
> +
> +enum ring {
> + RING_UNKNOWN = -1,
> + RING_RCS0,
> + RING_BCS0,
> +};
> +
> +static const struct ring_info {
> + enum ring ring;
> + const char *name;
> + uint32_t mmio_base;
> +} ring_info[] = {
> + {RING_RCS0, "rcs0", 0x02000, },
> + {RING_BCS0, "bcs0", 0x22000, },
> +};
> +
> +static const struct ring_info *ring_info_for_name(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(ring_info); i++)
> + if (strcmp(name, ring_info[i].name) == 0)
> + return &ring_info[i];
> +
> + return NULL;
> +}
> +
> +struct reg_info {
> + const char *name;
> + bool is_ring;
> + uint32_t addr_low;
> + uint32_t addr_high;
> +} reg_info[] = {
> +#define REG32(name, addr) { #name, false, addr }
> +#define REG64(name, low, high) { #name, false, low, high }
> +#define RING_REG32(name, addr) { #name, true, addr }
> +#define RING_REG64(name, low, high) { #name, true, low, high }
> +
> + RING_REG64(ACTHD, 0x74, 0x5c),
> + RING_REG32(BB_ADDR_DIFF, 0x154),
> + RING_REG64(BB_ADDR, 0x140, 0x168),
> + RING_REG32(BB_PER_CTX_PTR, 0x2c0),
> + RING_REG64(EXECLIST_STATUS, 0x234, 0x238),
> + RING_REG64(EXECLIST_SQ0, 0x510, 0x514),
> + RING_REG64(EXECLIST_SQ1, 0x518, 0x51c),
> + RING_REG32(HWS_PGA, 0x80),
> + RING_REG32(INDIRECT_CTX, 0x1C4),
> + RING_REG32(INDIRECT_CTX_OFFSET, 0x1C8),
> + RING_REG32(NOPID, 0x94),
> + RING_REG64(PML4E, 0x270, 0x274),
> + RING_REG32(RING_BUFFER_CTL, 0x3c),
> + RING_REG32(RING_BUFFER_HEAD, 0x34),
> + RING_REG32(RING_BUFFER_START, 0x38),
> + RING_REG32(RING_BUFFER_TAIL, 0x30),
> + RING_REG64(SBB_ADDR, 0x114, 0x11c),
> + RING_REG32(SBB_STATE, 0x118),
> +
> +#undef REG32
> +#undef REG64
> +#undef RING_REG32
> +#undef RING_REG64
> +};
> +
> +static const struct reg_info *reg_info_for_name(const char *name)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(reg_info); i++)
> + if (strcmp(name, reg_info[i].name) == 0)
> + return ®_info[i];
> +
> + return NULL;
> +}
> +
> +static int print_reg_for_info(int xe, FILE *fp, const struct reg_info *reg,
> + const struct ring_info *ring)
> +{
> + if (reg->is_ring) {
> + if (!ring) {
> + fprintf(stderr, "%s is a ring register but --ring "
> + "not set\n", reg->name);
> + return EXIT_FAILURE;
> + }
> +
> + if (reg->addr_high) {
> + uint32_t low = xe_mmio_read32(xe, reg->addr_low +
> + ring->mmio_base);
> + uint32_t high = xe_mmio_read32(xe, reg->addr_high +
> + ring->mmio_base);
> +
> + fprintf(fp, "%s[%s] = 0x%08x %08x\n", reg->name,
> + ring->name, high, low);
> + } else {
> + uint32_t value = xe_mmio_read32(xe, reg->addr_low +
> + ring->mmio_base);
> +
> + fprintf(fp, "%s[%s] = 0x%08x\n", reg->name,
> + ring->name, value);
> + }
> + } else {
> + if (reg->addr_high) {
> + uint32_t low = xe_mmio_read32(xe, reg->addr_low);
> + uint32_t high = xe_mmio_read32(xe, reg->addr_high);
> +
> + fprintf(fp, "%s = 0x%08x %08x\n", reg->name, high, low);
> + } else {
> + uint32_t value = xe_mmio_read32(xe, reg->addr_low);
> +
> + fprintf(fp, "%s = 0x%08x\n", reg->name, value);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void print_reg_for_addr(int xe, FILE *fp, uint32_t addr)
> +{
> + uint32_t value = xe_mmio_read32(xe, addr);
> +
> + fprintf(fp, "MMIO[0x%05x] = 0x%08x\n", addr, value);
> +}
> +
> +enum opt {
> + OPT_UNKNOWN = '?',
> + OPT_END = -1,
> + OPT_DEVICE,
> + OPT_RING,
> + OPT_ALL,
> +};
> +
> +static int read_reg(int argc, char *argv[])
> +{
> + int xe, i, err, index;
> + unsigned long reg_addr;
> + char *endp = NULL;
> + const struct ring_info *ring = NULL;
> + enum opt opt;
> + bool dump_all = false;
> +
> + static struct option options[] = {
> + { "device", required_argument, NULL, OPT_DEVICE },
> + { "ring", required_argument, NULL, OPT_RING },
> + { "all", no_argument, NULL, OPT_ALL },
> + };
> +
> + for (opt = 0; opt != OPT_END; ) {
> + opt = getopt_long(argc, argv, "", options, &index);
> +
> + switch (opt) {
> + case OPT_DEVICE:
> + igt_device_filter_add(optarg);
> + break;
> + case OPT_RING:
> + ring = ring_info_for_name(optarg);
> + if (!ring) {
> + fprintf(stderr, "invalid ring: %s\n", optarg);
> + return EXIT_FAILURE;
> + }
> + break;
> + case OPT_ALL:
> + dump_all = true;
> + break;
> + case OPT_END:
> + break;
> + case OPT_UNKNOWN:
> + return EXIT_FAILURE;
> + }
> + }
> +
> + argc -= optind;
> + argv += optind;
> +
> + xe = drm_open_driver(DRIVER_XE);
> + if (dump_all) {
> + for (i = 0; i < ARRAY_SIZE(reg_info); i++) {
> + if (reg_info[i].is_ring != !!ring)
> + continue;
> +
> + print_reg_for_info(xe, stdout, ®_info[i], ring);
> + }
> + } else {
> + for (i = 0; i < argc; i++) {
> + const struct reg_info *reg = reg_info_for_name(argv[i]);
> + if (reg) {
> + err = print_reg_for_info(xe, stdout, reg, ring);
> + if (err)
> + return err;
> + continue;
> + }
> + reg_addr = strtoul(argv[i], &endp, 16);
> + if (!reg_addr || reg_addr >= (4 << 20) || *endp) {
> + fprintf(stderr, "invalid reg address '%s'\n",
> + argv[i]);
> + return EXIT_FAILURE;
> + }
> + print_reg_for_addr(xe, stdout, reg_addr);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int write_reg_for_info(int xe, const struct reg_info *reg,
> + const struct ring_info *ring,
> + uint64_t value)
> +{
> + if (reg->is_ring) {
> + if (!ring) {
> + fprintf(stderr, "%s is a ring register but --ring "
> + "not set\n", reg->name);
> + return EXIT_FAILURE;
> + }
> +
> + xe_mmio_write32(xe, reg->addr_low + ring->mmio_base, value);
> + if (reg->addr_high) {
> + xe_mmio_write32(xe, reg->addr_high + ring->mmio_base,
> + value >> 32);
> + }
> + } else {
> + xe_mmio_write32(xe, reg->addr_low, value);
> + if (reg->addr_high)
> + xe_mmio_write32(xe, reg->addr_high, value >> 32);
> + }
> +
> + return 0;
> +}
> +
> +static void write_reg_for_addr(int xe, uint32_t addr, uint32_t value)
> +{
> + xe_mmio_write32(xe, addr, value);
> +}
> +
> +static int write_reg(int argc, char *argv[])
> +{
> + int xe, index;
> + unsigned long reg_addr;
> + char *endp = NULL;
> + const struct ring_info *ring = NULL;
> + enum opt opt;
> + const char *reg_name;
> + const struct reg_info *reg;
> + uint64_t value;
> +
> + static struct option options[] = {
> + { "device", required_argument, NULL, OPT_DEVICE },
> + { "ring", required_argument, NULL, OPT_RING },
> + };
> +
> + for (opt = 0; opt != OPT_END; ) {
> + opt = getopt_long(argc, argv, "", options, &index);
> +
> + switch (opt) {
> + case OPT_DEVICE:
> + igt_device_filter_add(optarg);
> + break;
> + case OPT_RING:
> + ring = ring_info_for_name(optarg);
> + if (!ring) {
> + fprintf(stderr, "invalid ring: %s\n", optarg);
> + return EXIT_FAILURE;
> + }
> + break;
> + case OPT_END:
> + break;
> + case OPT_UNKNOWN:
> + return EXIT_FAILURE;
> + default:
> + break;
> + }
> + }
> +
> + argc -= optind;
> + argv += optind;
> +
> + if (argc != 2) {
> + print_help(stderr);
> + return EXIT_FAILURE;
> + }
> +
> + reg_name = argv[0];
> + value = strtoull(argv[1], &endp, 0);
> + if (*endp) {
> + fprintf(stderr, "Invalid register value: %s\n", argv[1]);
> + return EXIT_FAILURE;
> + }
> +
> + xe = drm_open_driver(DRIVER_XE);
> +
> + reg = reg_info_for_name(reg_name);
> + if (reg)
> + return write_reg_for_info(xe, reg, ring, value);
> +
> + reg_addr = strtoul(reg_name, &endp, 16);
> + if (!reg_addr || reg_addr >= (4 << 20) || *endp) {
> + fprintf(stderr, "invalid reg address '%s'\n", reg_name);
> + return EXIT_FAILURE;
> + }
> + write_reg_for_addr(xe, reg_addr, value);
> +
> + return 0;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + if (argc < 2) {
> + print_help(stderr);
> + return EXIT_FAILURE;
> + }
> +
> + if (strcmp(argv[1], "read") == 0)
> + return read_reg(argc - 1, argv + 1);
> + else if (strcmp(argv[1], "write") == 0)
> + return write_reg(argc - 1, argv + 1);
> +
> + fprintf(stderr, "invalid sub-command: %s", argv[1]);
> + return EXIT_FAILURE;
> +}
More information about the igt-dev
mailing list