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