162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * Copyright 2021 HabanaLabs, Ltd.
562306a36Sopenharmony_ci * All Rights Reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/vmalloc.h>
962306a36Sopenharmony_ci#include <uapi/drm/habanalabs_accel.h>
1062306a36Sopenharmony_ci#include "habanalabs.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/**
1362306a36Sopenharmony_ci * hl_format_as_binary - helper function, format an integer as binary
1462306a36Sopenharmony_ci *                       using supplied scratch buffer
1562306a36Sopenharmony_ci * @buf: the buffer to use
1662306a36Sopenharmony_ci * @buf_len: buffer capacity
1762306a36Sopenharmony_ci * @n: number to format
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Returns pointer to buffer
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cichar *hl_format_as_binary(char *buf, size_t buf_len, u32 n)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	int i;
2462306a36Sopenharmony_ci	u32 bit;
2562306a36Sopenharmony_ci	bool leading0 = true;
2662306a36Sopenharmony_ci	char *wrptr = buf;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (buf_len > 0 && buf_len < 3) {
2962306a36Sopenharmony_ci		*wrptr = '\0';
3062306a36Sopenharmony_ci		return buf;
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	wrptr[0] = '0';
3462306a36Sopenharmony_ci	wrptr[1] = 'b';
3562306a36Sopenharmony_ci	wrptr += 2;
3662306a36Sopenharmony_ci	/* Remove 3 characters from length for '0b' and '\0' termination */
3762306a36Sopenharmony_ci	buf_len -= 3;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	for (i = 0; i < sizeof(n) * BITS_PER_BYTE && buf_len; ++i, n <<= 1) {
4062306a36Sopenharmony_ci		/* Writing bit calculation in one line would cause a false
4162306a36Sopenharmony_ci		 * positive static code analysis error, so splitting.
4262306a36Sopenharmony_ci		 */
4362306a36Sopenharmony_ci		bit = n & (1 << (sizeof(n) * BITS_PER_BYTE - 1));
4462306a36Sopenharmony_ci		bit = !!bit;
4562306a36Sopenharmony_ci		leading0 &= !bit;
4662306a36Sopenharmony_ci		if (!leading0) {
4762306a36Sopenharmony_ci			*wrptr = '0' + bit;
4862306a36Sopenharmony_ci			++wrptr;
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	*wrptr = '\0';
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return buf;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/**
5862306a36Sopenharmony_ci * resize_to_fit - helper function, resize buffer to fit given amount of data
5962306a36Sopenharmony_ci * @buf: destination buffer double pointer
6062306a36Sopenharmony_ci * @size: pointer to the size container
6162306a36Sopenharmony_ci * @desired_size: size the buffer must contain
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci * Returns 0 on success or error code on failure.
6462306a36Sopenharmony_ci * On success, the size of buffer is at least desired_size. Buffer is allocated
6562306a36Sopenharmony_ci * via vmalloc and must be freed with vfree.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic int resize_to_fit(char **buf, size_t *size, size_t desired_size)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	char *resized_buf;
7062306a36Sopenharmony_ci	size_t new_size;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (*size >= desired_size)
7362306a36Sopenharmony_ci		return 0;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Not enough space to print all, have to resize */
7662306a36Sopenharmony_ci	new_size = max_t(size_t, PAGE_SIZE, round_up(desired_size, PAGE_SIZE));
7762306a36Sopenharmony_ci	resized_buf = vmalloc(new_size);
7862306a36Sopenharmony_ci	if (!resized_buf)
7962306a36Sopenharmony_ci		return -ENOMEM;
8062306a36Sopenharmony_ci	memcpy(resized_buf, *buf, *size);
8162306a36Sopenharmony_ci	vfree(*buf);
8262306a36Sopenharmony_ci	*buf = resized_buf;
8362306a36Sopenharmony_ci	*size = new_size;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return 1;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * hl_snprintf_resize() - print formatted data to buffer, resize as needed
9062306a36Sopenharmony_ci * @buf: buffer double pointer, to be written to and resized, must be either
9162306a36Sopenharmony_ci *       NULL or allocated with vmalloc.
9262306a36Sopenharmony_ci * @size: current size of the buffer
9362306a36Sopenharmony_ci * @offset: current offset to write to
9462306a36Sopenharmony_ci * @format: format of the data
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * This function will write formatted data into the buffer. If buffer is not
9762306a36Sopenharmony_ci * large enough, it will be resized using vmalloc. Size may be modified if the
9862306a36Sopenharmony_ci * buffer was resized, offset will be advanced by the number of bytes written
9962306a36Sopenharmony_ci * not including the terminating character
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * Returns 0 on success or error code on failure
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Note that the buffer has to be manually released using vfree.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_ciint hl_snprintf_resize(char **buf, size_t *size, size_t *offset,
10662306a36Sopenharmony_ci			   const char *format, ...)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	va_list args;
10962306a36Sopenharmony_ci	size_t length;
11062306a36Sopenharmony_ci	int rc;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (*buf == NULL && (*size != 0 || *offset != 0))
11362306a36Sopenharmony_ci		return -EINVAL;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	va_start(args, format);
11662306a36Sopenharmony_ci	length = vsnprintf(*buf + *offset, *size - *offset, format, args);
11762306a36Sopenharmony_ci	va_end(args);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	rc = resize_to_fit(buf, size, *offset + length + 1);
12062306a36Sopenharmony_ci	if (rc < 0)
12162306a36Sopenharmony_ci		return rc;
12262306a36Sopenharmony_ci	else if (rc > 0) {
12362306a36Sopenharmony_ci		/* Resize was needed, write again */
12462306a36Sopenharmony_ci		va_start(args, format);
12562306a36Sopenharmony_ci		length = vsnprintf(*buf + *offset, *size - *offset, format,
12662306a36Sopenharmony_ci				   args);
12762306a36Sopenharmony_ci		va_end(args);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	*offset += length;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/**
13662306a36Sopenharmony_ci * hl_sync_engine_to_string - convert engine type enum to string literal
13762306a36Sopenharmony_ci * @engine_type: engine type (TPC/MME/DMA)
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci * Return the resolved string literal
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ciconst char *hl_sync_engine_to_string(enum hl_sync_engine_type engine_type)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	switch (engine_type) {
14462306a36Sopenharmony_ci	case ENGINE_DMA:
14562306a36Sopenharmony_ci		return "DMA";
14662306a36Sopenharmony_ci	case ENGINE_MME:
14762306a36Sopenharmony_ci		return "MME";
14862306a36Sopenharmony_ci	case ENGINE_TPC:
14962306a36Sopenharmony_ci		return "TPC";
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	return "Invalid Engine Type";
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * hl_print_resize_sync_engine - helper function, format engine name and ID
15662306a36Sopenharmony_ci * using hl_snprintf_resize
15762306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
15862306a36Sopenharmony_ci * @size: pointer to the size container
15962306a36Sopenharmony_ci * @offset: pointer to the offset container
16062306a36Sopenharmony_ci * @engine_type: engine type (TPC/MME/DMA)
16162306a36Sopenharmony_ci * @engine_id: engine numerical id
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci * Returns 0 on success or error code on failure
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_cistatic int hl_print_resize_sync_engine(char **buf, size_t *size, size_t *offset,
16662306a36Sopenharmony_ci				enum hl_sync_engine_type engine_type,
16762306a36Sopenharmony_ci				u32 engine_id)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	return hl_snprintf_resize(buf, size, offset, "%s%u",
17062306a36Sopenharmony_ci			hl_sync_engine_to_string(engine_type), engine_id);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci/**
17462306a36Sopenharmony_ci * hl_state_dump_get_sync_name - transform sync object id to name if available
17562306a36Sopenharmony_ci * @hdev: pointer to the device
17662306a36Sopenharmony_ci * @sync_id: sync object id
17762306a36Sopenharmony_ci *
17862306a36Sopenharmony_ci * Returns a name literal or NULL if not resolved.
17962306a36Sopenharmony_ci * Note: returning NULL shall not be considered as a failure, as not all
18062306a36Sopenharmony_ci * sync objects are named.
18162306a36Sopenharmony_ci */
18262306a36Sopenharmony_ciconst char *hl_state_dump_get_sync_name(struct hl_device *hdev, u32 sync_id)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
18562306a36Sopenharmony_ci	struct hl_hw_obj_name_entry *entry;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	hash_for_each_possible(sds->so_id_to_str_tb, entry,
18862306a36Sopenharmony_ci				node, sync_id)
18962306a36Sopenharmony_ci		if (sync_id == entry->id)
19062306a36Sopenharmony_ci			return entry->name;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	return NULL;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/**
19662306a36Sopenharmony_ci * hl_state_dump_get_monitor_name - transform monitor object dump to monitor
19762306a36Sopenharmony_ci * name if available
19862306a36Sopenharmony_ci * @hdev: pointer to the device
19962306a36Sopenharmony_ci * @mon: monitor state dump
20062306a36Sopenharmony_ci *
20162306a36Sopenharmony_ci * Returns a name literal or NULL if not resolved.
20262306a36Sopenharmony_ci * Note: returning NULL shall not be considered as a failure, as not all
20362306a36Sopenharmony_ci * monitors are named.
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_ciconst char *hl_state_dump_get_monitor_name(struct hl_device *hdev,
20662306a36Sopenharmony_ci					struct hl_mon_state_dump *mon)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
20962306a36Sopenharmony_ci	struct hl_hw_obj_name_entry *entry;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	hash_for_each_possible(sds->monitor_id_to_str_tb,
21262306a36Sopenharmony_ci				entry, node, mon->id)
21362306a36Sopenharmony_ci		if (mon->id == entry->id)
21462306a36Sopenharmony_ci			return entry->name;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return NULL;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/**
22062306a36Sopenharmony_ci * hl_state_dump_free_sync_to_engine_map - free sync object to engine map
22162306a36Sopenharmony_ci * @map: sync object to engine map
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * Note: generic free implementation, the allocation is implemented per ASIC.
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_civoid hl_state_dump_free_sync_to_engine_map(struct hl_sync_to_engine_map *map)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct hl_sync_to_engine_map_entry *entry;
22862306a36Sopenharmony_ci	struct hlist_node *tmp_node;
22962306a36Sopenharmony_ci	int i;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	hash_for_each_safe(map->tb, i, tmp_node, entry, node) {
23262306a36Sopenharmony_ci		hash_del(&entry->node);
23362306a36Sopenharmony_ci		kfree(entry);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/**
23862306a36Sopenharmony_ci * hl_state_dump_get_sync_to_engine - transform sync_id to
23962306a36Sopenharmony_ci * hl_sync_to_engine_map_entry if available for current id
24062306a36Sopenharmony_ci * @map: sync object to engine map
24162306a36Sopenharmony_ci * @sync_id: sync object id
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * Returns the translation entry if found or NULL if not.
24462306a36Sopenharmony_ci * Note, returned NULL shall not be considered as a failure as the map
24562306a36Sopenharmony_ci * does not cover all possible, it is a best effort sync ids.
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistatic struct hl_sync_to_engine_map_entry *
24862306a36Sopenharmony_cihl_state_dump_get_sync_to_engine(struct hl_sync_to_engine_map *map, u32 sync_id)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct hl_sync_to_engine_map_entry *entry;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	hash_for_each_possible(map->tb, entry, node, sync_id)
25362306a36Sopenharmony_ci		if (entry->sync_id == sync_id)
25462306a36Sopenharmony_ci			return entry;
25562306a36Sopenharmony_ci	return NULL;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/**
25962306a36Sopenharmony_ci * hl_state_dump_read_sync_objects - read sync objects array
26062306a36Sopenharmony_ci * @hdev: pointer to the device
26162306a36Sopenharmony_ci * @index: sync manager block index starting with E_N
26262306a36Sopenharmony_ci *
26362306a36Sopenharmony_ci * Returns array of size SP_SYNC_OBJ_AMOUNT on success or NULL on failure
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_cistatic u32 *hl_state_dump_read_sync_objects(struct hl_device *hdev, u32 index)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
26862306a36Sopenharmony_ci	u32 *sync_objects;
26962306a36Sopenharmony_ci	s64 base_addr; /* Base addr can be negative */
27062306a36Sopenharmony_ci	int i;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	base_addr = sds->props[SP_SYNC_OBJ_BASE_ADDR] +
27362306a36Sopenharmony_ci			sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	sync_objects = vmalloc(sds->props[SP_SYNC_OBJ_AMOUNT] * sizeof(u32));
27662306a36Sopenharmony_ci	if (!sync_objects)
27762306a36Sopenharmony_ci		return NULL;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	for (i = 0; i < sds->props[SP_SYNC_OBJ_AMOUNT]; ++i)
28062306a36Sopenharmony_ci		sync_objects[i] = RREG32(base_addr + i * sizeof(u32));
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return sync_objects;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/**
28662306a36Sopenharmony_ci * hl_state_dump_free_sync_objects - free sync objects array allocated by
28762306a36Sopenharmony_ci * hl_state_dump_read_sync_objects
28862306a36Sopenharmony_ci * @sync_objects: sync objects array
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_cistatic void hl_state_dump_free_sync_objects(u32 *sync_objects)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	vfree(sync_objects);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci/**
29762306a36Sopenharmony_ci * hl_state_dump_print_syncs_single_block - print active sync objects on a
29862306a36Sopenharmony_ci * single block
29962306a36Sopenharmony_ci * @hdev: pointer to the device
30062306a36Sopenharmony_ci * @index: sync manager block index starting with E_N
30162306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
30262306a36Sopenharmony_ci * @size: pointer to the size container
30362306a36Sopenharmony_ci * @offset: pointer to the offset container
30462306a36Sopenharmony_ci * @map: sync engines names map
30562306a36Sopenharmony_ci *
30662306a36Sopenharmony_ci * Returns 0 on success or error code on failure
30762306a36Sopenharmony_ci */
30862306a36Sopenharmony_cistatic int
30962306a36Sopenharmony_cihl_state_dump_print_syncs_single_block(struct hl_device *hdev, u32 index,
31062306a36Sopenharmony_ci				char **buf, size_t *size, size_t *offset,
31162306a36Sopenharmony_ci				struct hl_sync_to_engine_map *map)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
31462306a36Sopenharmony_ci	const char *sync_name;
31562306a36Sopenharmony_ci	u32 *sync_objects = NULL;
31662306a36Sopenharmony_ci	int rc = 0, i;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (sds->sync_namager_names) {
31962306a36Sopenharmony_ci		rc = hl_snprintf_resize(
32062306a36Sopenharmony_ci			buf, size, offset, "%s\n",
32162306a36Sopenharmony_ci			sds->sync_namager_names[index]);
32262306a36Sopenharmony_ci		if (rc)
32362306a36Sopenharmony_ci			goto out;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	sync_objects = hl_state_dump_read_sync_objects(hdev, index);
32762306a36Sopenharmony_ci	if (!sync_objects) {
32862306a36Sopenharmony_ci		rc = -ENOMEM;
32962306a36Sopenharmony_ci		goto out;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	for (i = 0; i < sds->props[SP_SYNC_OBJ_AMOUNT]; ++i) {
33362306a36Sopenharmony_ci		struct hl_sync_to_engine_map_entry *entry;
33462306a36Sopenharmony_ci		u64 sync_object_addr;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		if (!sync_objects[i])
33762306a36Sopenharmony_ci			continue;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		sync_object_addr = sds->props[SP_SYNC_OBJ_BASE_ADDR] +
34062306a36Sopenharmony_ci				sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index +
34162306a36Sopenharmony_ci				i * sizeof(u32);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		rc = hl_snprintf_resize(buf, size, offset, "sync id: %u", i);
34462306a36Sopenharmony_ci		if (rc)
34562306a36Sopenharmony_ci			goto free_sync_objects;
34662306a36Sopenharmony_ci		sync_name = hl_state_dump_get_sync_name(hdev, i);
34762306a36Sopenharmony_ci		if (sync_name) {
34862306a36Sopenharmony_ci			rc = hl_snprintf_resize(buf, size, offset, " %s",
34962306a36Sopenharmony_ci						sync_name);
35062306a36Sopenharmony_ci			if (rc)
35162306a36Sopenharmony_ci				goto free_sync_objects;
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci		rc = hl_snprintf_resize(buf, size, offset, ", value: %u",
35462306a36Sopenharmony_ci					sync_objects[i]);
35562306a36Sopenharmony_ci		if (rc)
35662306a36Sopenharmony_ci			goto free_sync_objects;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		/* Append engine string */
35962306a36Sopenharmony_ci		entry = hl_state_dump_get_sync_to_engine(map,
36062306a36Sopenharmony_ci			(u32)sync_object_addr);
36162306a36Sopenharmony_ci		if (entry) {
36262306a36Sopenharmony_ci			rc = hl_snprintf_resize(buf, size, offset,
36362306a36Sopenharmony_ci						", Engine: ");
36462306a36Sopenharmony_ci			if (rc)
36562306a36Sopenharmony_ci				goto free_sync_objects;
36662306a36Sopenharmony_ci			rc = hl_print_resize_sync_engine(buf, size, offset,
36762306a36Sopenharmony_ci						entry->engine_type,
36862306a36Sopenharmony_ci						entry->engine_id);
36962306a36Sopenharmony_ci			if (rc)
37062306a36Sopenharmony_ci				goto free_sync_objects;
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		rc = hl_snprintf_resize(buf, size, offset, "\n");
37462306a36Sopenharmony_ci		if (rc)
37562306a36Sopenharmony_ci			goto free_sync_objects;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cifree_sync_objects:
37962306a36Sopenharmony_ci	hl_state_dump_free_sync_objects(sync_objects);
38062306a36Sopenharmony_ciout:
38162306a36Sopenharmony_ci	return rc;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/**
38562306a36Sopenharmony_ci * hl_state_dump_print_syncs - print active sync objects
38662306a36Sopenharmony_ci * @hdev: pointer to the device
38762306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
38862306a36Sopenharmony_ci * @size: pointer to the size container
38962306a36Sopenharmony_ci * @offset: pointer to the offset container
39062306a36Sopenharmony_ci *
39162306a36Sopenharmony_ci * Returns 0 on success or error code on failure
39262306a36Sopenharmony_ci */
39362306a36Sopenharmony_cistatic int hl_state_dump_print_syncs(struct hl_device *hdev,
39462306a36Sopenharmony_ci					char **buf, size_t *size,
39562306a36Sopenharmony_ci					size_t *offset)
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
39962306a36Sopenharmony_ci	struct hl_sync_to_engine_map *map;
40062306a36Sopenharmony_ci	u32 index;
40162306a36Sopenharmony_ci	int rc = 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	map = kzalloc(sizeof(*map), GFP_KERNEL);
40462306a36Sopenharmony_ci	if (!map)
40562306a36Sopenharmony_ci		return -ENOMEM;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	rc = sds->funcs.gen_sync_to_engine_map(hdev, map);
40862306a36Sopenharmony_ci	if (rc)
40962306a36Sopenharmony_ci		goto free_map_mem;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	rc = hl_snprintf_resize(buf, size, offset, "Non zero sync objects:\n");
41262306a36Sopenharmony_ci	if (rc)
41362306a36Sopenharmony_ci		goto out;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (sds->sync_namager_names) {
41662306a36Sopenharmony_ci		for (index = 0; sds->sync_namager_names[index]; ++index) {
41762306a36Sopenharmony_ci			rc = hl_state_dump_print_syncs_single_block(
41862306a36Sopenharmony_ci				hdev, index, buf, size, offset, map);
41962306a36Sopenharmony_ci			if (rc)
42062306a36Sopenharmony_ci				goto out;
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci	} else {
42362306a36Sopenharmony_ci		for (index = 0; index < sds->props[SP_NUM_CORES]; ++index) {
42462306a36Sopenharmony_ci			rc = hl_state_dump_print_syncs_single_block(
42562306a36Sopenharmony_ci				hdev, index, buf, size, offset, map);
42662306a36Sopenharmony_ci			if (rc)
42762306a36Sopenharmony_ci				goto out;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ciout:
43262306a36Sopenharmony_ci	hl_state_dump_free_sync_to_engine_map(map);
43362306a36Sopenharmony_cifree_map_mem:
43462306a36Sopenharmony_ci	kfree(map);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return rc;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/**
44062306a36Sopenharmony_ci * hl_state_dump_alloc_read_sm_block_monitors - read monitors for a specific
44162306a36Sopenharmony_ci * block
44262306a36Sopenharmony_ci * @hdev: pointer to the device
44362306a36Sopenharmony_ci * @index: sync manager block index starting with E_N
44462306a36Sopenharmony_ci *
44562306a36Sopenharmony_ci * Returns an array of monitor data of size SP_MONITORS_AMOUNT or NULL
44662306a36Sopenharmony_ci * on error
44762306a36Sopenharmony_ci */
44862306a36Sopenharmony_cistatic struct hl_mon_state_dump *
44962306a36Sopenharmony_cihl_state_dump_alloc_read_sm_block_monitors(struct hl_device *hdev, u32 index)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
45262306a36Sopenharmony_ci	struct hl_mon_state_dump *monitors;
45362306a36Sopenharmony_ci	s64 base_addr; /* Base addr can be negative */
45462306a36Sopenharmony_ci	int i;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	monitors = vmalloc(sds->props[SP_MONITORS_AMOUNT] *
45762306a36Sopenharmony_ci			   sizeof(struct hl_mon_state_dump));
45862306a36Sopenharmony_ci	if (!monitors)
45962306a36Sopenharmony_ci		return NULL;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	base_addr = sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	for (i = 0; i < sds->props[SP_MONITORS_AMOUNT]; ++i) {
46462306a36Sopenharmony_ci		monitors[i].id = i;
46562306a36Sopenharmony_ci		monitors[i].wr_addr_low =
46662306a36Sopenharmony_ci			RREG32(base_addr + sds->props[SP_MON_OBJ_WR_ADDR_LOW] +
46762306a36Sopenharmony_ci				i * sizeof(u32));
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		monitors[i].wr_addr_high =
47062306a36Sopenharmony_ci			RREG32(base_addr + sds->props[SP_MON_OBJ_WR_ADDR_HIGH] +
47162306a36Sopenharmony_ci				i * sizeof(u32));
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		monitors[i].wr_data =
47462306a36Sopenharmony_ci			RREG32(base_addr + sds->props[SP_MON_OBJ_WR_DATA] +
47562306a36Sopenharmony_ci				i * sizeof(u32));
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		monitors[i].arm_data =
47862306a36Sopenharmony_ci			RREG32(base_addr + sds->props[SP_MON_OBJ_ARM_DATA] +
47962306a36Sopenharmony_ci				i * sizeof(u32));
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		monitors[i].status =
48262306a36Sopenharmony_ci			RREG32(base_addr + sds->props[SP_MON_OBJ_STATUS] +
48362306a36Sopenharmony_ci				i * sizeof(u32));
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return monitors;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/**
49062306a36Sopenharmony_ci * hl_state_dump_free_monitors - free the monitors structure
49162306a36Sopenharmony_ci * @monitors: monitors array created with
49262306a36Sopenharmony_ci *            hl_state_dump_alloc_read_sm_block_monitors
49362306a36Sopenharmony_ci */
49462306a36Sopenharmony_cistatic void hl_state_dump_free_monitors(struct hl_mon_state_dump *monitors)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	vfree(monitors);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/**
50062306a36Sopenharmony_ci * hl_state_dump_print_monitors_single_block - print active monitors on a
50162306a36Sopenharmony_ci * single block
50262306a36Sopenharmony_ci * @hdev: pointer to the device
50362306a36Sopenharmony_ci * @index: sync manager block index starting with E_N
50462306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
50562306a36Sopenharmony_ci * @size: pointer to the size container
50662306a36Sopenharmony_ci * @offset: pointer to the offset container
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci * Returns 0 on success or error code on failure
50962306a36Sopenharmony_ci */
51062306a36Sopenharmony_cistatic int hl_state_dump_print_monitors_single_block(struct hl_device *hdev,
51162306a36Sopenharmony_ci						u32 index,
51262306a36Sopenharmony_ci						char **buf, size_t *size,
51362306a36Sopenharmony_ci						size_t *offset)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
51662306a36Sopenharmony_ci	struct hl_mon_state_dump *monitors = NULL;
51762306a36Sopenharmony_ci	int rc = 0, i;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (sds->sync_namager_names) {
52062306a36Sopenharmony_ci		rc = hl_snprintf_resize(
52162306a36Sopenharmony_ci			buf, size, offset, "%s\n",
52262306a36Sopenharmony_ci			sds->sync_namager_names[index]);
52362306a36Sopenharmony_ci		if (rc)
52462306a36Sopenharmony_ci			goto out;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	monitors = hl_state_dump_alloc_read_sm_block_monitors(hdev, index);
52862306a36Sopenharmony_ci	if (!monitors) {
52962306a36Sopenharmony_ci		rc = -ENOMEM;
53062306a36Sopenharmony_ci		goto out;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	for (i = 0; i < sds->props[SP_MONITORS_AMOUNT]; ++i) {
53462306a36Sopenharmony_ci		if (!(sds->funcs.monitor_valid(&monitors[i])))
53562306a36Sopenharmony_ci			continue;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		/* Monitor is valid, dump it */
53862306a36Sopenharmony_ci		rc = sds->funcs.print_single_monitor(buf, size, offset, hdev,
53962306a36Sopenharmony_ci							&monitors[i]);
54062306a36Sopenharmony_ci		if (rc)
54162306a36Sopenharmony_ci			goto free_monitors;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		hl_snprintf_resize(buf, size, offset, "\n");
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cifree_monitors:
54762306a36Sopenharmony_ci	hl_state_dump_free_monitors(monitors);
54862306a36Sopenharmony_ciout:
54962306a36Sopenharmony_ci	return rc;
55062306a36Sopenharmony_ci}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci/**
55362306a36Sopenharmony_ci * hl_state_dump_print_monitors - print active monitors
55462306a36Sopenharmony_ci * @hdev: pointer to the device
55562306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
55662306a36Sopenharmony_ci * @size: pointer to the size container
55762306a36Sopenharmony_ci * @offset: pointer to the offset container
55862306a36Sopenharmony_ci *
55962306a36Sopenharmony_ci * Returns 0 on success or error code on failure
56062306a36Sopenharmony_ci */
56162306a36Sopenharmony_cistatic int hl_state_dump_print_monitors(struct hl_device *hdev,
56262306a36Sopenharmony_ci					char **buf, size_t *size,
56362306a36Sopenharmony_ci					size_t *offset)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
56662306a36Sopenharmony_ci	u32 index;
56762306a36Sopenharmony_ci	int rc = 0;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	rc = hl_snprintf_resize(buf, size, offset,
57062306a36Sopenharmony_ci		"Valid (armed) monitor objects:\n");
57162306a36Sopenharmony_ci	if (rc)
57262306a36Sopenharmony_ci		goto out;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (sds->sync_namager_names) {
57562306a36Sopenharmony_ci		for (index = 0; sds->sync_namager_names[index]; ++index) {
57662306a36Sopenharmony_ci			rc = hl_state_dump_print_monitors_single_block(
57762306a36Sopenharmony_ci				hdev, index, buf, size, offset);
57862306a36Sopenharmony_ci			if (rc)
57962306a36Sopenharmony_ci				goto out;
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci	} else {
58262306a36Sopenharmony_ci		for (index = 0; index < sds->props[SP_NUM_CORES]; ++index) {
58362306a36Sopenharmony_ci			rc = hl_state_dump_print_monitors_single_block(
58462306a36Sopenharmony_ci				hdev, index, buf, size, offset);
58562306a36Sopenharmony_ci			if (rc)
58662306a36Sopenharmony_ci				goto out;
58762306a36Sopenharmony_ci		}
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ciout:
59162306a36Sopenharmony_ci	return rc;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/**
59562306a36Sopenharmony_ci * hl_state_dump_print_engine_fences - print active fences for a specific
59662306a36Sopenharmony_ci * engine
59762306a36Sopenharmony_ci * @hdev: pointer to the device
59862306a36Sopenharmony_ci * @engine_type: engine type to use
59962306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
60062306a36Sopenharmony_ci * @size: pointer to the size container
60162306a36Sopenharmony_ci * @offset: pointer to the offset container
60262306a36Sopenharmony_ci */
60362306a36Sopenharmony_cistatic int
60462306a36Sopenharmony_cihl_state_dump_print_engine_fences(struct hl_device *hdev,
60562306a36Sopenharmony_ci				  enum hl_sync_engine_type engine_type,
60662306a36Sopenharmony_ci				  char **buf, size_t *size, size_t *offset)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
60962306a36Sopenharmony_ci	int rc = 0, i, n_fences;
61062306a36Sopenharmony_ci	u64 base_addr, next_fence;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	switch (engine_type) {
61362306a36Sopenharmony_ci	case ENGINE_TPC:
61462306a36Sopenharmony_ci		n_fences = sds->props[SP_NUM_OF_TPC_ENGINES];
61562306a36Sopenharmony_ci		base_addr = sds->props[SP_TPC0_CMDQ];
61662306a36Sopenharmony_ci		next_fence = sds->props[SP_NEXT_TPC];
61762306a36Sopenharmony_ci		break;
61862306a36Sopenharmony_ci	case ENGINE_MME:
61962306a36Sopenharmony_ci		n_fences = sds->props[SP_NUM_OF_MME_ENGINES];
62062306a36Sopenharmony_ci		base_addr = sds->props[SP_MME_CMDQ];
62162306a36Sopenharmony_ci		next_fence = sds->props[SP_NEXT_MME];
62262306a36Sopenharmony_ci		break;
62362306a36Sopenharmony_ci	case ENGINE_DMA:
62462306a36Sopenharmony_ci		n_fences = sds->props[SP_NUM_OF_DMA_ENGINES];
62562306a36Sopenharmony_ci		base_addr = sds->props[SP_DMA_CMDQ];
62662306a36Sopenharmony_ci		next_fence = sds->props[SP_DMA_QUEUES_OFFSET];
62762306a36Sopenharmony_ci		break;
62862306a36Sopenharmony_ci	default:
62962306a36Sopenharmony_ci		return -EINVAL;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci	for (i = 0; i < n_fences; ++i) {
63262306a36Sopenharmony_ci		rc = sds->funcs.print_fences_single_engine(
63362306a36Sopenharmony_ci			hdev,
63462306a36Sopenharmony_ci			base_addr + next_fence * i +
63562306a36Sopenharmony_ci				sds->props[SP_FENCE0_CNT_OFFSET],
63662306a36Sopenharmony_ci			base_addr + next_fence * i +
63762306a36Sopenharmony_ci				sds->props[SP_CP_STS_OFFSET],
63862306a36Sopenharmony_ci			engine_type, i, buf, size, offset);
63962306a36Sopenharmony_ci		if (rc)
64062306a36Sopenharmony_ci			goto out;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ciout:
64362306a36Sopenharmony_ci	return rc;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/**
64762306a36Sopenharmony_ci * hl_state_dump_print_fences - print active fences
64862306a36Sopenharmony_ci * @hdev: pointer to the device
64962306a36Sopenharmony_ci * @buf: destination buffer double pointer to be used with hl_snprintf_resize
65062306a36Sopenharmony_ci * @size: pointer to the size container
65162306a36Sopenharmony_ci * @offset: pointer to the offset container
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_cistatic int hl_state_dump_print_fences(struct hl_device *hdev, char **buf,
65462306a36Sopenharmony_ci				      size_t *size, size_t *offset)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	int rc = 0;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	rc = hl_snprintf_resize(buf, size, offset, "Valid (armed) fences:\n");
65962306a36Sopenharmony_ci	if (rc)
66062306a36Sopenharmony_ci		goto out;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	rc = hl_state_dump_print_engine_fences(hdev, ENGINE_TPC, buf, size, offset);
66362306a36Sopenharmony_ci	if (rc)
66462306a36Sopenharmony_ci		goto out;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	rc = hl_state_dump_print_engine_fences(hdev, ENGINE_MME, buf, size, offset);
66762306a36Sopenharmony_ci	if (rc)
66862306a36Sopenharmony_ci		goto out;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	rc = hl_state_dump_print_engine_fences(hdev, ENGINE_DMA, buf, size, offset);
67162306a36Sopenharmony_ci	if (rc)
67262306a36Sopenharmony_ci		goto out;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ciout:
67562306a36Sopenharmony_ci	return rc;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/**
67962306a36Sopenharmony_ci * hl_state_dump() - dump system state
68062306a36Sopenharmony_ci * @hdev: pointer to device structure
68162306a36Sopenharmony_ci */
68262306a36Sopenharmony_ciint hl_state_dump(struct hl_device *hdev)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	char *buf = NULL;
68562306a36Sopenharmony_ci	size_t offset = 0, size = 0;
68662306a36Sopenharmony_ci	int rc;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	rc = hl_snprintf_resize(&buf, &size, &offset,
68962306a36Sopenharmony_ci				"Timestamp taken on: %llu\n\n",
69062306a36Sopenharmony_ci				ktime_to_ns(ktime_get()));
69162306a36Sopenharmony_ci	if (rc)
69262306a36Sopenharmony_ci		goto err;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	rc = hl_state_dump_print_syncs(hdev, &buf, &size, &offset);
69562306a36Sopenharmony_ci	if (rc)
69662306a36Sopenharmony_ci		goto err;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	hl_snprintf_resize(&buf, &size, &offset, "\n");
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	rc = hl_state_dump_print_monitors(hdev, &buf, &size, &offset);
70162306a36Sopenharmony_ci	if (rc)
70262306a36Sopenharmony_ci		goto err;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	hl_snprintf_resize(&buf, &size, &offset, "\n");
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rc = hl_state_dump_print_fences(hdev, &buf, &size, &offset);
70762306a36Sopenharmony_ci	if (rc)
70862306a36Sopenharmony_ci		goto err;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	hl_snprintf_resize(&buf, &size, &offset, "\n");
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	hl_debugfs_set_state_dump(hdev, buf, size);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return 0;
71562306a36Sopenharmony_cierr:
71662306a36Sopenharmony_ci	vfree(buf);
71762306a36Sopenharmony_ci	return rc;
71862306a36Sopenharmony_ci}
719