linux/drivers/misc/habanalabs/common/state_dump.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Copyright 2021 HabanaLabs, Ltd.
   5 * All Rights Reserved.
   6 */
   7
   8#include <linux/vmalloc.h>
   9#include <uapi/misc/habanalabs.h>
  10#include "habanalabs.h"
  11
  12/**
  13 * hl_format_as_binary - helper function, format an integer as binary
  14 *                       using supplied scratch buffer
  15 * @buf: the buffer to use
  16 * @buf_len: buffer capacity
  17 * @n: number to format
  18 *
  19 * Returns pointer to buffer
  20 */
  21char *hl_format_as_binary(char *buf, size_t buf_len, u32 n)
  22{
  23        int i;
  24        u32 bit;
  25        bool leading0 = true;
  26        char *wrptr = buf;
  27
  28        if (buf_len > 0 && buf_len < 3) {
  29                *wrptr = '\0';
  30                return buf;
  31        }
  32
  33        wrptr[0] = '0';
  34        wrptr[1] = 'b';
  35        wrptr += 2;
  36        /* Remove 3 characters from length for '0b' and '\0' termination */
  37        buf_len -= 3;
  38
  39        for (i = 0; i < sizeof(n) * BITS_PER_BYTE && buf_len; ++i, n <<= 1) {
  40                /* Writing bit calculation in one line would cause a false
  41                 * positive static code analysis error, so splitting.
  42                 */
  43                bit = n & (1 << (sizeof(n) * BITS_PER_BYTE - 1));
  44                bit = !!bit;
  45                leading0 &= !bit;
  46                if (!leading0) {
  47                        *wrptr = '0' + bit;
  48                        ++wrptr;
  49                }
  50        }
  51
  52        *wrptr = '\0';
  53
  54        return buf;
  55}
  56
  57/**
  58 * resize_to_fit - helper function, resize buffer to fit given amount of data
  59 * @buf: destination buffer double pointer
  60 * @size: pointer to the size container
  61 * @desired_size: size the buffer must contain
  62 *
  63 * Returns 0 on success or error code on failure.
  64 * On success, the size of buffer is at least desired_size. Buffer is allocated
  65 * via vmalloc and must be freed with vfree.
  66 */
  67static int resize_to_fit(char **buf, size_t *size, size_t desired_size)
  68{
  69        char *resized_buf;
  70        size_t new_size;
  71
  72        if (*size >= desired_size)
  73                return 0;
  74
  75        /* Not enough space to print all, have to resize */
  76        new_size = max_t(size_t, PAGE_SIZE, round_up(desired_size, PAGE_SIZE));
  77        resized_buf = vmalloc(new_size);
  78        if (!resized_buf)
  79                return -ENOMEM;
  80        memcpy(resized_buf, *buf, *size);
  81        vfree(*buf);
  82        *buf = resized_buf;
  83        *size = new_size;
  84
  85        return 1;
  86}
  87
  88/**
  89 * hl_snprintf_resize() - print formatted data to buffer, resize as needed
  90 * @buf: buffer double pointer, to be written to and resized, must be either
  91 *       NULL or allocated with vmalloc.
  92 * @size: current size of the buffer
  93 * @offset: current offset to write to
  94 * @format: format of the data
  95 *
  96 * This function will write formatted data into the buffer. If buffer is not
  97 * large enough, it will be resized using vmalloc. Size may be modified if the
  98 * buffer was resized, offset will be advanced by the number of bytes written
  99 * not including the terminating character
 100 *
 101 * Returns 0 on success or error code on failure
 102 *
 103 * Note that the buffer has to be manually released using vfree.
 104 */
 105int hl_snprintf_resize(char **buf, size_t *size, size_t *offset,
 106                           const char *format, ...)
 107{
 108        va_list args;
 109        size_t length;
 110        int rc;
 111
 112        if (*buf == NULL && (*size != 0 || *offset != 0))
 113                return -EINVAL;
 114
 115        va_start(args, format);
 116        length = vsnprintf(*buf + *offset, *size - *offset, format, args);
 117        va_end(args);
 118
 119        rc = resize_to_fit(buf, size, *offset + length + 1);
 120        if (rc < 0)
 121                return rc;
 122        else if (rc > 0) {
 123                /* Resize was needed, write again */
 124                va_start(args, format);
 125                length = vsnprintf(*buf + *offset, *size - *offset, format,
 126                                   args);
 127                va_end(args);
 128        }
 129
 130        *offset += length;
 131
 132        return 0;
 133}
 134
 135/**
 136 * hl_sync_engine_to_string - convert engine type enum to string literal
 137 * @engine_type: engine type (TPC/MME/DMA)
 138 *
 139 * Return the resolved string literal
 140 */
 141const char *hl_sync_engine_to_string(enum hl_sync_engine_type engine_type)
 142{
 143        switch (engine_type) {
 144        case ENGINE_DMA:
 145                return "DMA";
 146        case ENGINE_MME:
 147                return "MME";
 148        case ENGINE_TPC:
 149                return "TPC";
 150        }
 151        return "Invalid Engine Type";
 152}
 153
 154/**
 155 * hl_print_resize_sync_engine - helper function, format engine name and ID
 156 * using hl_snprintf_resize
 157 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 158 * @size: pointer to the size container
 159 * @offset: pointer to the offset container
 160 * @engine_type: engine type (TPC/MME/DMA)
 161 * @engine_id: engine numerical id
 162 *
 163 * Returns 0 on success or error code on failure
 164 */
 165static int hl_print_resize_sync_engine(char **buf, size_t *size, size_t *offset,
 166                                enum hl_sync_engine_type engine_type,
 167                                u32 engine_id)
 168{
 169        return hl_snprintf_resize(buf, size, offset, "%s%u",
 170                        hl_sync_engine_to_string(engine_type), engine_id);
 171}
 172
 173/**
 174 * hl_state_dump_get_sync_name - transform sync object id to name if available
 175 * @hdev: pointer to the device
 176 * @sync_id: sync object id
 177 *
 178 * Returns a name literal or NULL if not resolved.
 179 * Note: returning NULL shall not be considered as a failure, as not all
 180 * sync objects are named.
 181 */
 182const char *hl_state_dump_get_sync_name(struct hl_device *hdev, u32 sync_id)
 183{
 184        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 185        struct hl_hw_obj_name_entry *entry;
 186
 187        hash_for_each_possible(sds->so_id_to_str_tb, entry,
 188                                node, sync_id)
 189                if (sync_id == entry->id)
 190                        return entry->name;
 191
 192        return NULL;
 193}
 194
 195/**
 196 * hl_state_dump_get_monitor_name - transform monitor object dump to monitor
 197 * name if available
 198 * @hdev: pointer to the device
 199 * @mon: monitor state dump
 200 *
 201 * Returns a name literal or NULL if not resolved.
 202 * Note: returning NULL shall not be considered as a failure, as not all
 203 * monitors are named.
 204 */
 205const char *hl_state_dump_get_monitor_name(struct hl_device *hdev,
 206                                        struct hl_mon_state_dump *mon)
 207{
 208        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 209        struct hl_hw_obj_name_entry *entry;
 210
 211        hash_for_each_possible(sds->monitor_id_to_str_tb,
 212                                entry, node, mon->id)
 213                if (mon->id == entry->id)
 214                        return entry->name;
 215
 216        return NULL;
 217}
 218
 219/**
 220 * hl_state_dump_free_sync_to_engine_map - free sync object to engine map
 221 * @map: sync object to engine map
 222 *
 223 * Note: generic free implementation, the allocation is implemented per ASIC.
 224 */
 225void hl_state_dump_free_sync_to_engine_map(struct hl_sync_to_engine_map *map)
 226{
 227        struct hl_sync_to_engine_map_entry *entry;
 228        struct hlist_node *tmp_node;
 229        int i;
 230
 231        hash_for_each_safe(map->tb, i, tmp_node, entry, node) {
 232                hash_del(&entry->node);
 233                kfree(entry);
 234        }
 235}
 236
 237/**
 238 * hl_state_dump_get_sync_to_engine - transform sync_id to
 239 * hl_sync_to_engine_map_entry if available for current id
 240 * @map: sync object to engine map
 241 * @sync_id: sync object id
 242 *
 243 * Returns the translation entry if found or NULL if not.
 244 * Note, returned NULL shall not be considered as a failure as the map
 245 * does not cover all possible, it is a best effort sync ids.
 246 */
 247static struct hl_sync_to_engine_map_entry *
 248hl_state_dump_get_sync_to_engine(struct hl_sync_to_engine_map *map, u32 sync_id)
 249{
 250        struct hl_sync_to_engine_map_entry *entry;
 251
 252        hash_for_each_possible(map->tb, entry, node, sync_id)
 253                if (entry->sync_id == sync_id)
 254                        return entry;
 255        return NULL;
 256}
 257
 258/**
 259 * hl_state_dump_read_sync_objects - read sync objects array
 260 * @hdev: pointer to the device
 261 * @index: sync manager block index starting with E_N
 262 *
 263 * Returns array of size SP_SYNC_OBJ_AMOUNT on success or NULL on failure
 264 */
 265static u32 *hl_state_dump_read_sync_objects(struct hl_device *hdev, u32 index)
 266{
 267        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 268        u32 *sync_objects;
 269        s64 base_addr; /* Base addr can be negative */
 270        int i;
 271
 272        base_addr = sds->props[SP_SYNC_OBJ_BASE_ADDR] +
 273                        sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index;
 274
 275        sync_objects = vmalloc(sds->props[SP_SYNC_OBJ_AMOUNT] * sizeof(u32));
 276        if (!sync_objects)
 277                return NULL;
 278
 279        for (i = 0; i < sds->props[SP_SYNC_OBJ_AMOUNT]; ++i)
 280                sync_objects[i] = RREG32(base_addr + i * sizeof(u32));
 281
 282        return sync_objects;
 283}
 284
 285/**
 286 * hl_state_dump_free_sync_objects - free sync objects array allocated by
 287 * hl_state_dump_read_sync_objects
 288 * @sync_objects: sync objects array
 289 */
 290static void hl_state_dump_free_sync_objects(u32 *sync_objects)
 291{
 292        vfree(sync_objects);
 293}
 294
 295
 296/**
 297 * hl_state_dump_print_syncs_single_block - print active sync objects on a
 298 * single block
 299 * @hdev: pointer to the device
 300 * @index: sync manager block index starting with E_N
 301 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 302 * @size: pointer to the size container
 303 * @offset: pointer to the offset container
 304 * @map: sync engines names map
 305 *
 306 * Returns 0 on success or error code on failure
 307 */
 308static int
 309hl_state_dump_print_syncs_single_block(struct hl_device *hdev, u32 index,
 310                                char **buf, size_t *size, size_t *offset,
 311                                struct hl_sync_to_engine_map *map)
 312{
 313        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 314        const char *sync_name;
 315        u32 *sync_objects = NULL;
 316        int rc = 0, i;
 317
 318        if (sds->sync_namager_names) {
 319                rc = hl_snprintf_resize(
 320                        buf, size, offset, "%s\n",
 321                        sds->sync_namager_names[index]);
 322                if (rc)
 323                        goto out;
 324        }
 325
 326        sync_objects = hl_state_dump_read_sync_objects(hdev, index);
 327        if (!sync_objects) {
 328                rc = -ENOMEM;
 329                goto out;
 330        }
 331
 332        for (i = 0; i < sds->props[SP_SYNC_OBJ_AMOUNT]; ++i) {
 333                struct hl_sync_to_engine_map_entry *entry;
 334                u64 sync_object_addr;
 335
 336                if (!sync_objects[i])
 337                        continue;
 338
 339                sync_object_addr = sds->props[SP_SYNC_OBJ_BASE_ADDR] +
 340                                sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index +
 341                                i * sizeof(u32);
 342
 343                rc = hl_snprintf_resize(buf, size, offset, "sync id: %u", i);
 344                if (rc)
 345                        goto free_sync_objects;
 346                sync_name = hl_state_dump_get_sync_name(hdev, i);
 347                if (sync_name) {
 348                        rc = hl_snprintf_resize(buf, size, offset, " %s",
 349                                                sync_name);
 350                        if (rc)
 351                                goto free_sync_objects;
 352                }
 353                rc = hl_snprintf_resize(buf, size, offset, ", value: %u",
 354                                        sync_objects[i]);
 355                if (rc)
 356                        goto free_sync_objects;
 357
 358                /* Append engine string */
 359                entry = hl_state_dump_get_sync_to_engine(map,
 360                        (u32)sync_object_addr);
 361                if (entry) {
 362                        rc = hl_snprintf_resize(buf, size, offset,
 363                                                ", Engine: ");
 364                        if (rc)
 365                                goto free_sync_objects;
 366                        rc = hl_print_resize_sync_engine(buf, size, offset,
 367                                                entry->engine_type,
 368                                                entry->engine_id);
 369                        if (rc)
 370                                goto free_sync_objects;
 371                }
 372
 373                rc = hl_snprintf_resize(buf, size, offset, "\n");
 374                if (rc)
 375                        goto free_sync_objects;
 376        }
 377
 378free_sync_objects:
 379        hl_state_dump_free_sync_objects(sync_objects);
 380out:
 381        return rc;
 382}
 383
 384/**
 385 * hl_state_dump_print_syncs - print active sync objects
 386 * @hdev: pointer to the device
 387 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 388 * @size: pointer to the size container
 389 * @offset: pointer to the offset container
 390 *
 391 * Returns 0 on success or error code on failure
 392 */
 393static int hl_state_dump_print_syncs(struct hl_device *hdev,
 394                                        char **buf, size_t *size,
 395                                        size_t *offset)
 396
 397{
 398        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 399        struct hl_sync_to_engine_map *map;
 400        u32 index;
 401        int rc = 0;
 402
 403        map = kzalloc(sizeof(*map), GFP_KERNEL);
 404        if (!map)
 405                return -ENOMEM;
 406
 407        rc = sds->funcs.gen_sync_to_engine_map(hdev, map);
 408        if (rc)
 409                goto free_map_mem;
 410
 411        rc = hl_snprintf_resize(buf, size, offset, "Non zero sync objects:\n");
 412        if (rc)
 413                goto out;
 414
 415        if (sds->sync_namager_names) {
 416                for (index = 0; sds->sync_namager_names[index]; ++index) {
 417                        rc = hl_state_dump_print_syncs_single_block(
 418                                hdev, index, buf, size, offset, map);
 419                        if (rc)
 420                                goto out;
 421                }
 422        } else {
 423                for (index = 0; index < sds->props[SP_NUM_CORES]; ++index) {
 424                        rc = hl_state_dump_print_syncs_single_block(
 425                                hdev, index, buf, size, offset, map);
 426                        if (rc)
 427                                goto out;
 428                }
 429        }
 430
 431out:
 432        hl_state_dump_free_sync_to_engine_map(map);
 433free_map_mem:
 434        kfree(map);
 435
 436        return rc;
 437}
 438
 439/**
 440 * hl_state_dump_alloc_read_sm_block_monitors - read monitors for a specific
 441 * block
 442 * @hdev: pointer to the device
 443 * @index: sync manager block index starting with E_N
 444 *
 445 * Returns an array of monitor data of size SP_MONITORS_AMOUNT or NULL
 446 * on error
 447 */
 448static struct hl_mon_state_dump *
 449hl_state_dump_alloc_read_sm_block_monitors(struct hl_device *hdev, u32 index)
 450{
 451        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 452        struct hl_mon_state_dump *monitors;
 453        s64 base_addr; /* Base addr can be negative */
 454        int i;
 455
 456        monitors = vmalloc(sds->props[SP_MONITORS_AMOUNT] *
 457                           sizeof(struct hl_mon_state_dump));
 458        if (!monitors)
 459                return NULL;
 460
 461        base_addr = sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index;
 462
 463        for (i = 0; i < sds->props[SP_MONITORS_AMOUNT]; ++i) {
 464                monitors[i].id = i;
 465                monitors[i].wr_addr_low =
 466                        RREG32(base_addr + sds->props[SP_MON_OBJ_WR_ADDR_LOW] +
 467                                i * sizeof(u32));
 468
 469                monitors[i].wr_addr_high =
 470                        RREG32(base_addr + sds->props[SP_MON_OBJ_WR_ADDR_HIGH] +
 471                                i * sizeof(u32));
 472
 473                monitors[i].wr_data =
 474                        RREG32(base_addr + sds->props[SP_MON_OBJ_WR_DATA] +
 475                                i * sizeof(u32));
 476
 477                monitors[i].arm_data =
 478                        RREG32(base_addr + sds->props[SP_MON_OBJ_ARM_DATA] +
 479                                i * sizeof(u32));
 480
 481                monitors[i].status =
 482                        RREG32(base_addr + sds->props[SP_MON_OBJ_STATUS] +
 483                                i * sizeof(u32));
 484        }
 485
 486        return monitors;
 487}
 488
 489/**
 490 * hl_state_dump_free_monitors - free the monitors structure
 491 * @monitors: monitors array created with
 492 *            hl_state_dump_alloc_read_sm_block_monitors
 493 */
 494static void hl_state_dump_free_monitors(struct hl_mon_state_dump *monitors)
 495{
 496        vfree(monitors);
 497}
 498
 499/**
 500 * hl_state_dump_print_monitors_single_block - print active monitors on a
 501 * single block
 502 * @hdev: pointer to the device
 503 * @index: sync manager block index starting with E_N
 504 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 505 * @size: pointer to the size container
 506 * @offset: pointer to the offset container
 507 *
 508 * Returns 0 on success or error code on failure
 509 */
 510static int hl_state_dump_print_monitors_single_block(struct hl_device *hdev,
 511                                                u32 index,
 512                                                char **buf, size_t *size,
 513                                                size_t *offset)
 514{
 515        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 516        struct hl_mon_state_dump *monitors = NULL;
 517        int rc = 0, i;
 518
 519        if (sds->sync_namager_names) {
 520                rc = hl_snprintf_resize(
 521                        buf, size, offset, "%s\n",
 522                        sds->sync_namager_names[index]);
 523                if (rc)
 524                        goto out;
 525        }
 526
 527        monitors = hl_state_dump_alloc_read_sm_block_monitors(hdev, index);
 528        if (!monitors) {
 529                rc = -ENOMEM;
 530                goto out;
 531        }
 532
 533        for (i = 0; i < sds->props[SP_MONITORS_AMOUNT]; ++i) {
 534                if (!(sds->funcs.monitor_valid(&monitors[i])))
 535                        continue;
 536
 537                /* Monitor is valid, dump it */
 538                rc = sds->funcs.print_single_monitor(buf, size, offset, hdev,
 539                                                        &monitors[i]);
 540                if (rc)
 541                        goto free_monitors;
 542
 543                hl_snprintf_resize(buf, size, offset, "\n");
 544        }
 545
 546free_monitors:
 547        hl_state_dump_free_monitors(monitors);
 548out:
 549        return rc;
 550}
 551
 552/**
 553 * hl_state_dump_print_monitors - print active monitors
 554 * @hdev: pointer to the device
 555 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 556 * @size: pointer to the size container
 557 * @offset: pointer to the offset container
 558 *
 559 * Returns 0 on success or error code on failure
 560 */
 561static int hl_state_dump_print_monitors(struct hl_device *hdev,
 562                                        char **buf, size_t *size,
 563                                        size_t *offset)
 564{
 565        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 566        u32 index;
 567        int rc = 0;
 568
 569        rc = hl_snprintf_resize(buf, size, offset,
 570                "Valid (armed) monitor objects:\n");
 571        if (rc)
 572                goto out;
 573
 574        if (sds->sync_namager_names) {
 575                for (index = 0; sds->sync_namager_names[index]; ++index) {
 576                        rc = hl_state_dump_print_monitors_single_block(
 577                                hdev, index, buf, size, offset);
 578                        if (rc)
 579                                goto out;
 580                }
 581        } else {
 582                for (index = 0; index < sds->props[SP_NUM_CORES]; ++index) {
 583                        rc = hl_state_dump_print_monitors_single_block(
 584                                hdev, index, buf, size, offset);
 585                        if (rc)
 586                                goto out;
 587                }
 588        }
 589
 590out:
 591        return rc;
 592}
 593
 594/**
 595 * hl_state_dump_print_engine_fences - print active fences for a specific
 596 * engine
 597 * @hdev: pointer to the device
 598 * @engine_type: engine type to use
 599 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 600 * @size: pointer to the size container
 601 * @offset: pointer to the offset container
 602 */
 603static int
 604hl_state_dump_print_engine_fences(struct hl_device *hdev,
 605                                  enum hl_sync_engine_type engine_type,
 606                                  char **buf, size_t *size, size_t *offset)
 607{
 608        struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
 609        int rc = 0, i, n_fences;
 610        u64 base_addr, next_fence;
 611
 612        switch (engine_type) {
 613        case ENGINE_TPC:
 614                n_fences = sds->props[SP_NUM_OF_TPC_ENGINES];
 615                base_addr = sds->props[SP_TPC0_CMDQ];
 616                next_fence = sds->props[SP_NEXT_TPC];
 617                break;
 618        case ENGINE_MME:
 619                n_fences = sds->props[SP_NUM_OF_MME_ENGINES];
 620                base_addr = sds->props[SP_MME_CMDQ];
 621                next_fence = sds->props[SP_NEXT_MME];
 622                break;
 623        case ENGINE_DMA:
 624                n_fences = sds->props[SP_NUM_OF_DMA_ENGINES];
 625                base_addr = sds->props[SP_DMA_CMDQ];
 626                next_fence = sds->props[SP_DMA_QUEUES_OFFSET];
 627                break;
 628        default:
 629                return -EINVAL;
 630        }
 631        for (i = 0; i < n_fences; ++i) {
 632                rc = sds->funcs.print_fences_single_engine(
 633                        hdev,
 634                        base_addr + next_fence * i +
 635                                sds->props[SP_FENCE0_CNT_OFFSET],
 636                        base_addr + next_fence * i +
 637                                sds->props[SP_CP_STS_OFFSET],
 638                        engine_type, i, buf, size, offset);
 639                if (rc)
 640                        goto out;
 641        }
 642out:
 643        return rc;
 644}
 645
 646/**
 647 * hl_state_dump_print_fences - print active fences
 648 * @hdev: pointer to the device
 649 * @buf: destination buffer double pointer to be used with hl_snprintf_resize
 650 * @size: pointer to the size container
 651 * @offset: pointer to the offset container
 652 */
 653static int hl_state_dump_print_fences(struct hl_device *hdev, char **buf,
 654                                      size_t *size, size_t *offset)
 655{
 656        int rc = 0;
 657
 658        rc = hl_snprintf_resize(buf, size, offset, "Valid (armed) fences:\n");
 659        if (rc)
 660                goto out;
 661
 662        rc = hl_state_dump_print_engine_fences(hdev, ENGINE_TPC, buf, size, offset);
 663        if (rc)
 664                goto out;
 665
 666        rc = hl_state_dump_print_engine_fences(hdev, ENGINE_MME, buf, size, offset);
 667        if (rc)
 668                goto out;
 669
 670        rc = hl_state_dump_print_engine_fences(hdev, ENGINE_DMA, buf, size, offset);
 671        if (rc)
 672                goto out;
 673
 674out:
 675        return rc;
 676}
 677
 678/**
 679 * hl_state_dump() - dump system state
 680 * @hdev: pointer to device structure
 681 */
 682int hl_state_dump(struct hl_device *hdev)
 683{
 684        char *buf = NULL;
 685        size_t offset = 0, size = 0;
 686        int rc;
 687
 688        rc = hl_snprintf_resize(&buf, &size, &offset,
 689                                "Timestamp taken on: %llu\n\n",
 690                                ktime_to_ns(ktime_get()));
 691        if (rc)
 692                goto err;
 693
 694        rc = hl_state_dump_print_syncs(hdev, &buf, &size, &offset);
 695        if (rc)
 696                goto err;
 697
 698        hl_snprintf_resize(&buf, &size, &offset, "\n");
 699
 700        rc = hl_state_dump_print_monitors(hdev, &buf, &size, &offset);
 701        if (rc)
 702                goto err;
 703
 704        hl_snprintf_resize(&buf, &size, &offset, "\n");
 705
 706        rc = hl_state_dump_print_fences(hdev, &buf, &size, &offset);
 707        if (rc)
 708                goto err;
 709
 710        hl_snprintf_resize(&buf, &size, &offset, "\n");
 711
 712        hl_debugfs_set_state_dump(hdev, buf, size);
 713
 714        return 0;
 715err:
 716        vfree(buf);
 717        return rc;
 718}
 719