forked from Minki/linux
habanalabs: state dump monitors and fences infrastructure
With the infrastructure in place, monitors and fences dump shall be implemented. Signed-off-by: Yuri Nudelman <ynudelman@habana.ai> Reviewed-by: Oded Gabbay <ogabbay@kernel.org> Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
This commit is contained in:
parent
938b793fde
commit
fd2010b5cc
@ -1880,6 +1880,24 @@ enum hl_sync_engine_type {
|
||||
ENGINE_MME,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hl_mon_state_dump - represents a state dump of a single monitor
|
||||
* @id: monitor id
|
||||
* @wr_addr_low: address monitor will write to, low bits
|
||||
* @wr_addr_high: address monitor will write to, high bits
|
||||
* @wr_data: data monitor will write
|
||||
* @arm_data: register value containing monitor configuration
|
||||
* @status: monitor status
|
||||
*/
|
||||
struct hl_mon_state_dump {
|
||||
u32 id;
|
||||
u32 wr_addr_low;
|
||||
u32 wr_addr_high;
|
||||
u32 wr_data;
|
||||
u32 arm_data;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hl_sync_to_engine_map_entry - sync object id to engine mapping entry
|
||||
* @engine_type: type of the engine
|
||||
@ -1905,10 +1923,23 @@ struct hl_sync_to_engine_map {
|
||||
/**
|
||||
* struct hl_state_dump_specs_funcs - virtual functions used by the state dump
|
||||
* @gen_sync_to_engine_map: generate a hash map from sync obj id to its engine
|
||||
* @print_single_monitor: format monitor data as string
|
||||
* @monitor_valid: return true if given monitor dump is valid
|
||||
* @print_fences_single_engine: format fences data as string
|
||||
*/
|
||||
struct hl_state_dump_specs_funcs {
|
||||
int (*gen_sync_to_engine_map)(struct hl_device *hdev,
|
||||
struct hl_sync_to_engine_map *map);
|
||||
int (*print_single_monitor)(char **buf, size_t *size, size_t *offset,
|
||||
struct hl_device *hdev,
|
||||
struct hl_mon_state_dump *mon);
|
||||
int (*monitor_valid)(struct hl_mon_state_dump *mon);
|
||||
int (*print_fences_single_engine)(struct hl_device *hdev,
|
||||
u64 base_offset,
|
||||
u64 status_base_offset,
|
||||
enum hl_sync_engine_type engine_type,
|
||||
u32 engine_id, char **buf,
|
||||
size_t *size, size_t *offset);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2795,6 +2826,8 @@ int hl_cs_signal_sob_wraparound_handler(struct hl_device *hdev, u32 q_idx,
|
||||
|
||||
int hl_state_dump(struct hl_device *hdev);
|
||||
const char *hl_state_dump_get_sync_name(struct hl_device *hdev, u32 sync_id);
|
||||
const char *hl_state_dump_get_monitor_name(struct hl_device *hdev,
|
||||
struct hl_mon_state_dump *mon);
|
||||
void hl_state_dump_free_sync_to_engine_map(struct hl_sync_to_engine_map *map);
|
||||
__printf(4, 5) int hl_snprintf_resize(char **buf, size_t *size, size_t *offset,
|
||||
const char *format, ...);
|
||||
@ -2895,8 +2928,8 @@ static inline void hl_debugfs_remove_ctx_mem_hash(struct hl_device *hdev,
|
||||
{
|
||||
}
|
||||
|
||||
void hl_debugfs_set_state_dump(struct hl_device *hdev, char *data,
|
||||
unsigned long length)
|
||||
static inline void hl_debugfs_set_state_dump(struct hl_device *hdev,
|
||||
char *data, unsigned long length)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
#include <uapi/misc/habanalabs.h>
|
||||
#include "habanalabs.h"
|
||||
|
||||
@ -191,6 +192,30 @@ const char *hl_state_dump_get_sync_name(struct hl_device *hdev, u32 sync_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_get_monitor_name - transform monitor object dump to monitor
|
||||
* name if available
|
||||
* @hdev: pointer to the device
|
||||
* @mon: monitor state dump
|
||||
*
|
||||
* Returns a name literal or NULL if not resolved.
|
||||
* Note: returning NULL shall not be considered as a failure, as not all
|
||||
* monitors are named.
|
||||
*/
|
||||
const char *hl_state_dump_get_monitor_name(struct hl_device *hdev,
|
||||
struct hl_mon_state_dump *mon)
|
||||
{
|
||||
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
|
||||
struct hl_hw_obj_name_entry *entry;
|
||||
|
||||
hash_for_each_possible(sds->monitor_id_to_str_tb,
|
||||
entry, node, mon->id)
|
||||
if (mon->id == entry->id)
|
||||
return entry->name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_free_sync_to_engine_map - free sync object to engine map
|
||||
* @map: sync object to engine map
|
||||
@ -244,23 +269,15 @@ static u32 *hl_state_dump_read_sync_objects(struct hl_device *hdev, u32 index)
|
||||
s64 base_addr; /* Base addr can be negative */
|
||||
int i;
|
||||
|
||||
base_addr =
|
||||
sds->props[SP_SYNC_OBJ_BASE_ADDR] +
|
||||
sds->props[SP_NEXT_SYNC_OBJ_ADDR] *
|
||||
index;
|
||||
base_addr = sds->props[SP_SYNC_OBJ_BASE_ADDR] +
|
||||
sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index;
|
||||
|
||||
sync_objects = vmalloc(
|
||||
sds->props[SP_SYNC_OBJ_AMOUNT] *
|
||||
sizeof(u32));
|
||||
sync_objects = vmalloc(sds->props[SP_SYNC_OBJ_AMOUNT] * sizeof(u32));
|
||||
if (!sync_objects)
|
||||
return NULL;
|
||||
|
||||
for (i = 0;
|
||||
i < sds->props[SP_SYNC_OBJ_AMOUNT];
|
||||
++i) {
|
||||
sync_objects[i] =
|
||||
RREG32(base_addr + i * sizeof(u32));
|
||||
}
|
||||
for (i = 0; i < sds->props[SP_SYNC_OBJ_AMOUNT]; ++i)
|
||||
sync_objects[i] = RREG32(base_addr + i * sizeof(u32));
|
||||
|
||||
return sync_objects;
|
||||
}
|
||||
@ -312,19 +329,16 @@ hl_state_dump_print_syncs_single_block(struct hl_device *hdev, u32 index,
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
i < sds->props[SP_SYNC_OBJ_AMOUNT];
|
||||
++i) {
|
||||
for (i = 0; i < sds->props[SP_SYNC_OBJ_AMOUNT]; ++i) {
|
||||
struct hl_sync_to_engine_map_entry *entry;
|
||||
u64 sync_object_addr;
|
||||
|
||||
if (!sync_objects[i])
|
||||
continue;
|
||||
|
||||
sync_object_addr =
|
||||
sds->props[SP_SYNC_OBJ_BASE_ADDR] +
|
||||
sds->props[SP_NEXT_SYNC_OBJ_ADDR] *
|
||||
index + i * sizeof(u32);
|
||||
sync_object_addr = sds->props[SP_SYNC_OBJ_BASE_ADDR] +
|
||||
sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index +
|
||||
i * sizeof(u32);
|
||||
|
||||
rc = hl_snprintf_resize(buf, size, offset, "sync id: %u", i);
|
||||
if (rc)
|
||||
@ -345,7 +359,8 @@ hl_state_dump_print_syncs_single_block(struct hl_device *hdev, u32 index,
|
||||
entry = hl_state_dump_get_sync_to_engine(map,
|
||||
(u32)sync_object_addr);
|
||||
if (entry) {
|
||||
rc = hl_snprintf_resize(buf, size, offset, ", Engine: ");
|
||||
rc = hl_snprintf_resize(buf, size, offset,
|
||||
", Engine: ");
|
||||
if (rc)
|
||||
goto free_sync_objects;
|
||||
rc = hl_print_resize_sync_engine(buf, size, offset,
|
||||
@ -421,6 +436,245 @@ free_map_mem:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_alloc_read_sm_block_monitors - read monitors for a specific
|
||||
* block
|
||||
* @hdev: pointer to the device
|
||||
* @index: sync manager block index starting with E_N
|
||||
*
|
||||
* Returns an array of monitor data of size SP_MONITORS_AMOUNT or NULL
|
||||
* on error
|
||||
*/
|
||||
static struct hl_mon_state_dump *
|
||||
hl_state_dump_alloc_read_sm_block_monitors(struct hl_device *hdev, u32 index)
|
||||
{
|
||||
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
|
||||
struct hl_mon_state_dump *monitors;
|
||||
s64 base_addr; /* Base addr can be negative */
|
||||
int i;
|
||||
|
||||
monitors = vmalloc(sds->props[SP_MONITORS_AMOUNT] *
|
||||
sizeof(struct hl_mon_state_dump));
|
||||
if (!monitors)
|
||||
return NULL;
|
||||
|
||||
base_addr = sds->props[SP_NEXT_SYNC_OBJ_ADDR] * index;
|
||||
|
||||
for (i = 0; i < sds->props[SP_MONITORS_AMOUNT]; ++i) {
|
||||
monitors[i].id = i;
|
||||
monitors[i].wr_addr_low =
|
||||
RREG32(base_addr + sds->props[SP_MON_OBJ_WR_ADDR_LOW] +
|
||||
i * sizeof(u32));
|
||||
|
||||
monitors[i].wr_addr_high =
|
||||
RREG32(base_addr + sds->props[SP_MON_OBJ_WR_ADDR_HIGH] +
|
||||
i * sizeof(u32));
|
||||
|
||||
monitors[i].wr_data =
|
||||
RREG32(base_addr + sds->props[SP_MON_OBJ_WR_DATA] +
|
||||
i * sizeof(u32));
|
||||
|
||||
monitors[i].arm_data =
|
||||
RREG32(base_addr + sds->props[SP_MON_OBJ_ARM_DATA] +
|
||||
i * sizeof(u32));
|
||||
|
||||
monitors[i].status =
|
||||
RREG32(base_addr + sds->props[SP_MON_OBJ_STATUS] +
|
||||
i * sizeof(u32));
|
||||
}
|
||||
|
||||
return monitors;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_free_monitors - free the monitors structure
|
||||
* @monitors: monitors array created with
|
||||
* hl_state_dump_alloc_read_sm_block_monitors
|
||||
*/
|
||||
static void hl_state_dump_free_monitors(struct hl_mon_state_dump *monitors)
|
||||
{
|
||||
vfree(monitors);
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_print_monitors_single_block - print active monitors on a
|
||||
* single block
|
||||
* @hdev: pointer to the device
|
||||
* @index: sync manager block index starting with E_N
|
||||
* @buf: destination buffer double pointer to be used with hl_snprintf_resize
|
||||
* @size: pointer to the size container
|
||||
* @offset: pointer to the offset container
|
||||
*
|
||||
* Returns 0 on success or error code on failure
|
||||
*/
|
||||
static int hl_state_dump_print_monitors_single_block(struct hl_device *hdev,
|
||||
u32 index,
|
||||
char **buf, size_t *size,
|
||||
size_t *offset)
|
||||
{
|
||||
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
|
||||
struct hl_mon_state_dump *monitors = NULL;
|
||||
int rc = 0, i;
|
||||
|
||||
if (sds->sync_namager_names) {
|
||||
rc = hl_snprintf_resize(
|
||||
buf, size, offset, "%s\n",
|
||||
sds->sync_namager_names[index]);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
monitors = hl_state_dump_alloc_read_sm_block_monitors(hdev, index);
|
||||
if (!monitors) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < sds->props[SP_MONITORS_AMOUNT]; ++i) {
|
||||
if (!(sds->funcs.monitor_valid(&monitors[i])))
|
||||
continue;
|
||||
|
||||
/* Monitor is valid, dump it */
|
||||
rc = sds->funcs.print_single_monitor(buf, size, offset, hdev,
|
||||
&monitors[i]);
|
||||
if (rc)
|
||||
goto free_monitors;
|
||||
|
||||
hl_snprintf_resize(buf, size, offset, "\n");
|
||||
}
|
||||
|
||||
free_monitors:
|
||||
hl_state_dump_free_monitors(monitors);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_print_monitors - print active monitors
|
||||
* @hdev: pointer to the device
|
||||
* @buf: destination buffer double pointer to be used with hl_snprintf_resize
|
||||
* @size: pointer to the size container
|
||||
* @offset: pointer to the offset container
|
||||
*
|
||||
* Returns 0 on success or error code on failure
|
||||
*/
|
||||
static int hl_state_dump_print_monitors(struct hl_device *hdev,
|
||||
char **buf, size_t *size,
|
||||
size_t *offset)
|
||||
{
|
||||
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
|
||||
u32 index;
|
||||
int rc = 0;
|
||||
|
||||
rc = hl_snprintf_resize(buf, size, offset,
|
||||
"Valid (armed) monitor objects:\n");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (sds->sync_namager_names) {
|
||||
for (index = 0; sds->sync_namager_names[index]; ++index) {
|
||||
rc = hl_state_dump_print_monitors_single_block(
|
||||
hdev, index, buf, size, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
for (index = 0; index < sds->props[SP_NUM_CORES]; ++index) {
|
||||
rc = hl_state_dump_print_monitors_single_block(
|
||||
hdev, index, buf, size, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_print_engine_fences - print active fences for a specific
|
||||
* engine
|
||||
* @hdev: pointer to the device
|
||||
* @engine_type: engine type to use
|
||||
* @buf: destination buffer double pointer to be used with hl_snprintf_resize
|
||||
* @size: pointer to the size container
|
||||
* @offset: pointer to the offset container
|
||||
*/
|
||||
static int
|
||||
hl_state_dump_print_engine_fences(struct hl_device *hdev,
|
||||
enum hl_sync_engine_type engine_type,
|
||||
char **buf, size_t *size, size_t *offset)
|
||||
{
|
||||
struct hl_state_dump_specs *sds = &hdev->state_dump_specs;
|
||||
int rc = 0, i, n_fences;
|
||||
u64 base_addr, next_fence;
|
||||
|
||||
switch (engine_type) {
|
||||
case ENGINE_TPC:
|
||||
n_fences = sds->props[SP_NUM_OF_TPC_ENGINES];
|
||||
base_addr = sds->props[SP_TPC0_CMDQ];
|
||||
next_fence = sds->props[SP_NEXT_TPC];
|
||||
break;
|
||||
case ENGINE_MME:
|
||||
n_fences = sds->props[SP_NUM_OF_MME_ENGINES];
|
||||
base_addr = sds->props[SP_MME_CMDQ];
|
||||
next_fence = sds->props[SP_NEXT_MME];
|
||||
break;
|
||||
case ENGINE_DMA:
|
||||
n_fences = sds->props[SP_NUM_OF_DMA_ENGINES];
|
||||
base_addr = sds->props[SP_DMA_CMDQ];
|
||||
next_fence = sds->props[SP_DMA_QUEUES_OFFSET];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < n_fences; ++i) {
|
||||
rc = sds->funcs.print_fences_single_engine(
|
||||
hdev,
|
||||
base_addr + next_fence * i +
|
||||
sds->props[SP_FENCE0_CNT_OFFSET],
|
||||
base_addr + next_fence * i +
|
||||
sds->props[SP_CP_STS_OFFSET],
|
||||
engine_type, i, buf, size, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump_print_fences - print active fences
|
||||
* @hdev: pointer to the device
|
||||
* @buf: destination buffer double pointer to be used with hl_snprintf_resize
|
||||
* @size: pointer to the size container
|
||||
* @offset: pointer to the offset container
|
||||
*/
|
||||
static int hl_state_dump_print_fences(struct hl_device *hdev, char **buf,
|
||||
size_t *size, size_t *offset)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = hl_snprintf_resize(buf, size, offset, "Valid (armed) fences:\n");
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = hl_state_dump_print_engine_fences(hdev, ENGINE_TPC, buf, size, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = hl_state_dump_print_engine_fences(hdev, ENGINE_MME, buf, size, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = hl_state_dump_print_engine_fences(hdev, ENGINE_DMA, buf, size, offset);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* hl_state_dump() - dump system state
|
||||
* @hdev: pointer to device structure
|
||||
@ -443,6 +697,18 @@ int hl_state_dump(struct hl_device *hdev)
|
||||
|
||||
hl_snprintf_resize(&buf, &size, &offset, "\n");
|
||||
|
||||
rc = hl_state_dump_print_monitors(hdev, &buf, &size, &offset);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
hl_snprintf_resize(&buf, &size, &offset, "\n");
|
||||
|
||||
rc = hl_state_dump_print_fences(hdev, &buf, &size, &offset);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
hl_snprintf_resize(&buf, &size, &offset, "\n");
|
||||
|
||||
hl_debugfs_set_state_dump(hdev, buf, size);
|
||||
|
||||
return 0;
|
||||
|
@ -8986,9 +8986,36 @@ static int gaudi_gen_sync_to_engine_map(struct hl_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gaudi_monitor_valid(struct hl_mon_state_dump *mon)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gaudi_print_single_monitor(char **buf, size_t *size, size_t *offset,
|
||||
struct hl_device *hdev,
|
||||
struct hl_mon_state_dump *mon)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int gaudi_print_fences_single_engine(
|
||||
struct hl_device *hdev, u64 base_offset, u64 status_base_offset,
|
||||
enum hl_sync_engine_type engine_type, u32 engine_id, char **buf,
|
||||
size_t *size, size_t *offset)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct hl_state_dump_specs_funcs gaudi_state_dump_funcs = {
|
||||
.monitor_valid = gaudi_monitor_valid,
|
||||
.print_single_monitor = gaudi_print_single_monitor,
|
||||
.gen_sync_to_engine_map = gaudi_gen_sync_to_engine_map,
|
||||
.print_fences_single_engine = gaudi_print_fences_single_engine,
|
||||
};
|
||||
|
||||
static void gaudi_state_dump_init(struct hl_device *hdev)
|
||||
|
@ -5533,9 +5533,36 @@ static int goya_gen_sync_to_engine_map(struct hl_device *hdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int goya_monitor_valid(struct hl_mon_state_dump *mon)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int goya_print_single_monitor(char **buf, size_t *size, size_t *offset,
|
||||
struct hl_device *hdev,
|
||||
struct hl_mon_state_dump *mon)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int goya_print_fences_single_engine(
|
||||
struct hl_device *hdev, u64 base_offset, u64 status_base_offset,
|
||||
enum hl_sync_engine_type engine_type, u32 engine_id, char **buf,
|
||||
size_t *size, size_t *offset)
|
||||
{
|
||||
/* Not implemented */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct hl_state_dump_specs_funcs goya_state_dump_funcs = {
|
||||
.monitor_valid = goya_monitor_valid,
|
||||
.print_single_monitor = goya_print_single_monitor,
|
||||
.gen_sync_to_engine_map = goya_gen_sync_to_engine_map,
|
||||
.print_fences_single_engine = goya_print_fences_single_engine,
|
||||
};
|
||||
|
||||
static void goya_state_dump_init(struct hl_device *hdev)
|
||||
|
Loading…
Reference in New Issue
Block a user