mirror of
git://nv-tegra.nvidia.com/linux-hwpm.git
synced 2025-12-22 17:30:40 +03:00
tegra: hwpm: add initial userspace lib
Initial change for libnvsochwpm userspace library. Change-Id: I20b11f9d253b65583db97dfebd9ff78b4d33d50c Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-hwpm/+/3267999 Reviewed-by: Vasuki Shankar <vasukis@nvidia.com> Reviewed-by: Yifei Wan <ywan@nvidia.com> GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
f1de425d35
commit
7f1249c9e9
60
libnvsochwpm/Makefile
Normal file
60
libnvsochwpm/Makefile
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
################################################################################
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Borrow the make environment from Linux kernel to support cross compilation.
|
||||||
|
ifneq ($(KERNEL_SOURCE),)
|
||||||
|
export srctree := $(KERNEL_SOURCE)
|
||||||
|
include $(srctree)/tools/scripts/Makefile.include
|
||||||
|
include $(srctree)/tools/scripts/Makefile.arch
|
||||||
|
else
|
||||||
|
CC = gcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
common/log.c \
|
||||||
|
os/lnx/nv_soc_hwpm_lnx.c \
|
||||||
|
nv_soc_hwpm.c
|
||||||
|
|
||||||
|
OBJECTS=$(foreach x, $(basename $(SOURCES)), $(x).o)
|
||||||
|
|
||||||
|
CFLAGS = -Wall -Wextra -Werror=missing-prototypes -Wswitch -Wformat
|
||||||
|
CFLAGS += -Wchar-subscripts -Wparentheses -Wtrigraphs -Wpointer-arith
|
||||||
|
CFLAGS += -Wmissing-declarations -Wredundant-decls -Wundef -Wmain
|
||||||
|
CFLAGS += -Wreturn-type -Wmultichar -Wunused -Wmissing-braces -Werror
|
||||||
|
|
||||||
|
LDFLAGS = -Wall -Wl,--version-script=os/lnx/libnvsochwpm.map
|
||||||
|
|
||||||
|
INCLUDES = -I. -I./include -I../include
|
||||||
|
|
||||||
|
# This library requires dma_buf headers, which may not be available by default
|
||||||
|
# under linux include dir. User can specify this argument to point the dma_buf
|
||||||
|
# header files.
|
||||||
|
ifneq ($(NV_SOURCE),)
|
||||||
|
INCLUDES += -I$(NV_SOURCE)/core/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: libnvsochwpm.so
|
||||||
|
|
||||||
|
# Shared Libs
|
||||||
|
libnvsochwpm.so: $(OBJECTS)
|
||||||
|
$(CC) $(LDFLAGS) -shared -fpic -Wl,-soname,libnvsochwpm.so $^ -o $@
|
||||||
|
rm -f $(OBJECTS)
|
||||||
|
|
||||||
|
# Objects
|
||||||
|
$(OBJECTS): %.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -std=gnu99 -fpic -c $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJECTS)
|
||||||
|
rm -f libnvsochwpm.so*
|
||||||
33
libnvsochwpm/Makefile.umbrella.tmk
Normal file
33
libnvsochwpm/Makefile.umbrella.tmk
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
################################### tell Emacs this is a -*- makefile-gmake -*-
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# tmake for SW Mobile
|
||||||
|
#
|
||||||
|
# Repository umbrella makefile fragment for "libnvsochwpm"
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Build tools in this repository
|
||||||
|
#
|
||||||
|
#NV_REPOSITORY_BUILD_TOOLS :=
|
||||||
|
|
||||||
|
#
|
||||||
|
# Components in this repository
|
||||||
|
#
|
||||||
|
NV_REPOSITORY_COMPONENTS := \
|
||||||
|
tmake/lib
|
||||||
|
# Local Variables:
|
||||||
|
# indent-tabs-mode: t
|
||||||
|
# tab-width: 8
|
||||||
|
# End:
|
||||||
31
libnvsochwpm/common/bit.h
Normal file
31
libnvsochwpm/common/bit.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BIT_H__
|
||||||
|
#define __BIT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FIELD_GET(v, m, s) ((v & m) >> s)
|
||||||
|
#define FIELD_SET(v, m, s) ((v & m) << s)
|
||||||
|
|
||||||
|
#define VAL_64(lo, hi) (uint64_t)lo | ((uint64_t)hi << 32U)
|
||||||
|
#define VAL_LO64(v) FIELD_GET(v, 0xFFFFFFFFULL, 0U)
|
||||||
|
#define VAL_HI64(v) FIELD_GET(v, 0xFFFFFFFF00000000ULL, 32U)
|
||||||
|
|
||||||
|
/* Align value up to the next multiple of alignment */
|
||||||
|
#define ALIGN_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment) - 1))
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*__BIT_H__*/
|
||||||
37
libnvsochwpm/common/log.c
Normal file
37
libnvsochwpm/common/log.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* kLvlString[LOG_COUNT] = {
|
||||||
|
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
|
||||||
|
};
|
||||||
|
|
||||||
|
void nv_soc_hwpm_log(int lvl, const char *file, int line, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
// TODO: actual implementation with different log levels.
|
||||||
|
printf("[%s] %s:%d - ", kLvlString[lvl], file, line);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vprintf(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
32
libnvsochwpm/common/log.h
Normal file
32
libnvsochwpm/common/log.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LOG_H__
|
||||||
|
#define __LOG_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL, LOG_COUNT };
|
||||||
|
|
||||||
|
#define log_trace(...) nv_soc_hwpm_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_debug(...) nv_soc_hwpm_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_info(...) nv_soc_hwpm_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_warn(...) nv_soc_hwpm_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_error(...) nv_soc_hwpm_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define log_fatal(...) nv_soc_hwpm_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
void nv_soc_hwpm_log(int lvl, const char *file, int line, const char *fmt, ...);
|
||||||
|
|
||||||
|
#endif /*__LOG_H__*/
|
||||||
38
libnvsochwpm/common/register_util.h
Normal file
38
libnvsochwpm/common/register_util.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UTIL_REGISTER_UTIL_H__
|
||||||
|
#define __UTIL_REGISTER_UTIL_H__
|
||||||
|
|
||||||
|
#define DRF_SHIFT32(drf) ((0?drf) % 32)
|
||||||
|
#define DRF_MASK32(drf) (0xFFFFFFFFU>>(31-((1?drf) % 32)+((0?drf) % 32)))
|
||||||
|
|
||||||
|
#define DRF_SHIFT64(drf) ((0?drf) % 64)
|
||||||
|
#define DRF_MASK64(drf) (0xFFFFFFFFFFFFFFFFULL>>(63-((1?drf) % 64)+((0?drf) % 64)))
|
||||||
|
|
||||||
|
#define DRF_BITRANGE(drf) ((1?drf) - (0?drf) + 1)
|
||||||
|
|
||||||
|
#define REG32_RD(reg32, range) (reg32 >> DRF_SHIFT32(range)) & DRF_MASK32(range)
|
||||||
|
#define REG32_WR(reg32, range, val) (reg32 & ~(DRF_MASK32(range) << DRF_SHIFT32(range))) | ((val & DRF_MASK32(range)) << DRF_SHIFT32(range))
|
||||||
|
|
||||||
|
#define REG32_RD_MS(reg32, mask, shift) (reg32 >> shift) & mask
|
||||||
|
#define REG32_WR_MS(reg32, mask, shift, val) (reg32 & ~(mask << shift)) | ((val & mask) << shift)
|
||||||
|
|
||||||
|
#define REG64_RD(reg64, range) (reg64 >> DRF_SHIFT64(range)) & DRF_MASK64(range)
|
||||||
|
#define REG64_WR(reg64, range, val) (reg64 & ~(DRF_MASK64(range) << DRF_SHIFT64(range))) | ((val & DRF_MASK64(range)) << DRF_SHIFT64(range))
|
||||||
|
|
||||||
|
#define REG64_RD_MS(reg64, mask, shift) (reg64 >> shift) & mask
|
||||||
|
#define REG64_WR_MS(reg64, mask, shift, val) (reg64 & ~(mask << shift)) | ((val & mask) << shift)
|
||||||
|
|
||||||
|
#endif // __UTIL_REGISTER_UTIL_H__
|
||||||
153
libnvsochwpm/common/types.h
Normal file
153
libnvsochwpm/common/types.h
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TYPES_H__
|
||||||
|
#define __TYPES_H__
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm.h"
|
||||||
|
|
||||||
|
#include "common/bit.h"
|
||||||
|
|
||||||
|
#define MAX_SOCKET_COUNT 1
|
||||||
|
#define MAX_DEVICE_COUNT 1
|
||||||
|
#define MAX_SESSION_COUNT 1
|
||||||
|
#define MAX_PATH_LENGTH 256
|
||||||
|
#define MAX_FS_MASK_SIZE 256
|
||||||
|
|
||||||
|
#define DEV_HANDLE_SHIFT 0U
|
||||||
|
#define DEV_HANDLE_MASK 0xFFULL /* Up to 256 HWPM devices */
|
||||||
|
|
||||||
|
#define SESSION_HANDLE_SHIFT 16U
|
||||||
|
#define SESSION_HANDLE_MASK 0xFF00ULL /* Up to 256 HWPM sessions per device */
|
||||||
|
|
||||||
|
static inline uint32_t to_dev_idx(uint64_t handle) {
|
||||||
|
return FIELD_GET(handle, DEV_HANDLE_MASK, DEV_HANDLE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t to_dev_handle(uint32_t dev_idx) {
|
||||||
|
uint64_t handle = FIELD_SET(dev_idx, DEV_HANDLE_MASK, DEV_HANDLE_SHIFT);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t to_session_idx(uint64_t handle) {
|
||||||
|
return FIELD_GET(handle, SESSION_HANDLE_MASK, SESSION_HANDLE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t to_session_handle(uint32_t dev_idx, uint32_t session_idx) {
|
||||||
|
uint64_t handle = 0;
|
||||||
|
handle |= FIELD_SET(dev_idx, DEV_HANDLE_MASK, DEV_HANDLE_SHIFT);
|
||||||
|
handle |= FIELD_SET(session_idx, SESSION_HANDLE_MASK, SESSION_HANDLE_SHIFT);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing NV_SOC_HWPM allocated PMA buffer.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
uint8_t* buffer;
|
||||||
|
uint64_t pma_va;
|
||||||
|
uint32_t handle;
|
||||||
|
uint32_t heap_fd;
|
||||||
|
} nv_soc_hwpm_pma_buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing NV_SOC_HWPM session attributes.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
nv_soc_hwpm_device device;
|
||||||
|
|
||||||
|
nv_soc_hwpm_pma_buffer record_buffer;
|
||||||
|
nv_soc_hwpm_pma_buffer mem_bytes_buffer;
|
||||||
|
|
||||||
|
uint32_t resource_count;
|
||||||
|
nv_soc_hwpm_resource resource_ids[NV_SOC_HWPM_NUM_RESOURCES];
|
||||||
|
|
||||||
|
uint8_t is_resource_reserved;
|
||||||
|
uint8_t is_pma_buffer_allocated;
|
||||||
|
uint8_t is_session_started;
|
||||||
|
} nv_soc_hwpm_session_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Internal NV_SOC_HWPM session structure.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
nv_soc_hwpm_session_info info;
|
||||||
|
struct nv_soc_hwpm_device_int* dev_int;
|
||||||
|
} nv_soc_hwpm_session_int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing NV_SOC_HWPM device attributes.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t soc_chip_id;
|
||||||
|
uint32_t soc_revision;
|
||||||
|
uint32_t soc_platform;
|
||||||
|
uint32_t soc_socket;
|
||||||
|
|
||||||
|
uint32_t ip_available_count;
|
||||||
|
nv_soc_hwpm_ip ip_available_list[NV_SOC_HWPM_NUM_IPS];
|
||||||
|
|
||||||
|
uint32_t res_available_count;
|
||||||
|
nv_soc_hwpm_resource res_available_list[NV_SOC_HWPM_NUM_RESOURCES];
|
||||||
|
} nv_soc_hwpm_device_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing NV_SOC_HWPM IP attributes.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/* IP availability status. */
|
||||||
|
uint8_t is_available;
|
||||||
|
|
||||||
|
/* IP instance/element max count. */
|
||||||
|
uint32_t inst_max_count;
|
||||||
|
|
||||||
|
/* IP floorsweeping mask. */
|
||||||
|
uint8_t fs_mask[MAX_FS_MASK_SIZE/sizeof(uint8_t)];
|
||||||
|
} nv_soc_hwpm_ip_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing NV_SOC_HWPM resource attributes.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/* Resource availability status. */
|
||||||
|
uint8_t is_available;
|
||||||
|
|
||||||
|
/* Resource reservation status. */
|
||||||
|
uint8_t is_reserved;
|
||||||
|
} nv_soc_hwpm_resource_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Internal NV_SOC_HWPM device structure for Linux.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char* dev_path;
|
||||||
|
|
||||||
|
nv_soc_hwpm_device_info dev_info;
|
||||||
|
nv_soc_hwpm_ip_info ip_info[NV_SOC_HWPM_NUM_IPS];
|
||||||
|
nv_soc_hwpm_resource_info res_info[NV_SOC_HWPM_NUM_RESOURCES];
|
||||||
|
|
||||||
|
nv_soc_hwpm_session_int* session_int[MAX_SESSION_COUNT];
|
||||||
|
uint32_t session_count;
|
||||||
|
uint32_t session_count_max;
|
||||||
|
} nv_soc_hwpm_device_int;
|
||||||
|
|
||||||
|
nv_soc_hwpm_device_int* to_device_int(uint64_t handle);
|
||||||
|
|
||||||
|
nv_soc_hwpm_session_int* to_session_int(uint64_t handle);
|
||||||
|
|
||||||
|
#endif /*__TYPES_H__*/
|
||||||
799
libnvsochwpm/include/nv_soc_hwpm.h
Normal file
799
libnvsochwpm/include/nv_soc_hwpm.h
Normal file
@@ -0,0 +1,799 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* nv_soc_hwpm.h:
|
||||||
|
* This is the userspace API header for the Tegra SOC HWPM driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NV_SOC_HWPM_H__
|
||||||
|
#define __NV_SOC_HWPM_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define NV_SOC_HWPM_API_EXPORT
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief List of IPs supported by HWPM.
|
||||||
|
*
|
||||||
|
* The list of supported IPs are varied across different SoCs. This enum
|
||||||
|
* provides a flattened list of all IPs supported by HWPM.
|
||||||
|
*
|
||||||
|
* @note this enum is duplicated from driver header.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NV_SOC_HWPM_IP_VI,
|
||||||
|
NV_SOC_HWPM_IP_ISP,
|
||||||
|
NV_SOC_HWPM_IP_VIC,
|
||||||
|
NV_SOC_HWPM_IP_OFA,
|
||||||
|
NV_SOC_HWPM_IP_PVA,
|
||||||
|
NV_SOC_HWPM_IP_NVDLA,
|
||||||
|
NV_SOC_HWPM_IP_MGBE,
|
||||||
|
NV_SOC_HWPM_IP_SCF,
|
||||||
|
NV_SOC_HWPM_IP_NVDEC,
|
||||||
|
NV_SOC_HWPM_IP_NVENC,
|
||||||
|
NV_SOC_HWPM_IP_PCIE,
|
||||||
|
NV_SOC_HWPM_IP_DISPLAY,
|
||||||
|
NV_SOC_HWPM_IP_MSS_CHANNEL,
|
||||||
|
NV_SOC_HWPM_IP_MSS_GPU_HUB,
|
||||||
|
NV_SOC_HWPM_IP_MSS_ISO_NISO_HUBS,
|
||||||
|
NV_SOC_HWPM_IP_MSS_MCF,
|
||||||
|
NV_SOC_HWPM_IP_APE,
|
||||||
|
NV_SOC_HWPM_IP_C2C,
|
||||||
|
NV_SOC_HWPM_IP_SMMU,
|
||||||
|
NV_SOC_HWPM_IP_CL2,
|
||||||
|
NV_SOC_HWPM_IP_NVLCTRL,
|
||||||
|
NV_SOC_HWPM_IP_NVLRX,
|
||||||
|
NV_SOC_HWPM_IP_NVLTX,
|
||||||
|
NV_SOC_HWPM_IP_MSS_HUB,
|
||||||
|
NV_SOC_HWPM_IP_MCF_SOC,
|
||||||
|
NV_SOC_HWPM_IP_MCF_C2C,
|
||||||
|
NV_SOC_HWPM_IP_MCF_CLINK,
|
||||||
|
NV_SOC_HWPM_IP_MCF_CORE,
|
||||||
|
NV_SOC_HWPM_IP_MCF_OCU,
|
||||||
|
NV_SOC_HWPM_IP_PCIE_XTLQ,
|
||||||
|
NV_SOC_HWPM_IP_PCIE_XTLRC,
|
||||||
|
NV_SOC_HWPM_IP_PCIE_XALRC,
|
||||||
|
NV_SOC_HWPM_IP_UCF_MSW,
|
||||||
|
NV_SOC_HWPM_IP_UCF_PSW,
|
||||||
|
NV_SOC_HWPM_IP_UCF_CSW,
|
||||||
|
NV_SOC_HWPM_IP_UCF_HUB,
|
||||||
|
NV_SOC_HWPM_IP_UCF_SCB,
|
||||||
|
NV_SOC_HWPM_IP_CPU,
|
||||||
|
NV_SOC_HWPM_NUM_IPS
|
||||||
|
} nv_soc_hwpm_ip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The resources which can be reserved for profiling.
|
||||||
|
*
|
||||||
|
* The list of supported resources are varied across different SoCs. This enum
|
||||||
|
* provides a flattened list of all resources supported by HWPM.
|
||||||
|
*
|
||||||
|
* @note this enum is duplicated from driver header.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NV_SOC_HWPM_RESOURCE_VI,
|
||||||
|
NV_SOC_HWPM_RESOURCE_ISP,
|
||||||
|
NV_SOC_HWPM_RESOURCE_VIC,
|
||||||
|
NV_SOC_HWPM_RESOURCE_OFA,
|
||||||
|
NV_SOC_HWPM_RESOURCE_PVA,
|
||||||
|
NV_SOC_HWPM_RESOURCE_NVDLA,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MGBE,
|
||||||
|
NV_SOC_HWPM_RESOURCE_SCF,
|
||||||
|
NV_SOC_HWPM_RESOURCE_NVDEC,
|
||||||
|
NV_SOC_HWPM_RESOURCE_NVENC,
|
||||||
|
NV_SOC_HWPM_RESOURCE_PCIE,
|
||||||
|
NV_SOC_HWPM_RESOURCE_DISPLAY,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MSS_CHANNEL,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MSS_GPU_HUB,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MSS_ISO_NISO_HUBS,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MSS_MCF,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* - SYS0 PERMON in RPG_PMG
|
||||||
|
* - PERFMUX: PMA_CHANNEL_PERFMUX_CONFIG_SECURE
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_RESOURCE_PMA,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* - PMA: Everything except PMA_CHANNEL_PERFMUX_CONFIG_SECURE
|
||||||
|
* - RTR: Entire aperture
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_RESOURCE_CMD_SLICE_RTR,
|
||||||
|
NV_SOC_HWPM_RESOURCE_APE,
|
||||||
|
NV_SOC_HWPM_RESOURCE_C2C,
|
||||||
|
NV_SOC_HWPM_RESOURCE_SMMU,
|
||||||
|
NV_SOC_HWPM_RESOURCE_CL2,
|
||||||
|
NV_SOC_HWPM_RESOURCE_NVLCTRL,
|
||||||
|
NV_SOC_HWPM_RESOURCE_NVLRX,
|
||||||
|
NV_SOC_HWPM_RESOURCE_NVLTX,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MSS_HUB,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MCF_SOC,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MCF_C2C,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MCF_CLINK,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MCF_CORE,
|
||||||
|
NV_SOC_HWPM_RESOURCE_MCF_OCU,
|
||||||
|
NV_SOC_HWPM_RESOURCE_PCIE_XTLQ,
|
||||||
|
NV_SOC_HWPM_RESOURCE_PCIE_XTLRC,
|
||||||
|
NV_SOC_HWPM_RESOURCE_PCIE_XALRC,
|
||||||
|
NV_SOC_HWPM_RESOURCE_UCF_MSW,
|
||||||
|
NV_SOC_HWPM_RESOURCE_UCF_PSW,
|
||||||
|
NV_SOC_HWPM_RESOURCE_UCF_CSW,
|
||||||
|
NV_SOC_HWPM_RESOURCE_UCF_HUB,
|
||||||
|
NV_SOC_HWPM_RESOURCE_UCF_SCB,
|
||||||
|
NV_SOC_HWPM_RESOURCE_CPU,
|
||||||
|
NV_SOC_HWPM_NUM_RESOURCES
|
||||||
|
} nv_soc_hwpm_resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the NV_SOC_HWPM library.
|
||||||
|
*
|
||||||
|
* The call to this library will enumerate the supported devices. This function
|
||||||
|
* should be the first to be called before other API. There is no reference
|
||||||
|
* counting here, so caller needs to make sure it is only called once.
|
||||||
|
*
|
||||||
|
* Internally it will enumerate the available HWPM driver device nodes, hence it
|
||||||
|
* will need to open connection to the driver and makes some IOCTLs.
|
||||||
|
* After it's done enumerating, the driver connection will be closed.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -ENOMEM: unable to allocate memory for internal data structures.
|
||||||
|
* -ENOENT: can't find HWPM device node.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finalize the NV_SOC_HWPM library.
|
||||||
|
*
|
||||||
|
* It will cleanup internal data structures, including any allocated session, and
|
||||||
|
* close all connections to driver.
|
||||||
|
*
|
||||||
|
* This function should be called at the end of execution.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT void nv_soc_hwpm_exit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief General system attributes. See \ref nv_soc_hwpm_system_get_info.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/* The major version of the library. */
|
||||||
|
NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MAJOR,
|
||||||
|
/* The minor version of the library. */
|
||||||
|
NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MINOR,
|
||||||
|
} nv_soc_hwpm_system_attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get system-level information about the SOC HWPM library.
|
||||||
|
*
|
||||||
|
* This function retrieves system-level information based on the specified
|
||||||
|
* attribute.
|
||||||
|
*
|
||||||
|
* @param[in] attribute The system attribute to query. See @ref
|
||||||
|
* nv_soc_hwpm_system_attribute.
|
||||||
|
* - NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MAJOR: info buffer
|
||||||
|
* should fit uint16_t.
|
||||||
|
* - NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MINOR: info buffer
|
||||||
|
* should fit uint16_t.
|
||||||
|
* @param[in] info_size The size of the \p info buffer.
|
||||||
|
* @param[out] info Pointer to user/application allocated buffer to store the
|
||||||
|
* attribute value.
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if attribute is invalid or info is NULL.
|
||||||
|
*/
|
||||||
|
int nv_soc_hwpm_system_get_info(
|
||||||
|
nv_soc_hwpm_system_attribute attribute, uint32_t info_size, void* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing opaque handle to an NV_SOC_HWPM device.
|
||||||
|
*
|
||||||
|
* An NV_SOC_HWPM device corresponds to a HWPM device node in the system.
|
||||||
|
*
|
||||||
|
* The user will need to use this handle to do the following:
|
||||||
|
* - gather information such as the SOC information, the socket the node is
|
||||||
|
* associated with, and the IP, resources available in the socket.
|
||||||
|
* - create a HWPM session in the socket.
|
||||||
|
*/
|
||||||
|
typedef struct { uint64_t handle; } nv_soc_hwpm_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get list of NV_SOC_HWPM devices.
|
||||||
|
*
|
||||||
|
* User will need to call this function twice:
|
||||||
|
* - first by giving a non NULL count and set its value to zero. This will
|
||||||
|
* populate count with the number of available devices.
|
||||||
|
* - second by giving non NULL valid pointers on both parameters, with non
|
||||||
|
* zero count. This will populate devices array with the SOC HWPM device
|
||||||
|
* handles for subsequent usage.
|
||||||
|
*
|
||||||
|
* @param[inout] count Pointer to variable to store the number of available
|
||||||
|
* devices.
|
||||||
|
*
|
||||||
|
* @param[out] devices NV_SOC_HWPM device array. The size of the array should
|
||||||
|
* be equal or greater than the value in \p count.
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if one of the arguments is invalid.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_get_devices(
|
||||||
|
uint32_t *count, nv_soc_hwpm_device *devices);
|
||||||
|
|
||||||
|
/* Tegra SOC chip id */
|
||||||
|
typedef enum {
|
||||||
|
TEGRA_SOC_HWPM_CHIP_ID_T241 = 0x500,
|
||||||
|
TEGRA_SOC_HWPM_CHIP_ID_T410 = 0x410,
|
||||||
|
TEGRA_SOC_HWPM_CHIP_ID_COUNT = 1
|
||||||
|
} tegra_soc_hwpm_chip_id;
|
||||||
|
|
||||||
|
/* Tegra SOC platform type */
|
||||||
|
typedef enum {
|
||||||
|
TEGRA_SOC_HWPM_PLATFORM_SILICON = 0x0,
|
||||||
|
TEGRA_SOC_HWPM_PLATFORM_PRESI_QT = 0x1,
|
||||||
|
TEGRA_SOC_HWPM_PLATFORM_PRESI_VDK = 0x8,
|
||||||
|
TEGRA_SOC_HWPM_PLATFORM_PRESI_VSP = 0x9
|
||||||
|
} tegra_soc_hwpm_platform;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Device attributes. See \ref nv_soc_hwpm_device_get_info.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/* The Tegra SOC chip id. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_CHIP_ID,
|
||||||
|
/* The Tegra SOC revision number. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_REVISION,
|
||||||
|
/* The Tegra SOC platform type. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_PLATFORM,
|
||||||
|
/* The Tegra SOC socket id. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_SOCKET,
|
||||||
|
/* The number of available IPs. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_COUNT,
|
||||||
|
/* Array containing the id of available IPs. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_LIST,
|
||||||
|
/* The number of available resources. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_RESOURCE_AVAILABLE_COUNT,
|
||||||
|
/* Array containing the id of available resources. */
|
||||||
|
NV_SOC_HWPM_DEVICE_ATTRIBUTE_RESOURCE_AVAILABLE_LIST,
|
||||||
|
} nv_soc_hwpm_device_attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get device information.
|
||||||
|
*
|
||||||
|
* This function retrieves device-specific information based on the specified
|
||||||
|
* attribute.
|
||||||
|
*
|
||||||
|
* @param[in] device Handle to NV_SOC_HWPM device.
|
||||||
|
*
|
||||||
|
* @param[in] attribute The device attribute to query. See @ref
|
||||||
|
* nv_soc_hwpm_device_attribute.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_CHIP_ID: the info
|
||||||
|
* buffer should fit @ref tegra_soc_hwpm_chip_id.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_REVISION: the info
|
||||||
|
* buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_PLATFORM: the info
|
||||||
|
* buffer should fit @ref tegra_soc_hwpm_platform.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_SOCKET: the info
|
||||||
|
* buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_COUNT: the
|
||||||
|
* info buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_LIST: the
|
||||||
|
* info buffer should point to an array of
|
||||||
|
* nv_soc_hwpm_ip. The size of the array should fit
|
||||||
|
* the value of @ref
|
||||||
|
* NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_COUNT.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_RESOURCE_AVAILABLE_COUNT:
|
||||||
|
* the info buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_DEVICE_ATTRIBUTE_RESOURCE_AVAILABLE_LIST:
|
||||||
|
* the info buffer should point to an array of
|
||||||
|
* nv_soc_hwpm_resource. The size of the array should
|
||||||
|
* fit the value of @ref
|
||||||
|
* NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_COUNT.
|
||||||
|
* @param[in] info_size The size of the \p info buffer.
|
||||||
|
* @param[out] info Pointer to user/application allocated buffer to store the
|
||||||
|
* attribute value.
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if device is invalid, attribute is invalid, info_size does
|
||||||
|
* not fit the attribute value, info is NULL.
|
||||||
|
*/
|
||||||
|
int nv_soc_hwpm_device_get_info(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_device_attribute attribute,
|
||||||
|
uint32_t info_size, void* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IP attributes. See \ref nv_soc_hwpm_ip_get_info.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/**
|
||||||
|
* The IP availability status. 1 means IP is available, 0 means IP is
|
||||||
|
* unavailable.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_IP_ATTRIBUTE_IS_AVAILABLE,
|
||||||
|
/* The IP instance/element max count. */
|
||||||
|
NV_SOC_HWPM_IP_ATTRIBUTE_INST_MAX_COUNT,
|
||||||
|
/**
|
||||||
|
* The flatten IP instance/element floorsweeping mask. The LSB is the
|
||||||
|
* lowest element/instance. The number of bits is equal to the
|
||||||
|
* @ref NV_SOC_HWPM_IP_ATTRIBUTE_INST_MAX_COUNT.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_IP_ATTRIBUTE_FS_MASK,
|
||||||
|
} nv_soc_hwpm_ip_attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get information about a specific IP.
|
||||||
|
*
|
||||||
|
* @param[in] device The SOC HWPM device handle.
|
||||||
|
* @param[in] ip The IP to query information about.
|
||||||
|
* @param[in] attribute The IP attribute to query. See @ref nv_soc_hwpm_ip_attribute.
|
||||||
|
* - NV_SOC_HWPM_IP_ATTRIBUTE_IS_AVAILABLE: value should fit
|
||||||
|
* uint32_t.
|
||||||
|
* - NV_SOC_HWPM_IP_ATTRIBUTE_INST_MAX_COUNT: value should
|
||||||
|
* fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_IP_ATTRIBUTE_FS_MASK: value should fit
|
||||||
|
* the number of bits equal to the value of @ref
|
||||||
|
* NV_SOC_HWPM_IP_ATTRIBUTE_INST_MAX_COUNT.
|
||||||
|
* @param[in] info_size The size of the \p info buffer.
|
||||||
|
* @param[out] info Pointer to user/application allocated buffer to store the
|
||||||
|
* attribute value.
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if device is invalid, ip is invalid, attribute is invalid,
|
||||||
|
* info_size does not fit the attribute value, or info is NULL.
|
||||||
|
*/
|
||||||
|
int nv_soc_hwpm_ip_get_info(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_ip ip,
|
||||||
|
nv_soc_hwpm_ip_attribute attribute, uint32_t info_size, void* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resource attributes. See \ref nv_soc_hwpm_resource_get_info.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/**
|
||||||
|
* The resource availability status. The output type of this attribute is
|
||||||
|
* uint32_t. 1 means resource is available, 0 means unavailable.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_RESOURCE_ATTRIBUTE_IS_AVAILABLE,
|
||||||
|
} nv_soc_hwpm_resource_attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get information about a specific resource.
|
||||||
|
*
|
||||||
|
* @param[in] device The SOC HWPM device handle.
|
||||||
|
* @param[in] resource The resource to query information about.
|
||||||
|
* @param[in] attribute The resource attribute to query.
|
||||||
|
* See @ref nv_soc_hwpm_resource_attribute.
|
||||||
|
* - NV_SOC_HWPM_RESOURCE_ATTRIBUTE_IS_AVAILABLE: value should
|
||||||
|
* fit uint32_t.
|
||||||
|
* @param[in] info_size The size of the \p info buffer.
|
||||||
|
* @param[out] info Pointer to user/application allocated buffer to store the
|
||||||
|
* attribute value.
|
||||||
|
*
|
||||||
|
* @return 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if device is invalid, resource is invalid, attribute is
|
||||||
|
* invalid, info_size does not fit the attribute value, or info is NULL.
|
||||||
|
*/
|
||||||
|
int nv_soc_hwpm_resource_get_info(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_resource resource,
|
||||||
|
nv_soc_hwpm_resource_attribute attribute, uint32_t info_size, void* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing opaque handle to an NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* The user will need this handle to do the following:
|
||||||
|
* - reserve the resources that will be used in the experiment
|
||||||
|
* - manage the PMA buffer
|
||||||
|
* - perform regops
|
||||||
|
* - get PMA channel state
|
||||||
|
* - working with cross trigger
|
||||||
|
* - credit programming
|
||||||
|
*/
|
||||||
|
typedef struct { uint64_t handle; } nv_soc_hwpm_session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a session on a device.
|
||||||
|
*
|
||||||
|
* Internally this will open connection to the corresponding driver device node
|
||||||
|
* and keep it open until the session is freed.
|
||||||
|
*
|
||||||
|
* @param[in] device Handle to NV_SOC_HWPM device.
|
||||||
|
*
|
||||||
|
* @param[out] session Pointer to NV_SOC_HWPM session handle.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: one of the arguments is invalid.
|
||||||
|
* -ENOMEM: unable to create new session since the maximum session count
|
||||||
|
* is reached.
|
||||||
|
* Other non zero status corresponds to failure when opening the driver
|
||||||
|
* device node.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_alloc(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_session *session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free a session on a device.
|
||||||
|
*
|
||||||
|
* This will reset the state of a session, cleanup any allocated buffer, and
|
||||||
|
* close connection to the driver device node.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_free(
|
||||||
|
nv_soc_hwpm_session session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Session attributes. See \ref nv_soc_hwpm_session_get_info.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/* The device handle associated with the session. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_DEVICE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The session's start status. 1 means the session is started. 0 means
|
||||||
|
* session is not started.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_SESSION_STARTED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The session's PMA buffer allocation status. 1 means the buffers
|
||||||
|
* are allocated. 0 means buffers are not allocated.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_BUFFER_ALLOCATED,
|
||||||
|
|
||||||
|
/* Size of the session's record buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_SIZE,
|
||||||
|
/* CPU accessible address of the session's record buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_CPU_VA,
|
||||||
|
/* PMA accessible addres of the session's record buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_PMA_VA,
|
||||||
|
/* Opaque handle of the session's record buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_HANDLE,
|
||||||
|
|
||||||
|
/* Size of the session's mem bytes buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_SIZE,
|
||||||
|
/* CPU accessible address of the session's mem bytes buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_CPU_VA,
|
||||||
|
/* PMA accessible addres of the session's mem bytes buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_PMA_VA,
|
||||||
|
/* Opaque handle of the session's mem bytes buffer. */
|
||||||
|
NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_HANDLE,
|
||||||
|
} nv_soc_hwpm_session_attribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get info of an NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] attribute The session attribute to query.
|
||||||
|
* See @ref nv_soc_hwpm_session_attribute.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_DEVICE: the info buffer
|
||||||
|
* should fit @ref nv_soc_hwpm_device.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_SESSION_STARTED: the info
|
||||||
|
* buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_BUFFER_ALLOCATED: the
|
||||||
|
* info buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_SIZE:
|
||||||
|
* the info buffer should fit size_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_CPU_VA:
|
||||||
|
* the info buffer should fit (void*).
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_PMA_VA:
|
||||||
|
* the info buffer should fit uint64_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_HANDLE:
|
||||||
|
* the info buffer should fit uint32_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_SIZE:
|
||||||
|
* the info buffer should fit size_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_CPU_VA:
|
||||||
|
* the info buffer should fit (void*).
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_PMA_VA:
|
||||||
|
* the info buffer should fit uint64_t.
|
||||||
|
* - NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_HANDLE:
|
||||||
|
* the info buffer should fit uint32_t.
|
||||||
|
* @param[in] info_size The size of the \p info buffer.
|
||||||
|
* @param[out] info Pointer to user/application allocated buffer to store the
|
||||||
|
* attribute value.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, attribute is invalid, info_size does
|
||||||
|
* not fit the attribute value, or info is NULL.
|
||||||
|
*/
|
||||||
|
int nv_soc_hwpm_session_get_info(
|
||||||
|
nv_soc_hwpm_session session, nv_soc_hwpm_session_attribute attribute,
|
||||||
|
uint32_t info_size, void* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reserve the resources that will be monitored by a session.
|
||||||
|
*
|
||||||
|
* This will perform the IOCTLs to reserve the resources to the driver.
|
||||||
|
* Note that since the driver does not expose interface to release a resource,
|
||||||
|
* the reserved resources can not be changed until the session is freed.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] res_count The number of element in \p res_ids
|
||||||
|
*
|
||||||
|
* @param[in] res_ids Array containing the resource id.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, res_count is invalid, res_ids is
|
||||||
|
* NULL, res_ids contain unavailable resource id, or the session
|
||||||
|
* has already started.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_reserve_resources(
|
||||||
|
nv_soc_hwpm_session session, uint32_t res_count,
|
||||||
|
const nv_soc_hwpm_resource *res_ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set all supported resources to be monitored to a session.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, or the session has already started.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_reserve_all_resources(
|
||||||
|
nv_soc_hwpm_session session);
|
||||||
|
|
||||||
|
/* Tegra SOC HWPM PMA buffer cache coherency type */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
TEGRA_SOC_HWPM_COHERENCY_TYPE_UNCACHED,
|
||||||
|
TEGRA_SOC_HWPM_COHERENCY_TYPE_CACHED,
|
||||||
|
TEGRA_SOC_HWPM_COHERENCY_TYPE_COUNT
|
||||||
|
} tegra_soc_hwpm_coherency_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing NV_SOC_HWPM PMA buffer allocation parameters.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
size_t size;
|
||||||
|
void* cpu_va;
|
||||||
|
tegra_soc_hwpm_coherency_type coherency_type;
|
||||||
|
} nv_soc_hwpm_pma_buffer_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory for PMA channel.
|
||||||
|
*
|
||||||
|
* After a successful allocation, the user can call nv_soc_hwpm_session_get_info
|
||||||
|
* to get the allocation result, i.e nv_soc_hwpm_session_info::record_buffer
|
||||||
|
* and nv_soc_hwpm_session_info::mem_bytes_buffer.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] record_buffer_params Pointer to PMA record buffer allocation
|
||||||
|
* param structure.
|
||||||
|
*
|
||||||
|
* @param[in] mem_bytes_buffer_params Pointer to PMA mem_bytes buffer allocation
|
||||||
|
* param structure.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, a prior allocation has been made, or
|
||||||
|
* the session has already started.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
* -ENOMEM: failure on allocating memory.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_alloc_pma(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
const nv_soc_hwpm_pma_buffer_params *record_buffer_params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing parameter to update and query PMA channel state.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t in_mem_bump;
|
||||||
|
uint8_t in_stream_mem_bytes;
|
||||||
|
uint8_t in_read_mem_head;
|
||||||
|
uint8_t in_check_overflow;
|
||||||
|
uint64_t out_mem_head;
|
||||||
|
uint8_t out_overflowed;
|
||||||
|
} nv_soc_hwpm_pma_channel_state_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set and get PMA channel state.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] param Structure containing the input/output arguments.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, param is NULL, or the session has
|
||||||
|
* not started yet.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_set_get_pma_state(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
nv_soc_hwpm_pma_channel_state_params* param);
|
||||||
|
|
||||||
|
/* Tegra SOC HWPM enums for querying various info */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/* Read credits information */
|
||||||
|
TEGRA_SOC_HWPM_GET_TYPE_HS_CREDITS,
|
||||||
|
/* Read total HS credits*/
|
||||||
|
TEGRA_SOC_HWPM_GET_TYPE_TOTAL_HS_CREDITS,
|
||||||
|
TEGRA_SOC_HWPM_GET_TYPE_COUNT,
|
||||||
|
} tegra_soc_hwpm_get_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Credit programming interface to get HS credits.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] type credit or total HS credits.
|
||||||
|
*
|
||||||
|
* @param[in] num_hs_credits Pointer to output variable containing HS credits.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, type is invalid, num_hs_credits
|
||||||
|
* is NULL, or the session has not started yet.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_get_hs_credits(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
tegra_soc_hwpm_get_type type,
|
||||||
|
uint32_t* num_hs_credits);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing parameter to configure HS credit.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t cblock_idx;
|
||||||
|
uint32_t num_credits_per_chiplet;
|
||||||
|
} nv_soc_hwpm_config_hs_credit_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Credit programming interface to configure HS credits.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] param_count Number of element in \p params.
|
||||||
|
*
|
||||||
|
* @param[in] params Structure containing the array of credit param.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, param_count is invalid, params is
|
||||||
|
* NULL, or the session has not started yet.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_config_hs_credits(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
uint32_t param_count,
|
||||||
|
const nv_soc_hwpm_config_hs_credit_params* params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starting session by binding the resources.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, or the session has already started.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_start(
|
||||||
|
nv_soc_hwpm_session session);
|
||||||
|
|
||||||
|
/* Tegra SOC HWPM enums for regops cmd */
|
||||||
|
typedef enum {
|
||||||
|
NV_SOC_HWPM_REG_OPS_CMD_INVALID,
|
||||||
|
NV_SOC_HWPM_REG_OPS_CMD_READ32,
|
||||||
|
NV_SOC_HWPM_REG_OPS_CMD_READ64,
|
||||||
|
NV_SOC_HWPM_REG_OPS_CMD_WRITE32,
|
||||||
|
NV_SOC_HWPM_REG_OPS_CMD_WRITE64,
|
||||||
|
NV_SOC_HWPM_REG_OPS_CMD_COUNT
|
||||||
|
} nv_soc_hwpm_reg_ops_cmd;
|
||||||
|
|
||||||
|
/* Tegra SOC HWPM enums for regops status */
|
||||||
|
typedef enum {
|
||||||
|
NV_SOC_HWPM_REG_OPS_STATUS_SUCCESS,
|
||||||
|
NV_SOC_HWPM_REG_OPS_STATUS_INVALID_CMD,
|
||||||
|
NV_SOC_HWPM_REG_OPS_STATUS_INVALID_OFFSET,
|
||||||
|
NV_SOC_HWPM_REG_OPS_STATUS_INSUFFICIENT_PERMISSIONS,
|
||||||
|
NV_SOC_HWPM_REG_OPS_STATUS_COUNT
|
||||||
|
} nv_soc_hwpm_reg_ops_status;
|
||||||
|
|
||||||
|
/* Tegra SOC HWPM enums for regops validation */
|
||||||
|
typedef enum {
|
||||||
|
NV_SOC_HWPM_REG_OPS_VALIDATION_MODE_INVALID,
|
||||||
|
NV_SOC_HWPM_REG_OPS_VALIDATION_MODE_FAIL_ON_FIRST_ERROR,
|
||||||
|
NV_SOC_HWPM_REG_OPS_VALIDATION_MODE_CONTINUE_ON_ERROR,
|
||||||
|
NV_SOC_HWPM_REG_OPS_VALIDATION_MODE_COUNT
|
||||||
|
} nv_soc_hwpm_reg_ops_validation_mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing parameter to perform regops.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/* register offset, as per kernel team this can be 40 bits */
|
||||||
|
uint64_t in_offset;
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint32_t in_out_val32;
|
||||||
|
uint64_t in_out_val64;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint32_t in_mask32;
|
||||||
|
uint64_t in_mask64;
|
||||||
|
};
|
||||||
|
|
||||||
|
nv_soc_hwpm_reg_ops_cmd in_cmd;
|
||||||
|
nv_soc_hwpm_reg_ops_status out_status;
|
||||||
|
} nv_soc_hwpm_reg_ops_params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function to read/write HWPM registers.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] param_count Number of element in \p params.
|
||||||
|
*
|
||||||
|
* @param[in] params Structure containing the array of regops param.
|
||||||
|
*
|
||||||
|
* @param[in] mode Validation mode.
|
||||||
|
*
|
||||||
|
* @param[out] all_reg_ops_passed Pointer to output variable, 1 means all the
|
||||||
|
* operations are successful, 0 means one or
|
||||||
|
* more are failed.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, param_count is invalid, params is
|
||||||
|
* NULL, or the session has not started yet.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_regops(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
const size_t param_count,
|
||||||
|
nv_soc_hwpm_reg_ops_params* params,
|
||||||
|
nv_soc_hwpm_reg_ops_validation_mode mode,
|
||||||
|
int* all_reg_ops_passed);
|
||||||
|
|
||||||
|
/* Tegra SOC HWPM trigger session type */
|
||||||
|
typedef enum {
|
||||||
|
NV_SOC_HWPM_TRIGGER_SESSION_TYPE_INVALID,
|
||||||
|
NV_SOC_HWPM_TRIGGER_SESSION_TYPE_PROFILER, /* maps to Start-Stop triggers */
|
||||||
|
NV_SOC_HWPM_TRIGGER_SESSION_TYPE_SAMPLER, /* maps to Periodic triggers */
|
||||||
|
NV_SOC_HWPM_TRIGGER_SESSION_TYPE_COUNT
|
||||||
|
} nv_soc_hwpm_trigger_session_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trigger mask setup interface.
|
||||||
|
*
|
||||||
|
* Used for programming cross-trigger config in the SECURE trigger mask
|
||||||
|
* registers.
|
||||||
|
*
|
||||||
|
* @param[in] session Handle to NV_SOC_HWPM session.
|
||||||
|
*
|
||||||
|
* @param[in] enable_cross_trigger 1 to enable and 0 to disable cross trigger.
|
||||||
|
*
|
||||||
|
* @param[in] session_type Trigger session type.
|
||||||
|
*
|
||||||
|
* @returns This function returns 0 on success, negative errno on failure:
|
||||||
|
* -EINVAL: if session is invalid, or the session has not started yet.
|
||||||
|
* -EIO: error on IOCTLs to the driver.
|
||||||
|
*/
|
||||||
|
NV_SOC_HWPM_API_EXPORT int nv_soc_hwpm_session_setup_trigger(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
int enable_cross_trigger,
|
||||||
|
nv_soc_hwpm_trigger_session_type session_type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__NV_SOC_HWPM_H__*/
|
||||||
107
libnvsochwpm/include/nv_soc_hwpm_loader.hpp
Normal file
107
libnvsochwpm/include/nv_soc_hwpm_loader.hpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NV_SOC_HWPM_LOADER_H__
|
||||||
|
#define __NV_SOC_HWPM_LOADER_H__
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void* handle;
|
||||||
|
decltype(nv_soc_hwpm_init)* nv_soc_hwpm_init_fn;
|
||||||
|
decltype(nv_soc_hwpm_exit)* nv_soc_hwpm_exit_fn;
|
||||||
|
decltype(nv_soc_hwpm_system_get_info)* nv_soc_hwpm_system_get_info_fn;
|
||||||
|
decltype(nv_soc_hwpm_get_devices)* nv_soc_hwpm_get_devices_fn;
|
||||||
|
decltype(nv_soc_hwpm_device_get_info)* nv_soc_hwpm_device_get_info_fn;
|
||||||
|
decltype(nv_soc_hwpm_ip_get_info)* nv_soc_hwpm_ip_get_info_fn;
|
||||||
|
decltype(nv_soc_hwpm_resource_get_info)* nv_soc_hwpm_resource_get_info_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_alloc)* nv_soc_hwpm_session_alloc_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_free)* nv_soc_hwpm_session_free_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_get_info)* nv_soc_hwpm_session_get_info_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_reserve_resources)* nv_soc_hwpm_session_reserve_resources_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_reserve_all_resources)* nv_soc_hwpm_session_reserve_all_resources_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_alloc_pma)* nv_soc_hwpm_session_alloc_pma_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_set_get_pma_state)* nv_soc_hwpm_session_set_get_pma_state_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_get_hs_credits)* nv_soc_hwpm_session_get_hs_credits_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_config_hs_credits)* nv_soc_hwpm_session_config_hs_credits_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_start)* nv_soc_hwpm_session_start_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_regops)* nv_soc_hwpm_session_regops_fn;
|
||||||
|
decltype(nv_soc_hwpm_session_setup_trigger)* nv_soc_hwpm_session_setup_trigger_fn;
|
||||||
|
} nv_soc_hwpm_api_table;
|
||||||
|
|
||||||
|
#define XSTR(a) STR(a)
|
||||||
|
#define STR(a) #a
|
||||||
|
#define GET_HWPM_SYM(table, name) GET_HWPM_SYM_FN(table, name, name ## _fn)
|
||||||
|
#define GET_HWPM_SYM_FN(table, name, name_fn) \
|
||||||
|
table->name_fn = (decltype(name)* )dlsym(table->handle, XSTR(name)); \
|
||||||
|
if (table->name_fn == NULL) { \
|
||||||
|
fprintf (stderr, "%s\n", dlerror()); \
|
||||||
|
return -EINVAL; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int load_nv_soc_hwpm(const char* path, nv_soc_hwpm_api_table* table) {
|
||||||
|
if (table == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (table->handle != NULL) {
|
||||||
|
fprintf (stderr, "NvSocHwpm already loaded\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->handle = dlopen (path, RTLD_LAZY);
|
||||||
|
if (!table->handle) {
|
||||||
|
fprintf (stderr, "Failed to load NvSocHwpm: %s\n", dlerror());
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_init);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_exit);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_system_get_info);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_get_devices);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_device_get_info);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_ip_get_info);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_resource_get_info);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_alloc);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_free);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_get_info);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_reserve_resources);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_reserve_all_resources);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_alloc_pma);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_set_get_pma_state);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_get_hs_credits);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_config_hs_credits);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_start);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_regops);
|
||||||
|
GET_HWPM_SYM(table, nv_soc_hwpm_session_setup_trigger);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int unload_nv_soc_hwpm(nv_soc_hwpm_api_table* table) {
|
||||||
|
if (table == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (table->handle == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dlclose(table->handle);
|
||||||
|
table->handle = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __NV_SOC_HWPM_LOADER_H__ */
|
||||||
879
libnvsochwpm/nv_soc_hwpm.c
Normal file
879
libnvsochwpm/nv_soc_hwpm.c
Normal file
@@ -0,0 +1,879 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
#include "os/nv_soc_hwpm_os.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LIB_VERSION_MAJOR 0
|
||||||
|
#define LIB_VERSION_MINOR 1
|
||||||
|
|
||||||
|
/* Internal tracker of the number of enumerated NV_SOC_HWPM devices. */
|
||||||
|
static uint32_t g_device_count = 0;
|
||||||
|
|
||||||
|
/* Internal NV_SOC_HWPM device array. */
|
||||||
|
static nv_soc_hwpm_device_int g_devices_int[MAX_DEVICE_COUNT] = {{ 0 }};
|
||||||
|
|
||||||
|
/* The nv_soc_hwpm_device handle contains the index in g_devices_int array. */
|
||||||
|
nv_soc_hwpm_device_int* to_device_int(uint64_t handle) {
|
||||||
|
const uint64_t dev_idx = to_dev_idx(handle);
|
||||||
|
if (dev_idx >= g_device_count) {
|
||||||
|
log_error("Invalid device handle: %llu\n", handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &g_devices_int[dev_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The nv_soc_hwpm_session handle contains the index in
|
||||||
|
* nv_soc_hwpm_device_int::session array.
|
||||||
|
*/
|
||||||
|
nv_soc_hwpm_session_int* to_session_int(uint64_t handle) {
|
||||||
|
nv_soc_hwpm_device_int* dev_int = to_device_int(handle);
|
||||||
|
if (dev_int == NULL) {
|
||||||
|
log_error("Invalid device session: %llu\n", handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t session_idx = to_session_idx(handle);
|
||||||
|
if (session_idx >= dev_int->session_count_max) {
|
||||||
|
log_error("Invalid session: %llu\n", handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev_int->session_int[session_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_init(void) {
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (g_device_count == 0) {
|
||||||
|
ret = nv_soc_hwpm_os_enumerate_device(
|
||||||
|
MAX_DEVICE_COUNT, &g_device_count, g_devices_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv_soc_hwpm_exit(void) {
|
||||||
|
uint32_t i, s;
|
||||||
|
|
||||||
|
for (i = 0; i < g_device_count; ++i) {
|
||||||
|
for (s = 0; s < g_devices_int[i].session_count_max; ++s) {
|
||||||
|
if (g_devices_int[i].session_int[s]) {
|
||||||
|
nv_soc_hwpm_session session =
|
||||||
|
{.handle = to_session_handle(i, s)};
|
||||||
|
nv_soc_hwpm_session_free(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_device_count = 0;
|
||||||
|
memset(&g_devices_int, 0, sizeof(g_devices_int));
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_system_get_info(
|
||||||
|
nv_soc_hwpm_system_attribute attribute, uint32_t info_size, void* info)
|
||||||
|
{
|
||||||
|
if (info == NULL) {
|
||||||
|
log_error("Invalid info param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MAJOR:
|
||||||
|
if (info_size < sizeof(uint16_t)) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
sizeof(uint16_t), info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint16_t*)info) = LIB_VERSION_MAJOR;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MINOR:
|
||||||
|
if (info_size < sizeof(uint16_t)) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
sizeof(uint16_t), info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint16_t*)info) = LIB_VERSION_MINOR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_get_devices(uint32_t *count, nv_soc_hwpm_device *devices)
|
||||||
|
{
|
||||||
|
uint32_t i, dev_count;
|
||||||
|
|
||||||
|
if (count == NULL) {
|
||||||
|
log_error("Invalid count param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*count == 0) {
|
||||||
|
*count = g_device_count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devices == NULL) {
|
||||||
|
log_error("Invalid devices param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_count = (*count < g_device_count) ? *count : g_device_count;
|
||||||
|
for (i = 0; i < dev_count; ++i) {
|
||||||
|
devices[i].handle = to_dev_handle(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_device_get_info(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_device_attribute attribute,
|
||||||
|
uint32_t info_size, void* info)
|
||||||
|
{
|
||||||
|
uint32_t size_expected;
|
||||||
|
nv_soc_hwpm_device_int* dev_int = to_device_int(device.handle);
|
||||||
|
|
||||||
|
if (dev_int == NULL) {
|
||||||
|
log_error("Invalid device handle: %llu\n", device.handle);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == NULL) {
|
||||||
|
log_error("Invalid info param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info, 0, info_size);
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_CHIP_ID:
|
||||||
|
size_expected = sizeof(tegra_soc_hwpm_chip_id);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((tegra_soc_hwpm_chip_id*)info) =
|
||||||
|
dev_int->dev_info.soc_chip_id;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_REVISION:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->dev_info.soc_revision;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_PLATFORM:
|
||||||
|
size_expected = sizeof(tegra_soc_hwpm_platform);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((tegra_soc_hwpm_platform*)info) =
|
||||||
|
dev_int->dev_info.soc_platform;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_SOC_SOCKET:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->dev_info.soc_socket;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_COUNT:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->dev_info.ip_available_count;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_IP_AVAILABLE_LIST:
|
||||||
|
size_expected = sizeof(nv_soc_hwpm_ip) * dev_int->dev_info.ip_available_count;
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
memcpy(info, dev_int->dev_info.ip_available_list, size_expected);
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_RESOURCE_AVAILABLE_COUNT:
|
||||||
|
if (info_size < sizeof(uint32_t)) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
sizeof(uint32_t), info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->dev_info.res_available_count;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_DEVICE_ATTRIBUTE_RESOURCE_AVAILABLE_LIST:
|
||||||
|
size_expected =
|
||||||
|
sizeof(nv_soc_hwpm_resource) * dev_int->dev_info.res_available_count;
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
memcpy(info, dev_int->dev_info.res_available_list, size_expected);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("Invalid attribute: %d\n", attribute);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_ip_get_info(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_ip ip,
|
||||||
|
nv_soc_hwpm_ip_attribute attribute, uint32_t info_size, void* info)
|
||||||
|
{
|
||||||
|
uint32_t size_expected;
|
||||||
|
nv_soc_hwpm_device_int* dev_int = to_device_int(device.handle);
|
||||||
|
|
||||||
|
if (dev_int == NULL) {
|
||||||
|
log_error("Invalid device handle: %llu\n", device.handle);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == NULL) {
|
||||||
|
log_error("Invalid info param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip >= NV_SOC_HWPM_NUM_IPS) {
|
||||||
|
log_error("Invalid IP ID: %d\n", ip);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info, 0, info_size);
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case NV_SOC_HWPM_IP_ATTRIBUTE_IS_AVAILABLE:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->ip_info[ip].is_available;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_IP_ATTRIBUTE_INST_MAX_COUNT:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->ip_info[ip].inst_max_count;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_IP_ATTRIBUTE_FS_MASK:
|
||||||
|
/* Get the minimal byte size to fit the fs_mask. */
|
||||||
|
size_expected =
|
||||||
|
ALIGN_UP(dev_int->ip_info[ip].inst_max_count, 8) / 8;
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
memcpy(info, dev_int->ip_info[ip].fs_mask, size_expected);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("Invalid attribute: %d\n", attribute);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_resource_get_info(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_resource resource,
|
||||||
|
nv_soc_hwpm_resource_attribute attribute, uint32_t info_size, void* info)
|
||||||
|
{
|
||||||
|
uint32_t size_expected;
|
||||||
|
nv_soc_hwpm_device_int* dev_int = to_device_int(device.handle);
|
||||||
|
|
||||||
|
if (dev_int == NULL) {
|
||||||
|
log_error("Invalid device handle: %llu\n", device.handle);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == NULL) {
|
||||||
|
log_error("Invalid info param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource >= NV_SOC_HWPM_NUM_RESOURCES) {
|
||||||
|
log_error("Invalid resource ID: %d\n", resource);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info, 0, info_size);
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case NV_SOC_HWPM_RESOURCE_ATTRIBUTE_IS_AVAILABLE:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) =
|
||||||
|
dev_int->res_info[resource].is_available;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("Invalid attribute: %d\n", attribute);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_alloc(
|
||||||
|
nv_soc_hwpm_device device, nv_soc_hwpm_session *session)
|
||||||
|
{
|
||||||
|
uint32_t session_idx;
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
if (session == NULL) {
|
||||||
|
log_error("Invalid null session\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nv_soc_hwpm_device_int* dev_int = to_device_int(device.handle);
|
||||||
|
if (dev_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find empty session slot. */
|
||||||
|
for (session_idx = 0; session_idx < dev_int->session_count_max; ++session_idx) {
|
||||||
|
if (!dev_int->session_int[session_idx]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_idx >= dev_int->session_count_max) {
|
||||||
|
log_error("Maximum session count is reached, dev: %s\n",
|
||||||
|
dev_int->dev_path);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open connection to driver. */
|
||||||
|
fd = nv_soc_hwpm_os_open_hwpm_device(dev_int->dev_path);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_error("Failed opening HWPM device: %s, errno: %s\n",
|
||||||
|
dev_int->dev_path, strerror(errno));
|
||||||
|
ret = -errno;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
nv_soc_hwpm_session_int* session_int = malloc(sizeof(nv_soc_hwpm_session_int));
|
||||||
|
memset(session_int, 0, sizeof(nv_soc_hwpm_session_int));
|
||||||
|
session_int->fd = fd;
|
||||||
|
session_int->dev_int = (void*)dev_int;
|
||||||
|
session_int->info.device = device;
|
||||||
|
|
||||||
|
dev_int->session_int[session_idx] = session_int;
|
||||||
|
dev_int->session_count += 1;
|
||||||
|
|
||||||
|
session->handle = to_session_handle(to_dev_idx(device.handle), session_idx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_resource_reservation_status(
|
||||||
|
nv_soc_hwpm_session_int* session_int, uint8_t is_reserved)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
nv_soc_hwpm_device_int* dev_int = (void*)session_int->dev_int;
|
||||||
|
nv_soc_hwpm_resource_info *res_info = dev_int->res_info;
|
||||||
|
nv_soc_hwpm_session_info *session_info = &session_int->info;
|
||||||
|
|
||||||
|
for (i = 0; i < session_info->resource_count; ++i) {
|
||||||
|
const uint32_t res_id = session_info->resource_ids[i];
|
||||||
|
res_info[res_id].is_reserved = is_reserved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_free(
|
||||||
|
nv_soc_hwpm_session session)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_device_int* dev_int;
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark the resources as unreserved. */
|
||||||
|
update_resource_reservation_status(session_int, 0);
|
||||||
|
|
||||||
|
/* Release the buffers.*/
|
||||||
|
nv_soc_hwpm_os_session_free_pma(session_int);
|
||||||
|
|
||||||
|
/* Close driver connection. */
|
||||||
|
nv_soc_hwpm_os_close_hwpm_device(session_int->fd);
|
||||||
|
|
||||||
|
/* Cleanup session object. */
|
||||||
|
dev_int = (void*)session_int->dev_int;
|
||||||
|
const uint32_t session_idx = to_session_idx(session.handle);
|
||||||
|
|
||||||
|
free(session_int);
|
||||||
|
dev_int->session_int[session_idx] = NULL;
|
||||||
|
dev_int->session_count -= 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_get_info(
|
||||||
|
nv_soc_hwpm_session session, nv_soc_hwpm_session_attribute attribute,
|
||||||
|
uint32_t info_size, void* info)
|
||||||
|
{
|
||||||
|
uint32_t size_expected;
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
log_error("Invalid session handle: %llu\n", session.handle);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info == NULL) {
|
||||||
|
log_error("Invalid info param\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info, 0, info_size);
|
||||||
|
|
||||||
|
switch (attribute) {
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_DEVICE:
|
||||||
|
size_expected = sizeof(nv_soc_hwpm_device);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
memcpy(info, &session_int->info.device, size_expected);
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_SESSION_STARTED:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) = session_int->info.is_session_started;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_BUFFER_ALLOCATED:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) = session_int->info.is_pma_buffer_allocated;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_SIZE:
|
||||||
|
size_expected = sizeof(size_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((size_t*)info) = session_int->info.record_buffer.size;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_CPU_VA:
|
||||||
|
size_expected = sizeof(void*);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((void**)info) = session_int->info.record_buffer.buffer;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_PMA_VA:
|
||||||
|
size_expected = sizeof(uint64_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint64_t*)info) = session_int->info.record_buffer.pma_va;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_HANDLE:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) = session_int->info.record_buffer.handle;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_SIZE:
|
||||||
|
size_expected = sizeof(size_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((size_t*)info) = session_int->info.mem_bytes_buffer.size;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_CPU_VA:
|
||||||
|
size_expected = sizeof(void*);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((void**)info) = session_int->info.mem_bytes_buffer.buffer;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_PMA_VA:
|
||||||
|
size_expected = sizeof(uint64_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint64_t*)info) = session_int->info.mem_bytes_buffer.pma_va;
|
||||||
|
break;
|
||||||
|
case NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_HANDLE:
|
||||||
|
size_expected = sizeof(uint32_t);
|
||||||
|
if (info_size < size_expected) {
|
||||||
|
log_error("Invalid info size. Expected %d, got %d\n",
|
||||||
|
size_expected, info_size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*((uint32_t*)info) = session_int->info.mem_bytes_buffer.handle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("Invalid attribute: %d\n", attribute);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_reserve_resources(
|
||||||
|
nv_soc_hwpm_session session, uint32_t res_count,
|
||||||
|
const nv_soc_hwpm_resource *res_ids)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t i;
|
||||||
|
nv_soc_hwpm_device_int* dev_int;
|
||||||
|
nv_soc_hwpm_resource_info* res_info;
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res_count == 0 ||
|
||||||
|
res_count > NV_SOC_HWPM_NUM_RESOURCES ||
|
||||||
|
res_ids == NULL) {
|
||||||
|
log_error("Invalid resource count: %u or resource id array: %p\n",
|
||||||
|
res_count, res_ids);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the session is already started. */
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (session_info->is_session_started) {
|
||||||
|
log_error("Unable to reserve resources. Session is already started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_int = (void*)session_int->dev_int;
|
||||||
|
res_info = dev_int->res_info;
|
||||||
|
|
||||||
|
/* Check the status of the requested resource(s) */
|
||||||
|
for (i = 0; i < res_count; ++i) {
|
||||||
|
const uint32_t res_id = res_ids[i];
|
||||||
|
if (res_id >= NV_SOC_HWPM_NUM_RESOURCES) {
|
||||||
|
log_error("Invalid resource id: %u on index: %u\n",
|
||||||
|
res_id, i);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res_info[res_id].is_available != 1) {
|
||||||
|
log_error("Resource id: %u is not available\n", res_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the request to the driver to reserve the resources. */
|
||||||
|
for (i = 0; i < res_count; ++i) {
|
||||||
|
const uint32_t res_id = res_ids[i];
|
||||||
|
ret = nv_soc_hwpm_os_session_reserve_resources(session_int, res_id);
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed to reserve resource id: %u\n", res_id);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the session's resource list. */
|
||||||
|
memset(session_info->resource_ids, 0, sizeof(session_info->resource_ids));
|
||||||
|
memcpy(session_info->resource_ids, res_ids, res_count * sizeof(*session_info->resource_ids));
|
||||||
|
session_info->resource_count = res_count;
|
||||||
|
|
||||||
|
/* Update the reservation status of the resources. */
|
||||||
|
update_resource_reservation_status(session_int, 1);
|
||||||
|
session_info->is_resource_reserved = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_reserve_all_resources(
|
||||||
|
nv_soc_hwpm_session session)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_device_int* dev_int;
|
||||||
|
const nv_soc_hwpm_device_info* dev_info;
|
||||||
|
|
||||||
|
dev_int = to_device_int(session.handle);
|
||||||
|
if (dev_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info = &dev_int->dev_info;
|
||||||
|
return nv_soc_hwpm_session_reserve_resources(
|
||||||
|
session, dev_info->res_available_count, dev_info->res_available_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_alloc_pma(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
const nv_soc_hwpm_pma_buffer_params *record_buffer_params)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
if (record_buffer_params == NULL) {
|
||||||
|
log_error("Invalid record buffer param: %p\n", record_buffer_params);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (session_info->is_session_started) {
|
||||||
|
log_error("Session is already started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_info->is_pma_buffer_allocated == 1) {
|
||||||
|
log_error("PMA buffers are already allocated\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_alloc_pma(session_int, record_buffer_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_set_get_pma_state(
|
||||||
|
nv_soc_hwpm_session session, nv_soc_hwpm_pma_channel_state_params* param)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (!session_info->is_session_started) {
|
||||||
|
log_error("Session is not started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_set_get_pma_state(session_int, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_get_hs_credits(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
tegra_soc_hwpm_get_type type,
|
||||||
|
uint32_t* num_hs_credits)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (!session_info->is_session_started) {
|
||||||
|
log_error("Session is not started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_hs_credits == NULL) {
|
||||||
|
log_error("Invalid null num_hs_credits\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_get_hs_credits(
|
||||||
|
session_int, type, num_hs_credits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_config_hs_credits(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
uint32_t param_count,
|
||||||
|
const nv_soc_hwpm_config_hs_credit_params* params)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (!session_info->is_session_started) {
|
||||||
|
log_error("Session is not started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param_count == 0) {
|
||||||
|
log_error("Invalid 0 param_count\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params == NULL) {
|
||||||
|
log_error("Invalid null params\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_config_hs_credits(
|
||||||
|
session_int, param_count, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_start(nv_soc_hwpm_session session)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (session_info->is_session_started) {
|
||||||
|
log_error("Session is already started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_start(session_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_regops(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
const size_t param_count,
|
||||||
|
nv_soc_hwpm_reg_ops_params* params,
|
||||||
|
nv_soc_hwpm_reg_ops_validation_mode mode,
|
||||||
|
int* all_reg_ops_passed)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
if (param_count == 0) {
|
||||||
|
log_error("Invalid 0 param_count\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params == NULL) {
|
||||||
|
log_error("Invalid null params\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode >= NV_SOC_HWPM_REG_OPS_VALIDATION_MODE_COUNT) {
|
||||||
|
log_error("Invalid mode: %u\n", mode);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (!session_info->is_session_started) {
|
||||||
|
log_error("Session is not started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_regops(
|
||||||
|
session_int, param_count, params, mode, all_reg_ops_passed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_session_setup_trigger(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
int enable_cross_trigger,
|
||||||
|
nv_soc_hwpm_trigger_session_type session_type)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_int *session_int;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
if (session_type >= NV_SOC_HWPM_TRIGGER_SESSION_TYPE_COUNT) {
|
||||||
|
log_error("Invalid trigger session type: %u\n", session_type);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_int = to_session_int(session.handle);
|
||||||
|
if (session_int == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
if (!session_info->is_session_started) {
|
||||||
|
log_error("Session is not started\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nv_soc_hwpm_os_session_setup_trigger(
|
||||||
|
session_int, enable_cross_trigger, session_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
33
libnvsochwpm/os/lnx/libnvsochwpm.export
Normal file
33
libnvsochwpm/os/lnx/libnvsochwpm.export
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
|
||||||
|
nv_soc_hwpm_init
|
||||||
|
nv_soc_hwpm_exit
|
||||||
|
nv_soc_hwpm_get_devices
|
||||||
|
nv_soc_hwpm_get_device_info
|
||||||
|
nv_soc_hwpm_get_ip_info
|
||||||
|
nv_soc_hwpm_get_ip_info_list
|
||||||
|
nv_soc_hwpm_get_resource_info
|
||||||
|
nv_soc_hwpm_get_resource_info_list
|
||||||
|
nv_soc_hwpm_session_alloc
|
||||||
|
nv_soc_hwpm_session_free
|
||||||
|
nv_soc_hwpm_session_get_info
|
||||||
|
nv_soc_hwpm_session_set_resources
|
||||||
|
nv_soc_hwpm_session_set_all_resources
|
||||||
|
nv_soc_hwpm_session_reserve_resources
|
||||||
|
nv_soc_hwpm_session_alloc_pma
|
||||||
|
nv_soc_hwpm_session_set_get_pma_state
|
||||||
|
nv_soc_hwpm_session_get_hs_credits
|
||||||
|
nv_soc_hwpm_session_config_hs_credits
|
||||||
|
nv_soc_hwpm_session_start
|
||||||
|
nv_soc_hwpm_session_regops
|
||||||
|
nv_soc_hwpm_session_setup_trigger
|
||||||
38
libnvsochwpm/os/lnx/libnvsochwpm.map
Normal file
38
libnvsochwpm/os/lnx/libnvsochwpm.map
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
LIBNVSOCHWPM {
|
||||||
|
global:
|
||||||
|
nv_soc_hwpm_init;
|
||||||
|
nv_soc_hwpm_exit;
|
||||||
|
nv_soc_hwpm_system_get_info;
|
||||||
|
nv_soc_hwpm_get_devices;
|
||||||
|
nv_soc_hwpm_device_get_info;
|
||||||
|
nv_soc_hwpm_ip_get_info;
|
||||||
|
nv_soc_hwpm_resource_get_info;
|
||||||
|
nv_soc_hwpm_session_alloc;
|
||||||
|
nv_soc_hwpm_session_free;
|
||||||
|
nv_soc_hwpm_session_get_info;
|
||||||
|
nv_soc_hwpm_session_reserve_resources;
|
||||||
|
nv_soc_hwpm_session_reserve_all_resources;
|
||||||
|
nv_soc_hwpm_session_alloc_pma;
|
||||||
|
nv_soc_hwpm_session_set_get_pma_state;
|
||||||
|
nv_soc_hwpm_session_get_hs_credits;
|
||||||
|
nv_soc_hwpm_session_config_hs_credits;
|
||||||
|
nv_soc_hwpm_session_start;
|
||||||
|
nv_soc_hwpm_session_regops;
|
||||||
|
nv_soc_hwpm_session_setup_trigger;
|
||||||
|
local:
|
||||||
|
*;
|
||||||
|
};
|
||||||
836
libnvsochwpm/os/lnx/nv_soc_hwpm_lnx.c
Normal file
836
libnvsochwpm/os/lnx/nv_soc_hwpm_lnx.c
Normal file
@@ -0,0 +1,836 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined (__QNX__)
|
||||||
|
|
||||||
|
#include <linux/dma-heap.h>
|
||||||
|
#include <linux/dma-buf.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "uapi/linux/tegra-soc-hwpm-uapi.h"
|
||||||
|
#include "os/nv_soc_hwpm_os.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int get_device_info(int fd, nv_soc_hwpm_device_info* dev_info)
|
||||||
|
{
|
||||||
|
struct tegra_soc_hwpm_device_info params;
|
||||||
|
int ret;
|
||||||
|
ret = ioctl(fd, TEGRA_CTRL_CMD_SOC_HWPM_DEVICE_INFO, ¶ms);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_DEVICE_INFO, ret: %d, errno: %s\n",
|
||||||
|
ret,
|
||||||
|
strerror(errno));
|
||||||
|
ret = -EIO;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info->soc_chip_id = (params.chip << 4) | params.chip_revision;
|
||||||
|
dev_info->soc_revision = params.revision;
|
||||||
|
dev_info->soc_platform = params.platform;
|
||||||
|
dev_info->soc_socket = 0; /* TODO: only single socket support for now. */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_ip_floorsweep_info(
|
||||||
|
int fd, nv_soc_hwpm_ip_info* ip_info, uint32_t* ip_available_count,
|
||||||
|
nv_soc_hwpm_ip* ip_available_list)
|
||||||
|
{
|
||||||
|
uint32_t ip, available_count, query_count, q;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Query all IPs. */
|
||||||
|
ip = 0;
|
||||||
|
available_count = 0;
|
||||||
|
while (ip < TERGA_SOC_HWPM_NUM_IPS) {
|
||||||
|
struct tegra_soc_hwpm_ip_floorsweep_info param = {};
|
||||||
|
query_count = MIN((TERGA_SOC_HWPM_NUM_IPS - ip),
|
||||||
|
TEGRA_SOC_HWPM_IP_QUERIES_MAX);
|
||||||
|
param.num_queries = query_count;
|
||||||
|
for (q = 0; q < query_count; ++q) {
|
||||||
|
param.ip_fsinfo[q].ip = ip + q;
|
||||||
|
param.ip_fsinfo[q].ip_inst_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl(fd, TEGRA_CTRL_CMD_SOC_HWPM_IP_FLOORSWEEP_INFO,
|
||||||
|
¶m);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_IP_FLOORSWEEP_INFO, ip: %d, ret: %d, errno: %s\n",
|
||||||
|
ip, ret, strerror(errno));
|
||||||
|
ret = -EIO;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (q = 0; q < query_count; ++q, ++ip) {
|
||||||
|
ip_info[ip].is_available =
|
||||||
|
(param.ip_fsinfo[q].status ==
|
||||||
|
TEGRA_SOC_HWPM_IP_STATUS_VALID) ? 1 : 0;
|
||||||
|
*((uint64_t*)ip_info[ip].fs_mask) = param.ip_fsinfo[q].ip_inst_mask;
|
||||||
|
|
||||||
|
if (ip_info[ip].is_available)
|
||||||
|
ip_available_list[available_count++] = ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ip_available_count = available_count;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: get the actual IP instance/element max count. */
|
||||||
|
static uint32_t get_ip_max_instances(
|
||||||
|
tegra_soc_hwpm_chip_id chip_id, nv_soc_hwpm_ip ip)
|
||||||
|
{
|
||||||
|
switch (chip_id) {
|
||||||
|
case TEGRA_SOC_HWPM_CHIP_ID_T241:
|
||||||
|
switch (ip) {
|
||||||
|
case NV_SOC_HWPM_IP_MSS_CHANNEL:
|
||||||
|
return 64;
|
||||||
|
case NV_SOC_HWPM_IP_PCIE_XALRC:
|
||||||
|
case NV_SOC_HWPM_IP_PCIE_XTLRC:
|
||||||
|
case NV_SOC_HWPM_IP_PCIE_XTLQ:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TEGRA_SOC_HWPM_CHIP_ID_T410:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_resource_info(
|
||||||
|
int fd, nv_soc_hwpm_resource_info* res_info, uint32_t* res_available_count,
|
||||||
|
nv_soc_hwpm_resource* res_available_list)
|
||||||
|
{
|
||||||
|
uint32_t res, available_count, query_count, q;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Query all resources. */
|
||||||
|
res = 0;
|
||||||
|
available_count = 0;
|
||||||
|
while (res < TERGA_SOC_HWPM_NUM_RESOURCES) {
|
||||||
|
struct tegra_soc_hwpm_resource_info param = {};
|
||||||
|
query_count = MIN((TERGA_SOC_HWPM_NUM_RESOURCES - res),
|
||||||
|
TEGRA_SOC_HWPM_RESOURCE_QUERIES_MAX);
|
||||||
|
param.num_queries = query_count;
|
||||||
|
for (q = 0; q < query_count; ++q) {
|
||||||
|
param.resource_info[q].resource = res + q;
|
||||||
|
param.resource_info[q].status = TEGRA_SOC_HWPM_RESOURCE_STATUS_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl(fd, TEGRA_CTRL_CMD_SOC_HWPM_RESOURCE_INFO, ¶m);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_RESOURCE_INFO, res: %d, ret: %d, errno: %s\n",
|
||||||
|
res, ret, strerror(errno));
|
||||||
|
ret = -EIO;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (q = 0; q < query_count; ++q, ++res) {
|
||||||
|
res_info[res].is_available =
|
||||||
|
(param.resource_info[q].status ==
|
||||||
|
TEGRA_SOC_HWPM_RESOURCE_STATUS_VALID) ? 1 : 0;
|
||||||
|
|
||||||
|
if (res_info[res].is_available)
|
||||||
|
res_available_list[available_count++] = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*res_available_count = available_count;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_open_hwpm_device(const char* dev_path)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open(dev_path, O_RDWR);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_close_hwpm_device(int fd)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int enumerate_socket(uint32_t socket, nv_soc_hwpm_device_int* device_int)
|
||||||
|
{
|
||||||
|
int fd, ret = 0;
|
||||||
|
uint32_t i;
|
||||||
|
const char* hwpm_path;
|
||||||
|
|
||||||
|
hwpm_path = TEGRA_SOC_HWPM_DEV_NODE;
|
||||||
|
fd = nv_soc_hwpm_os_open_hwpm_device(hwpm_path);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_error("Failed opening HWPM socket: %u, device: %s, errno: %s\n",
|
||||||
|
socket, hwpm_path, strerror(errno));
|
||||||
|
ret = -errno;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
nv_soc_hwpm_device_info* dev_info = &device_int->dev_info;
|
||||||
|
ret = get_device_info(fd, dev_info);
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed get_device_info, dev: %s\n", hwpm_path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
nv_soc_hwpm_ip_info* ip_info = device_int->ip_info;
|
||||||
|
ret = get_ip_floorsweep_info(fd, ip_info, &dev_info->ip_available_count,
|
||||||
|
dev_info->ip_available_list);
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed get_ip_floorsweep_info, dev: %s\n", hwpm_path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dev_info->ip_available_count; i++) {
|
||||||
|
nv_soc_hwpm_ip cur_ip = dev_info->ip_available_list[i];
|
||||||
|
ip_info[cur_ip].inst_max_count =
|
||||||
|
get_ip_max_instances(dev_info->soc_chip_id, cur_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
nv_soc_hwpm_resource_info* res_info = device_int->res_info;
|
||||||
|
ret = get_resource_info(fd, res_info, &dev_info->res_available_count,
|
||||||
|
dev_info->res_available_list);
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed get_resource_info, dev: %s\n", hwpm_path);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_int->dev_path = hwpm_path;
|
||||||
|
device_int->session_count_max = 1; /* TODO: only single session now */
|
||||||
|
device_int->session_count = 0;
|
||||||
|
memset(device_int->session_int, 0, sizeof(device_int->session_int));
|
||||||
|
|
||||||
|
if (device_int->session_count_max > MAX_SESSION_COUNT) {
|
||||||
|
log_error("Session count max: %u is greater than MAX_SESSION_COUNT: %u\n",
|
||||||
|
device_int->session_count_max, MAX_SESSION_COUNT);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
nv_soc_hwpm_os_close_hwpm_device(fd);
|
||||||
|
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enumerate NV_SOC_HWPM device in the system.
|
||||||
|
*
|
||||||
|
* @return 0 if successful.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int nv_soc_hwpm_os_enumerate_device(
|
||||||
|
uint32_t max_count, uint32_t* actual_count,
|
||||||
|
nv_soc_hwpm_device_int* devices_int)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
uint32_t socket;
|
||||||
|
|
||||||
|
memset(devices_int, 0, sizeof(nv_soc_hwpm_device_int) * max_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: only single socket support for now.
|
||||||
|
*/
|
||||||
|
socket = 0;
|
||||||
|
ret = enumerate_socket(socket, &devices_int[socket]);
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed enumerate device on socket: %u, ret: %d\n", socket, ret);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
*actual_count = 1;
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
*actual_count = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_reserve_resources(
|
||||||
|
nv_soc_hwpm_session_int* session_int, nv_soc_hwpm_resource res_id)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
struct tegra_soc_hwpm_reserve_resource params = {};
|
||||||
|
params.resource = (enum tegra_soc_hwpm_resource)res_id;
|
||||||
|
ret = ioctl(session_int->fd,
|
||||||
|
TEGRA_CTRL_CMD_SOC_HWPM_RESERVE_RESOURCE,
|
||||||
|
¶ms);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_RESERVE_RESOURCE res id: %u, ret: %d, "
|
||||||
|
"errno: %s\n",
|
||||||
|
params.resource,
|
||||||
|
ret,
|
||||||
|
strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unmap_dma_heap(int handle, void *va, size_t size)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!handle || !va || !size) {
|
||||||
|
log_error("Invalid handle: %d, va: %p, size: %llu\n", handle, va, size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = munmap(va, size);
|
||||||
|
if (ret < 0) {
|
||||||
|
log_error("munmap failed : %s\n", strerror(errno));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alloc_dma_heap(
|
||||||
|
const char* heap_path,
|
||||||
|
size_t size,
|
||||||
|
tegra_soc_hwpm_coherency_type coherency,
|
||||||
|
uint32_t flags,
|
||||||
|
void* cpu_va_user,
|
||||||
|
void** cpu_va,
|
||||||
|
uint32_t* mem_handle,
|
||||||
|
uint32_t* mem_fd,
|
||||||
|
uint32_t* heap_fd)
|
||||||
|
{
|
||||||
|
int ret, fd;
|
||||||
|
|
||||||
|
/* Coherency flag not used in DMA heap implementation. */
|
||||||
|
(void)coherency;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
|
if (size == 0 || cpu_va == NULL || mem_handle == NULL || mem_fd == NULL || heap_fd == NULL) {
|
||||||
|
log_error("Invalid size: %llu, cpu_va: %p, mem_handle: %p, mem_fd: %p, heap_fd: %p\n",
|
||||||
|
size, cpu_va, mem_handle, mem_fd, heap_fd);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*heap_fd = 0;
|
||||||
|
fd = open(heap_path, O_RDWR | O_SYNC | O_CLOEXEC);
|
||||||
|
if (fd < 0) {
|
||||||
|
log_error("open %s failed [%s]\n", heap_path, strerror(errno));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dma_heap_allocation_data data = {
|
||||||
|
.len = size,
|
||||||
|
.fd = 0,
|
||||||
|
.fd_flags = O_RDWR | O_CLOEXEC,
|
||||||
|
.heap_flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = ioctl(fd, DMA_HEAP_IOCTL_ALLOC, &data);
|
||||||
|
if (ret) {
|
||||||
|
log_error("dma heap Alloc failed [%s]\n", strerror(errno));
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mem_handle = (uint32_t)data.fd;
|
||||||
|
|
||||||
|
*cpu_va = mmap(*cpu_va,
|
||||||
|
size,
|
||||||
|
(PROT_READ | PROT_WRITE),
|
||||||
|
MAP_SHARED,
|
||||||
|
data.fd,
|
||||||
|
0);
|
||||||
|
if (*cpu_va == MAP_FAILED) {
|
||||||
|
log_error("mmap failed : %s\n", strerror(errno));
|
||||||
|
*cpu_va = NULL;
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(*cpu_va, 0, size);
|
||||||
|
|
||||||
|
if ((cpu_va_user != NULL) && (*cpu_va != cpu_va_user)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error_unmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve memHandle's FD */
|
||||||
|
*mem_fd = data.fd;
|
||||||
|
*heap_fd = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_unmap:
|
||||||
|
unmap_dma_heap(data.fd, *cpu_va, size);
|
||||||
|
|
||||||
|
error:
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int free_dma_heap(
|
||||||
|
uint64_t mem_handle, void *cpu_va, size_t size, uint32_t heap_fd)
|
||||||
|
{
|
||||||
|
if ((cpu_va != NULL) && (mem_handle != 0)) {
|
||||||
|
unmap_dma_heap((int)mem_handle, cpu_va, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem_handle != 0) {
|
||||||
|
close((int)mem_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heap_fd != 0) {
|
||||||
|
close(heap_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alloc_pma(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
const char* heap_path,
|
||||||
|
const nv_soc_hwpm_pma_buffer_params *record_buffer_params)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
nv_soc_hwpm_session_info *session_info = &session_int->info;
|
||||||
|
|
||||||
|
/* Allocate PMA record buffer */
|
||||||
|
|
||||||
|
void* record_buffer = NULL;
|
||||||
|
uint32_t record_buffer_handle = 0;
|
||||||
|
uint32_t record_buffer_fd = 0;
|
||||||
|
uint32_t record_buffer_heap_fd = 0;
|
||||||
|
const size_t record_buffer_size = record_buffer_params->size;
|
||||||
|
void* record_buffer_cpu_va = record_buffer_params->cpu_va;
|
||||||
|
tegra_soc_hwpm_coherency_type record_buffer_coherency = record_buffer_params->coherency_type;
|
||||||
|
|
||||||
|
ret = alloc_dma_heap(
|
||||||
|
heap_path,
|
||||||
|
record_buffer_size,
|
||||||
|
record_buffer_coherency,
|
||||||
|
0, /* TODO: for other allocator may need to pass read/write property*/
|
||||||
|
record_buffer_cpu_va,
|
||||||
|
&record_buffer,
|
||||||
|
&record_buffer_handle,
|
||||||
|
&record_buffer_fd,
|
||||||
|
&record_buffer_heap_fd);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed allocating PMA buffer\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate mem bytes buffer */
|
||||||
|
|
||||||
|
void* mem_bytes_buffer = NULL;
|
||||||
|
uint32_t mem_bytes_buffer_handle = 0;
|
||||||
|
uint32_t mem_bytes_buffer_fd = 0;
|
||||||
|
uint32_t mem_bytes_buffer_heap_fd = 0;
|
||||||
|
const size_t mem_bytes_buffer_size = 4096; // ignore size passed by caller
|
||||||
|
void* mem_bytes_buffer_cpu_va = NULL;
|
||||||
|
tegra_soc_hwpm_coherency_type mem_bytes_buffer_coherency =
|
||||||
|
record_buffer_coherency; // same with record buffer
|
||||||
|
|
||||||
|
ret = alloc_dma_heap(
|
||||||
|
heap_path,
|
||||||
|
mem_bytes_buffer_size,
|
||||||
|
mem_bytes_buffer_coherency,
|
||||||
|
0, /* TODO: for other allocator may need to pass read/write property*/
|
||||||
|
mem_bytes_buffer_cpu_va,
|
||||||
|
&mem_bytes_buffer,
|
||||||
|
&mem_bytes_buffer_handle,
|
||||||
|
&mem_bytes_buffer_fd,
|
||||||
|
&mem_bytes_buffer_heap_fd);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed allocating mem bytes buffer\n");
|
||||||
|
goto error_free_record;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tegra_soc_hwpm_alloc_pma_stream params = {};
|
||||||
|
params.stream_buf_fd = record_buffer_fd;
|
||||||
|
params.mem_bytes_buf_fd = mem_bytes_buffer_fd;
|
||||||
|
params.stream_buf_size = record_buffer_size;
|
||||||
|
|
||||||
|
/* Register the buffers to the driver */
|
||||||
|
ret = ioctl(session_int->fd, TEGRA_CTRL_CMD_SOC_HWPM_ALLOC_PMA_STREAM, ¶ms);
|
||||||
|
if (ret) {
|
||||||
|
log_error("Failed TEGRA_CTRL_CMD_SOC_HWPM_ALLOC_PMA_STREAM with errno=%s.\n",
|
||||||
|
strerror(errno));
|
||||||
|
ret = -EIO;
|
||||||
|
goto error_free_mem_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info->record_buffer.buffer = (uint8_t*)record_buffer;
|
||||||
|
session_info->record_buffer.size = record_buffer_size;
|
||||||
|
session_info->record_buffer.pma_va = params.stream_buf_pma_va;
|
||||||
|
session_info->record_buffer.handle = record_buffer_handle;
|
||||||
|
session_info->record_buffer.heap_fd = record_buffer_heap_fd;
|
||||||
|
|
||||||
|
session_info->mem_bytes_buffer.buffer = (uint8_t*)mem_bytes_buffer;
|
||||||
|
session_info->mem_bytes_buffer.size = mem_bytes_buffer_size;
|
||||||
|
session_info->mem_bytes_buffer.pma_va = 0; /* TODO: currently, kernel doesn't provide this. */
|
||||||
|
session_info->mem_bytes_buffer.handle = mem_bytes_buffer_handle;
|
||||||
|
session_info->mem_bytes_buffer.heap_fd = mem_bytes_buffer_heap_fd;
|
||||||
|
|
||||||
|
session_info->is_pma_buffer_allocated = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_free_mem_bytes:
|
||||||
|
free_dma_heap(
|
||||||
|
mem_bytes_buffer_handle, mem_bytes_buffer, mem_bytes_buffer_size,
|
||||||
|
mem_bytes_buffer_heap_fd);
|
||||||
|
|
||||||
|
error_free_record:
|
||||||
|
free_dma_heap(
|
||||||
|
record_buffer_handle, record_buffer, record_buffer_size,
|
||||||
|
record_buffer_heap_fd);
|
||||||
|
|
||||||
|
error:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int path_exists(const char* filename) {
|
||||||
|
struct stat buffer;
|
||||||
|
return (stat(filename, &buffer) == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_alloc_pma(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
const nv_soc_hwpm_pma_buffer_params *record_buffer_params)
|
||||||
|
{
|
||||||
|
static const uint32_t kHeapPathCount = 3;
|
||||||
|
static const char* kHeapPath[] = {
|
||||||
|
"/dev/dma_heap/cma",
|
||||||
|
"/dev/dma_heap/reserved",
|
||||||
|
"/dev/dma_heap/system",
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < kHeapPathCount; i++) {
|
||||||
|
log_debug("Trying to allocate PMA buffer from %s\n", kHeapPath[i]);
|
||||||
|
if (path_exists(kHeapPath[i]) == 0) {
|
||||||
|
log_debug("Heap %s does not exist\n", kHeapPath[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = alloc_pma(session_int, kHeapPath[i], record_buffer_params);
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv_soc_hwpm_os_session_free_pma(nv_soc_hwpm_session_int* session_int)
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_info *session_info = &session_int->info;
|
||||||
|
|
||||||
|
/* Cleanup PMA buffer. */
|
||||||
|
if (session_info->record_buffer.handle != 0) {
|
||||||
|
free_dma_heap(
|
||||||
|
session_info->record_buffer.handle,
|
||||||
|
session_info->record_buffer.buffer,
|
||||||
|
session_info->record_buffer.size,
|
||||||
|
session_info->record_buffer.heap_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_info->mem_bytes_buffer.handle != 0) {
|
||||||
|
free_dma_heap(
|
||||||
|
session_info->mem_bytes_buffer.handle,
|
||||||
|
session_info->mem_bytes_buffer.buffer,
|
||||||
|
session_info->mem_bytes_buffer.size,
|
||||||
|
session_info->mem_bytes_buffer.heap_fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_set_get_pma_state(
|
||||||
|
nv_soc_hwpm_session_int *session_int,
|
||||||
|
nv_soc_hwpm_pma_channel_state_params* params)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct tegra_soc_hwpm_update_get_put io_params = {};
|
||||||
|
|
||||||
|
io_params.mem_bump = params->in_mem_bump;
|
||||||
|
|
||||||
|
if (params->in_check_overflow)
|
||||||
|
{
|
||||||
|
io_params.b_check_overflow = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->in_read_mem_head)
|
||||||
|
{
|
||||||
|
io_params.b_read_mem_head = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_params.b_stream_mem_bytes = (params->in_stream_mem_bytes != 0);
|
||||||
|
|
||||||
|
ret = ioctl(session_int->fd,
|
||||||
|
TEGRA_CTRL_CMD_SOC_HWPM_UPDATE_GET_PUT,
|
||||||
|
&io_params);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_UPDATE_GET_PUT, ret: %d, errno: %s\n",
|
||||||
|
ret, strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->in_check_overflow)
|
||||||
|
{
|
||||||
|
params->out_overflowed = !!io_params.b_overflowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params->in_read_mem_head)
|
||||||
|
{
|
||||||
|
params->out_mem_head = io_params.mem_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_get_hs_credits(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
tegra_soc_hwpm_get_type type,
|
||||||
|
uint32_t* num_hs_credits)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint16_t credit_cmd;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TEGRA_SOC_HWPM_GET_TYPE_HS_CREDITS:
|
||||||
|
credit_cmd = TEGRA_SOC_HWPM_CMD_GET_HS_CREDITS;
|
||||||
|
break;
|
||||||
|
case TEGRA_SOC_HWPM_GET_TYPE_TOTAL_HS_CREDITS:
|
||||||
|
credit_cmd = TEGRA_SOC_HWPM_CMD_GET_TOTAL_HS_CREDITS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log_error("Invalid credit type: %u\n", type);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tegra_soc_hwpm_exec_credit_program params = { 0 };
|
||||||
|
|
||||||
|
params.num_entries = 1;
|
||||||
|
params.credit_cmd = credit_cmd;
|
||||||
|
params.credit_info[0].num_credits = ~0;
|
||||||
|
|
||||||
|
ret = ioctl(session_int->fd,
|
||||||
|
TEGRA_CTRL_CMD_SOC_HWPM_CREDIT_PROGRAM,
|
||||||
|
¶ms);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_CREDIT_PROGRAM, ret: %d, errno: %s\n",
|
||||||
|
ret, strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Total credits are available in first entry */
|
||||||
|
*num_hs_credits = params.credit_info[0].num_credits;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_config_hs_credits(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
uint32_t param_count,
|
||||||
|
const nv_soc_hwpm_config_hs_credit_params* params)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < param_count)
|
||||||
|
{
|
||||||
|
/* TODO set params.pmaChannelIdx for multi-channel support (currently 0) */
|
||||||
|
uint32_t b, batch_count;
|
||||||
|
struct tegra_soc_hwpm_exec_credit_program io_params = { 0 };
|
||||||
|
|
||||||
|
batch_count = MIN((param_count - i),
|
||||||
|
TEGRA_SOC_HWPM_MAX_CREDIT_INFO_ENTRIES);
|
||||||
|
|
||||||
|
io_params.credit_cmd = TEGRA_SOC_HWPM_CMD_SET_HS_CREDITS;
|
||||||
|
io_params.num_entries = batch_count;
|
||||||
|
|
||||||
|
for (b = 0; b < batch_count; ++b) {
|
||||||
|
const uint32_t param_idx = i + b;;
|
||||||
|
io_params.credit_info[b].cblock_idx = params[param_idx].cblock_idx;
|
||||||
|
io_params.credit_info[b].num_credits = params[param_idx].num_credits_per_chiplet;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl(session_int->fd,
|
||||||
|
TEGRA_CTRL_CMD_SOC_HWPM_CREDIT_PROGRAM,
|
||||||
|
&io_params);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_CREDIT_PROGRAM, ret: %d, errno: %s\n",
|
||||||
|
ret, strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO get info regarding failed credit programming from params.statusInfo (currently unused) */
|
||||||
|
|
||||||
|
i += batch_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_start(nv_soc_hwpm_session_int* session_int)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
nv_soc_hwpm_session_info *session_info;
|
||||||
|
|
||||||
|
ret = ioctl(session_int->fd, TEGRA_CTRL_CMD_BIND);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_BIND, ret: %d, errno: %s\n",
|
||||||
|
ret, strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_info = &session_int->info;
|
||||||
|
session_info->is_session_started = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_regops(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
const size_t param_count,
|
||||||
|
nv_soc_hwpm_reg_ops_params* params,
|
||||||
|
nv_soc_hwpm_reg_ops_validation_mode mode,
|
||||||
|
int* all_reg_ops_passed)
|
||||||
|
{
|
||||||
|
int ret, all_passed;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
all_passed = 1;
|
||||||
|
i = 0;
|
||||||
|
while (i < param_count)
|
||||||
|
{
|
||||||
|
/* TODO set params.pmaChannelIdx for multi-channel support (currently 0) */
|
||||||
|
uint32_t b, batch_count;
|
||||||
|
struct tegra_soc_hwpm_exec_reg_ops io_params = { 0 };
|
||||||
|
|
||||||
|
batch_count = MIN((param_count - i),
|
||||||
|
TEGRA_SOC_HWPM_REG_OPS_SIZE);
|
||||||
|
|
||||||
|
io_params.mode = (uint8_t)mode;
|
||||||
|
io_params.op_count = batch_count;
|
||||||
|
|
||||||
|
for (b = 0; b < batch_count; ++b) {
|
||||||
|
const uint32_t param_idx = i + b;;
|
||||||
|
io_params.ops[b].phys_addr = params[param_idx].in_offset;
|
||||||
|
io_params.ops[b].reg_val_lo = VAL_LO64(params[param_idx].in_out_val64);
|
||||||
|
io_params.ops[b].reg_val_hi = VAL_HI64(params[param_idx].in_out_val64);
|
||||||
|
io_params.ops[b].mask_lo = VAL_LO64(params[param_idx].in_mask64);
|
||||||
|
io_params.ops[b].mask_hi = VAL_HI64(params[param_idx].in_mask64);
|
||||||
|
io_params.ops[b].cmd = params[param_idx].in_cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ioctl(session_int->fd,
|
||||||
|
TEGRA_CTRL_CMD_SOC_HWPM_EXEC_REG_OPS,
|
||||||
|
&io_params);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_EXEC_REG_OPS, ret: %d, errno: %s\n",
|
||||||
|
ret, strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
all_passed &= !!io_params.b_all_reg_ops_passed;
|
||||||
|
|
||||||
|
// Read back the result.
|
||||||
|
for (b = 0; b < batch_count; ++b) {
|
||||||
|
const uint32_t param_idx = i + b;
|
||||||
|
params[param_idx].in_out_val64 =
|
||||||
|
VAL_64(io_params.ops[b].reg_val_lo,
|
||||||
|
io_params.ops[b].reg_val_hi);
|
||||||
|
params[param_idx].out_status = io_params.ops[b].status;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += batch_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_reg_ops_passed != NULL)
|
||||||
|
*all_reg_ops_passed = all_passed;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_setup_trigger(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
int enable_cross_trigger,
|
||||||
|
nv_soc_hwpm_trigger_session_type session_type)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO:
|
||||||
|
* set params.cblockIdx and params.pmaChannelIdx for multi-channel
|
||||||
|
* support (currently 0)
|
||||||
|
*/
|
||||||
|
struct tegra_soc_hwpm_setup_trigger params = { 0 };
|
||||||
|
params.enable_cross_trigger = (uint8_t)enable_cross_trigger;
|
||||||
|
params.session_type = (uint8_t)session_type;
|
||||||
|
|
||||||
|
ret = ioctl(session_int->fd,
|
||||||
|
TEGRA_CTRL_CMD_SOC_HWPM_SETUP_TRIGGER,
|
||||||
|
¶ms);
|
||||||
|
if (ret) {
|
||||||
|
log_error(
|
||||||
|
"Failed TEGRA_CTRL_CMD_SOC_HWPM_SETUP_TRIGGER, ret: %d, errno: %s\n",
|
||||||
|
ret, strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !__QNX__ */
|
||||||
75
libnvsochwpm/os/nv_soc_hwpm_os.h
Normal file
75
libnvsochwpm/os/nv_soc_hwpm_os.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NV_SOC_HWPM_OS__
|
||||||
|
#define __NV_SOC_HWPM_OS__
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_open_hwpm_device(const char* dev_path);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_close_hwpm_device(int fd);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_enumerate_device(
|
||||||
|
uint32_t max_count, uint32_t* actual_count,
|
||||||
|
nv_soc_hwpm_device_int* devices_int);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_reserve_resources(
|
||||||
|
nv_soc_hwpm_session_int* session_int, nv_soc_hwpm_resource res_id);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_alloc_pma(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
const nv_soc_hwpm_pma_buffer_params *record_buffer_params);
|
||||||
|
|
||||||
|
void nv_soc_hwpm_os_session_free_pma(
|
||||||
|
nv_soc_hwpm_session_int* session_int);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_set_get_pma_state(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
nv_soc_hwpm_pma_channel_state_params* param);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_get_hs_credits(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
tegra_soc_hwpm_get_type type,
|
||||||
|
uint32_t* num_hs_credits);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_config_hs_credits(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
uint32_t param_count,
|
||||||
|
const nv_soc_hwpm_config_hs_credit_params* params);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_start(nv_soc_hwpm_session_int* session_int);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_regops(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
const size_t param_count,
|
||||||
|
nv_soc_hwpm_reg_ops_params* params,
|
||||||
|
nv_soc_hwpm_reg_ops_validation_mode mode,
|
||||||
|
int* all_reg_ops_passed);
|
||||||
|
|
||||||
|
int nv_soc_hwpm_os_session_setup_trigger(
|
||||||
|
nv_soc_hwpm_session_int* session_int,
|
||||||
|
int enable_cross_trigger,
|
||||||
|
nv_soc_hwpm_trigger_session_type session_type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*__NV_SOC_HWPM_OS__*/
|
||||||
72
libnvsochwpm/test/Makefile
Normal file
72
libnvsochwpm/test/Makefile
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
################################################################################
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Borrow the make environment from Linux kernel to support cross compilation.
|
||||||
|
ifneq ($(KERNEL_SOURCE),)
|
||||||
|
export srctree := $(KERNEL_SOURCE)
|
||||||
|
include $(srctree)/tools/scripts/Makefile.include
|
||||||
|
include $(srctree)/tools/scripts/Makefile.arch
|
||||||
|
else
|
||||||
|
CXX = g++
|
||||||
|
endif
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
nv_soc_hwpm_test.cpp \
|
||||||
|
t241_test.cpp \
|
||||||
|
soc_mode_e_buffer.cpp
|
||||||
|
|
||||||
|
OBJECTS=$(foreach x, $(basename $(SOURCES)), $(x).o)
|
||||||
|
|
||||||
|
CXXFLAGS = -Wall -Wextra -Werror -std=c++14 -g
|
||||||
|
CXXFLAGS += -I. -I../include -I./include -I../
|
||||||
|
|
||||||
|
ifneq ($(NV_SOURCE),)
|
||||||
|
# Need to be built using this command:
|
||||||
|
# ARCH=arm64 CROSS_COMPILE=$P4_GCC/bin/aarch64-linux-gnu- NV_SOURCE=$TEGRA_TOP KERNEL_SOURCE=$TEGRA_TOP/kernel/kernel-pset make
|
||||||
|
# Example:
|
||||||
|
# ARCH=arm64 \
|
||||||
|
# CROSS_COMPILE=$P4ROOT/sw/mobile/tools/linux/linaro//gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- \
|
||||||
|
# NV_SOURCE=~/repo/platform-enablement-dev-main-20250212 \
|
||||||
|
# KERNEL_SOURCE=~/repo/platform-enablement-dev-main-20250212/kernel/kernel-pset make
|
||||||
|
CXXFLAGS += -I$(NV_SOURCE)/3rdparty/google/googletest/googletest/include
|
||||||
|
CXXFLAGS += -I$(NV_SOURCE)/3rdparty/google/googletest/googletest/
|
||||||
|
|
||||||
|
CXXFLAGS += -I$(NV_SOURCE)/hwinc-private/th500/66838280
|
||||||
|
|
||||||
|
GTEST_SOURCES += \
|
||||||
|
$(NV_SOURCE)/3rdparty/google/googletest/googletest/src/gtest-all.cc \
|
||||||
|
$(NV_SOURCE)/3rdparty/google/googletest/googletest/src/gtest_main.cc
|
||||||
|
GTEST_OBJECTS=$(foreach x, $(basename $(GTEST_SOURCES)), $(x).o)
|
||||||
|
else
|
||||||
|
# Need to install libgtest-dev
|
||||||
|
LDFLAGS += -lgtest -lgtest_main
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDFLAGS += -lpthread -ldl
|
||||||
|
|
||||||
|
all: nv_soc_hwpm_test
|
||||||
|
|
||||||
|
nv_soc_hwpm_test: $(GTEST_OBJECTS) $(OBJECTS)
|
||||||
|
$(CXX) $(OBJECTS) $(GTEST_OBJECTS) $(LDFLAGS) -o $@
|
||||||
|
rm -f $(OBJECTS) $(GTEST_OBJECTS)
|
||||||
|
|
||||||
|
$(OBJECTS): %.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
$(GTEST_OBJECTS): %.o: %.cc
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJECTS) $(GTEST_OBJECTS)
|
||||||
|
rm -f nv_soc_hwpm_test
|
||||||
423
libnvsochwpm/test/hwpm_record_format.h
Normal file
423
libnvsochwpm/test/hwpm_record_format.h
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HWPM_RECORD_FORMAT_H
|
||||||
|
#define HWPM_RECORD_FORMAT_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// Copied from /sw/devtools/Agora/Dev/Perfkit/Shared/Perfkit/Modules/Target/Counters/Hwpm/Inc/Perfkit/Counters/Hwpm/TargetMicroPassHwpm.h
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Mode E Record
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Basic mode E record in the native HW layout
|
||||||
|
struct ModeERecordRaw
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint64_t timestamp;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t timestamp_lo;
|
||||||
|
uint8_t timestamp_hi;
|
||||||
|
uint8_t perfmon_id;
|
||||||
|
uint16_t smplcnt_ds_sz;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// counter results
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint32_t counter[4];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32_t event;
|
||||||
|
uint32_t trig0;
|
||||||
|
uint32_t trig1;
|
||||||
|
uint32_t sampl;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t zero2;
|
||||||
|
uint32_t zero3;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Imported from \\hw\nvgpu_gvlit1\ip\perf\hwpm\2.0\defs\public\registers\pri_perf_pmm.ref with below corrections
|
||||||
|
1) timestamp[40:32] => timestamp[39:32]
|
||||||
|
|
||||||
|
15 8 7 0
|
||||||
|
.--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----.
|
||||||
|
0x00 | timestamp[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x02 | timestamp[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x04 | PERFMONID[7:0] | timestamp[39:32] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x06 |0 |0 |SZ|DS|PMID[10:8]| SMPLCNT[8:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x08 | count0[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0A | count0[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0C | count1[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0E | count1[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x10 | count2[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x12 | count2[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x14 | count3[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x16 | count3[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x18 | pm local trigger B count | <-- or TOTAL_TRIG_RCV[15:0] if PMLOCALTRIGB_EN_DISABLE
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1A | bookmark B | <-- or TOTAL_TRIG_RCV[31:0] if PMLOCALTRIGB_EN_DISABLE
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1C | pm local trigger A count |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1E | bookmark A |
|
||||||
|
`--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----'
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ModeERecordVolta : ModeERecordRaw
|
||||||
|
{
|
||||||
|
static const uint64_t TimestampMask = 0x000000ffffffffffull; // lower 40 bits
|
||||||
|
|
||||||
|
uint64_t GetTimestamp() const
|
||||||
|
{
|
||||||
|
const uint64_t timestampMasked = timestamp & TimestampMask;
|
||||||
|
return timestampMasked;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GetSampleCount() const
|
||||||
|
{
|
||||||
|
uint16_t sampleCount = smplcnt_ds_sz & 0x01FF;
|
||||||
|
return sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetPerfmonId() const
|
||||||
|
{
|
||||||
|
uint32_t perfmonId_lsb = perfmon_id;
|
||||||
|
uint32_t perfmonId_msb = (smplcnt_ds_sz & 0xe00) >> 1;
|
||||||
|
uint32_t perfmonId = perfmonId_msb | perfmonId_lsb;
|
||||||
|
return perfmonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetTriggerCount() const
|
||||||
|
{
|
||||||
|
return zero2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDelayedSampled() const
|
||||||
|
{
|
||||||
|
uint8_t ds = (smplcnt_ds_sz >> 12) & 0x1;
|
||||||
|
return !!ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Is32B() const
|
||||||
|
{
|
||||||
|
uint8_t sz = (smplcnt_ds_sz >> 13) & 0x1;
|
||||||
|
return !sz;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Mode C Record
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// Basic Mode C record in the native HW layout
|
||||||
|
struct ModeCRecordRaw
|
||||||
|
{
|
||||||
|
uint16_t timestamp_15_0;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint16_t timestamp_31_16;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t timestamp_23_16;
|
||||||
|
uint8_t total_trig_rcv_7_0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t timestamp_39_32;
|
||||||
|
uint8_t total_trig_rcv_15_8;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t perfmon_id;
|
||||||
|
uint16_t smplcnt_ds_sz_or_pmid;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint16_t counter[12];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t counter_2B[4];
|
||||||
|
uint32_t counter_4B[4];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* https://p4viewer.nvidia.com/get//hw/nvgpu/ip/perf/hwpm/4.1/defs/public/registers/pri_perf_pmm.ref
|
||||||
|
|
||||||
|
_MODEC_4X16_4X32_DISABLE _MODEC_4X16_4X32_RECONFIGURE
|
||||||
|
|
||||||
|
15 8 7 0 15 8 7 0
|
||||||
|
.--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----. .--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----.
|
||||||
|
0x00 | timestamp[15:0] | | timestamp[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x02 | timestamp[31:16] | | timestamp[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x02 | TOTAL_TRIG_RCV[7:0] | timestamp[23:16] | | TOTAL_TRIG_RCV[7:0] | timestamp[23:16] | <-- or TOTAL_TRIG_RCV[7:0] only if TRIGRCV_IN_MODEC is set
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x04 | PERFMONID[7:0] | timestamp[39:32] | | PERFMONID[7:0] | timestamp[39:32] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x04 | PERFMONID[7:0] | TOTAL_TRIG_RCV[15:8] | | PERFMONID[7:0] | TOTAL_TRIG_RCV[15:8] | <-- or TOTAL_TRIG_RCV[15:8] only if TRIGRCV_IN_MODEC is set
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x06 |0 |0 |0 |DS|PMID[10:8]| SMPLCNT[8:0] | |0 |0 |0 |DS|PMID[10:8]| SMPLCNT[8:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x08 | count0[15:0] | | count0[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0A | count1[15:0] | | count1[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0C | count2[15:0] | | count2[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0E | count3[15:0] | | count3[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x10 | count4[15:0] | | count4[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x12 | count5[15:0] | | count4[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x14 | count6[15:0] | | count6[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x16 | count7[15:0] | | count6[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x18 | count8[15:0] | | count8[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1A | count9[15:0] | | count8[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1C | count10[15:0] | | count10[15:0] | <-- or 'pm local trigger A count' if NV_PERF_PMM_CONTROLB_PMLOCALTRIGA_EN is enabled
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1E | count11[15:0] | | count10[31:16] | <-- or 'bookmark A' if NV_PERF_PMM_CONTROLB_PMLOCALTRIGA_EN is enabled
|
||||||
|
`--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----' `--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----'
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ModeCRecordVolta_12x16 : public ModeCRecordRaw
|
||||||
|
{
|
||||||
|
static const uint64_t TimestampMask = 0x000000ffffffffffull; // lower 40 bits(TRIGRCV_IN_MODEC_DISABLE)
|
||||||
|
|
||||||
|
uint64_t GetTimestamp() const
|
||||||
|
{
|
||||||
|
const uint64_t timestamp64 = *(uint64_t*)(this);
|
||||||
|
const uint64_t timestampMasked = timestamp64 & TimestampMask;
|
||||||
|
return timestampMasked;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t GetSampleCount() const
|
||||||
|
{
|
||||||
|
uint16_t sampleCount = smplcnt_ds_sz_or_pmid & 0x01FF;
|
||||||
|
return sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetPerfmonId() const
|
||||||
|
{
|
||||||
|
const uint32_t perfmonId_lsb = perfmon_id;
|
||||||
|
const uint32_t perfmonId_msb = (smplcnt_ds_sz_or_pmid & 0xe00) >> 1;
|
||||||
|
const uint32_t perfmonId = perfmonId_msb | perfmonId_lsb;
|
||||||
|
return perfmonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDelayedSampled() const
|
||||||
|
{
|
||||||
|
uint8_t ds = (smplcnt_ds_sz_or_pmid >> 12) & 0x1;
|
||||||
|
return !!ds;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
//hw/nvgpu/ip/perf/hwpm/4.1/defs/public/registers/pri_perf_pma.ref
|
||||||
|
|
||||||
|
APPENDIX D - PMA RECORD FORMAT
|
||||||
|
|
||||||
|
PMA PERFMONID = 0x7FF Other Perfmons should not be programmed to use that ID.
|
||||||
|
|
||||||
|
15 8 7 0
|
||||||
|
.--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----.
|
||||||
|
0x00 | timestamp[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x02 | timestamp[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x04 | PERFMONID[7:0] | timestamp[40:32] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x06 |0 |0 |SZ|DR| PMID[10:8]| unused |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x08 | start[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0A | start[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0C | end[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x0E | end[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x10 | total[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x12 | total[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x14 | bookmark[15:0] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x16 | bookmark[31:16] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x18 | PTIMER[10:0] | 0 0 0 0 0|
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1A | PTIMER[26:11] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1C | PTIMER[42:27] |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x1E | 0 0 0| PTIMER[55:43] |
|
||||||
|
`--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----'
|
||||||
|
|
||||||
|
PTIMER - 56 bits (32 bit granulariy) global timer on fixed frequency clock
|
||||||
|
incoming from the SOC in gray code format.
|
||||||
|
The DR bit stands for dropped record. The PMA can only process 1 packet at a time,
|
||||||
|
until it goes into the record buffer. All the triggers which come in during this period
|
||||||
|
will not have packets generated for each of them.
|
||||||
|
If the PMA gets multiple triggers in a short window, then it only sends the packet for the first trigger.
|
||||||
|
The trigger counts are updated to account for the missed triggers.
|
||||||
|
After it completes processing the first packet, it then sends a packet when a new trigger comes in.
|
||||||
|
To indicate this, the DR bit will be set to 1 in the packet that is sent next.
|
||||||
|
The DR bit will be seen as set when the difference in total trigger counts is more than 1
|
||||||
|
in the current and the previous packet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// copied from //sw/devtools/Agora/Dev/Perfkit/Shared/Perfkit/Modules/Target/Counters/Hwpm/Inc/Perfkit/Counters/Hwpm/TargetMicroPassHwpm.h
|
||||||
|
|
||||||
|
// PMA Record
|
||||||
|
enum { PMA_PerfmonId = 0x7FF }; // Other perfmons should not be programmed to use this ID.
|
||||||
|
|
||||||
|
struct PmaRecordRaw
|
||||||
|
{
|
||||||
|
uint32_t timestamp_lo;
|
||||||
|
uint8_t timestamp_hi;
|
||||||
|
uint8_t perfmon_id;
|
||||||
|
uint16_t sz_dr_pmid; // "dr" stands for dropped record
|
||||||
|
|
||||||
|
uint32_t start_trigger_count;
|
||||||
|
uint32_t stop_trigger_count;
|
||||||
|
uint32_t total_trigger_count;
|
||||||
|
|
||||||
|
uint32_t bookmark;
|
||||||
|
uint64_t ptimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// adapted from PmaRecordTuring in //sw/devtools/Agora/Dev/Perfkit/Shared/Perfkit/Modules/Target/Counters/Hwpm/Inc/Perfkit/Counters/Hwpm/TargetMicroPassHwpm.h
|
||||||
|
|
||||||
|
struct PmaRecordSoc : public PmaRecordRaw
|
||||||
|
{
|
||||||
|
uint32_t GetPerfmonId() const
|
||||||
|
{
|
||||||
|
uint32_t perfmonId_lsb = perfmon_id;
|
||||||
|
uint32_t perfmonId_msb = (sz_dr_pmid & 0xe00) >> 1; // there is an unused bit in position 8
|
||||||
|
uint32_t perfmonId = perfmonId_msb | perfmonId_lsb;
|
||||||
|
return perfmonId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDroppedRecord() const
|
||||||
|
{
|
||||||
|
const uint8_t dr = (sz_dr_pmid >> 12) & 0x1;
|
||||||
|
return !!dr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of start triggers sent to perfmons
|
||||||
|
uint32_t GetStartTriggerCount() const
|
||||||
|
{
|
||||||
|
return start_trigger_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of end/stop triggers sent to perfmons
|
||||||
|
uint32_t GetStopTriggerCount() const
|
||||||
|
{
|
||||||
|
return stop_trigger_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The total number of triggers including PMA pulses sent to perfmons
|
||||||
|
uint32_t GetTotalTriggerCount() const
|
||||||
|
{
|
||||||
|
return total_trigger_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last value from the PmTrigger packet
|
||||||
|
uint32_t GetBookmark() const
|
||||||
|
{
|
||||||
|
return bookmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: is the PTIMER value in gray code?
|
||||||
|
// From empirical testing, it doesn't look that way.
|
||||||
|
uint64_t GetPtimer() const
|
||||||
|
{
|
||||||
|
uint64_t ptimer_val = (ptimer & 0x1fffffffffffffe0ull) >> 5;
|
||||||
|
#if 0
|
||||||
|
// http://morwenn.github.io/cpp-gray/converting-to-and-from-gray-code/
|
||||||
|
ptimer_val = ptimer_val ^ (ptimer_val >> 32);
|
||||||
|
ptimer_val = ptimer_val ^ (ptimer_val >> 16);
|
||||||
|
ptimer_val = ptimer_val ^ (ptimer_val >> 8);
|
||||||
|
ptimer_val = ptimer_val ^ (ptimer_val >> 4);
|
||||||
|
ptimer_val = ptimer_val ^ (ptimer_val >> 2);
|
||||||
|
ptimer_val = ptimer_val ^ (ptimer_val >> 1);
|
||||||
|
#endif
|
||||||
|
return ptimer_val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// adapted from PmRecordVoltaCommonPrefix in //sw/devtools/Agora/Dev/Perfkit/Shared/Perfkit/Modules/Target/Counters/Hwpm/Inc/Perfkit/Counters/Hwpm/TargetMicroPassHwpm.h
|
||||||
|
|
||||||
|
struct PmRecordSocCommonPrefix
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
15 8 7 0
|
||||||
|
.--+--+--+--+--+--+--+--+--+--+--+--+--+--+-----.
|
||||||
|
0x00 | data0 |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x02 | data1 |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x04 | PERFMONID[7:0] | data2 |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
0x06 | data4 |PMID[10:8]| data3 |
|
||||||
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
*/
|
||||||
|
uint16_t data0_2B;
|
||||||
|
uint16_t data1_2B;
|
||||||
|
uint8_t data2_1B;
|
||||||
|
uint8_t perfmon_id;
|
||||||
|
uint8_t data3_1B;
|
||||||
|
uint8_t data4_pmid;
|
||||||
|
|
||||||
|
uint32_t GetPerfmonId() const
|
||||||
|
{
|
||||||
|
const uint32_t perfmonId_lsb = perfmon_id;
|
||||||
|
const uint32_t perfmonId_msb = (data4_pmid & 0xe) << 7;
|
||||||
|
const uint32_t perfmonId = perfmonId_msb | perfmonId_lsb;
|
||||||
|
return perfmonId;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(PmRecordSocCommonPrefix) == 8, "sizeof(PmRecordSocCommonPrefix) == 8B");
|
||||||
|
|
||||||
|
#endif
|
||||||
92
libnvsochwpm/test/nv_soc_hwpm_test.cpp
Normal file
92
libnvsochwpm/test/nv_soc_hwpm_test.cpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm_test.h"
|
||||||
|
|
||||||
|
NvSocHwpmTests::NvSocHwpmTests() : testing::Test(), api_table()
|
||||||
|
{}
|
||||||
|
|
||||||
|
NvSocHwpmTests::~NvSocHwpmTests()
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Called once before the tests start to run.
|
||||||
|
void NvSocHwpmTests::SetUpTestCase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called after all tests are done.
|
||||||
|
void NvSocHwpmTests::TearDownTestCase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called before each test is run.
|
||||||
|
void NvSocHwpmTests::SetUp()
|
||||||
|
{
|
||||||
|
LoadNvSocHwpm();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called after each test is run.
|
||||||
|
void NvSocHwpmTests::TearDown()
|
||||||
|
{
|
||||||
|
UnloadNvSocHwpm();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NvSocHwpmTests::LoadNvSocHwpm()
|
||||||
|
{
|
||||||
|
static const char* kLibName = "libnvsochwpm.so";
|
||||||
|
ASSERT_EQ(0, load_nv_soc_hwpm(kLibName, &api_table));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NvSocHwpmTests::UnloadNvSocHwpm()
|
||||||
|
{
|
||||||
|
ASSERT_EQ(0, unload_nv_soc_hwpm(&api_table));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NvSocHwpmTests, MultipleInitExit)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(0, api_table.nv_soc_hwpm_init_fn());
|
||||||
|
ASSERT_EQ(0, api_table.nv_soc_hwpm_init_fn());
|
||||||
|
api_table.nv_soc_hwpm_exit_fn();
|
||||||
|
api_table.nv_soc_hwpm_exit_fn();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure we can get the lib major/minor version without calling init/exit
|
||||||
|
TEST_F(NvSocHwpmTests, EnumerateSystemInfo)
|
||||||
|
{
|
||||||
|
uint32_t major, minor;
|
||||||
|
nv_soc_hwpm_system_attribute attr = NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MAJOR;
|
||||||
|
ASSERT_EQ(0, api_table.nv_soc_hwpm_system_get_info_fn(attr, sizeof(major), &major));
|
||||||
|
attr = NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MINOR;
|
||||||
|
ASSERT_EQ(0, api_table.nv_soc_hwpm_system_get_info_fn(attr, sizeof(minor), &minor));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NvSocHwpmTests, EnumerateSystemInfoNegative)
|
||||||
|
{
|
||||||
|
uint32_t dummy, minor;
|
||||||
|
|
||||||
|
nv_soc_hwpm_system_attribute attr;
|
||||||
|
|
||||||
|
// Should fail with invalid attribute.
|
||||||
|
attr = (nv_soc_hwpm_system_attribute)0xffffffff;
|
||||||
|
ASSERT_NE(0, api_table.nv_soc_hwpm_system_get_info_fn(attr, sizeof(dummy), &dummy));
|
||||||
|
|
||||||
|
attr = NV_SOC_HWPM_SYSTEM_ATTRIBUTE_VERSION_MAJOR;
|
||||||
|
|
||||||
|
// Should fail with invalid buffer size.
|
||||||
|
ASSERT_NE(0, api_table.nv_soc_hwpm_system_get_info_fn(attr, sizeof(uint8_t), &minor));
|
||||||
|
|
||||||
|
// Should fail with invalid buffer ptr.
|
||||||
|
ASSERT_NE(0, api_table.nv_soc_hwpm_system_get_info_fn(attr, sizeof(minor), NULL));
|
||||||
|
}
|
||||||
41
libnvsochwpm/test/nv_soc_hwpm_test.h
Normal file
41
libnvsochwpm/test/nv_soc_hwpm_test.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NV_SOC_HWPM_NV_SOC_HWPM_TEST_H
|
||||||
|
#define NV_SOC_HWPM_NV_SOC_HWPM_TEST_H
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "nv_soc_hwpm_loader.hpp"
|
||||||
|
|
||||||
|
class NvSocHwpmTests : public ::testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NvSocHwpmTests();
|
||||||
|
~NvSocHwpmTests() override;
|
||||||
|
//global start and stop
|
||||||
|
static void SetUpTestCase();
|
||||||
|
static void TearDownTestCase();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//individual start and stop
|
||||||
|
void SetUp() override;
|
||||||
|
void TearDown() override;
|
||||||
|
|
||||||
|
void LoadNvSocHwpm();
|
||||||
|
void UnloadNvSocHwpm();
|
||||||
|
|
||||||
|
nv_soc_hwpm_api_table api_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //NV_SOC_HWPM_NV_SOC_HWPM_TEST_H
|
||||||
935
libnvsochwpm/test/soc_mode_e_buffer.cpp
Normal file
935
libnvsochwpm/test/soc_mode_e_buffer.cpp
Normal file
@@ -0,0 +1,935 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "soc_mode_e_buffer.h"
|
||||||
|
#include "hwpm_record_format.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
SocModeEBuffer::SocModeEBuffer(nv_soc_hwpm_api_table& api_table, nv_soc_hwpm_session session)
|
||||||
|
: m_api_table(api_table)
|
||||||
|
, m_session(session)
|
||||||
|
, m_record_format(RecordFormatType::ModeE)
|
||||||
|
, m_num_valid_records(0)
|
||||||
|
, m_num_overflow_records(0)
|
||||||
|
, m_num_pma_records(0)
|
||||||
|
, m_num_samples(0)
|
||||||
|
, m_delayed_sample_detected(false)
|
||||||
|
, m_merged_samples_detected(false)
|
||||||
|
, m_sum_counter_values(0)
|
||||||
|
, m_zero_timestamp_detected(false)
|
||||||
|
, m_reversed_trigger_count_detected(false)
|
||||||
|
, m_local_trigger_bookmark_mismatch(false)
|
||||||
|
, m_first_pma_timestamp(0)
|
||||||
|
, m_last_pma_timestamp(0)
|
||||||
|
, m_first_sys0_timestamp(0)
|
||||||
|
, m_last_sys0_timestamp(0)
|
||||||
|
, m_pma_buffer(nullptr)
|
||||||
|
, m_membytes_buffer(nullptr)
|
||||||
|
, m_max_records(0)
|
||||||
|
, m_unread_head(0)
|
||||||
|
, m_pma_buffer_size(0)
|
||||||
|
, m_pma_buffer_cpu_va(nullptr)
|
||||||
|
, m_mem_bytes_buffer_cpu_va(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SocModeEBuffer::~SocModeEBuffer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::Initialize()
|
||||||
|
{
|
||||||
|
nv_soc_hwpm_session_attribute session_attr;
|
||||||
|
|
||||||
|
session_attr = NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_SIZE;
|
||||||
|
if (m_api_table.nv_soc_hwpm_session_get_info_fn(
|
||||||
|
m_session,
|
||||||
|
session_attr,
|
||||||
|
sizeof(m_pma_buffer_size),
|
||||||
|
&m_pma_buffer_size)) {
|
||||||
|
printf("ERROR: SOC HWPM session get info buffer size failed!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_attr = NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_RECORD_BUFFER_CPU_VA;
|
||||||
|
if (m_api_table.nv_soc_hwpm_session_get_info_fn(
|
||||||
|
m_session,
|
||||||
|
session_attr,
|
||||||
|
sizeof(m_pma_buffer_cpu_va),
|
||||||
|
&m_pma_buffer_cpu_va)) {
|
||||||
|
printf("ERROR: SOC HWPM session get info stream buffer ptr failed!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
session_attr = NV_SOC_HWPM_SESSION_ATTRIBUTE_PMA_MEM_BYTES_BUFFER_CPU_VA;
|
||||||
|
if (m_api_table.nv_soc_hwpm_session_get_info_fn(
|
||||||
|
m_session,
|
||||||
|
session_attr,
|
||||||
|
sizeof(m_mem_bytes_buffer_cpu_va),
|
||||||
|
&m_mem_bytes_buffer_cpu_va)) {
|
||||||
|
printf("ERROR: SOC HWPM session get info mem bytes buffer ptr failed!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_max_records = m_pma_buffer_size / sizeof(ModeERecordRaw);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocModeEBuffer::ResetParsedData()
|
||||||
|
{
|
||||||
|
m_num_valid_records = 0;
|
||||||
|
m_num_overflow_records = 0;
|
||||||
|
m_num_pma_records = 0;
|
||||||
|
m_num_samples = 0;
|
||||||
|
m_delayed_sample_detected = false;
|
||||||
|
m_merged_samples_detected = false;
|
||||||
|
m_sum_counter_values = 0;
|
||||||
|
m_num_local_triggers = 0;
|
||||||
|
m_zero_timestamp_detected = false;
|
||||||
|
m_reversed_trigger_count_detected = false;
|
||||||
|
m_local_trigger_bookmark_mismatch = false;
|
||||||
|
m_perfmon_id_trigger_count_map.clear();
|
||||||
|
|
||||||
|
m_first_pma_timestamp = 0;
|
||||||
|
m_last_pma_timestamp = 0;
|
||||||
|
m_first_sys0_timestamp = 0;
|
||||||
|
m_last_sys0_timestamp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocModeEBuffer::SetRecordFormat(const RecordFormatType record_format_type)
|
||||||
|
{
|
||||||
|
m_record_format = record_format_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from Perfkit\Shared\Perfkit\Tests\Emulation\SOC\Tests\SocCrossTriggerTest\Src\SocModeEBuffer.cpp
|
||||||
|
#define LOCAL_TRIGGER_BOOKMARK_VAL 0xBEEF
|
||||||
|
void SocModeEBuffer::ParseRecords()
|
||||||
|
{
|
||||||
|
ResetParsedData();
|
||||||
|
|
||||||
|
// init buffer parsing variables
|
||||||
|
uint32_t record_idx_lo = m_unread_head;
|
||||||
|
uint32_t record_idx_hi = m_max_records;
|
||||||
|
bool valid_record_end_detected = false;
|
||||||
|
|
||||||
|
// Buffer wraparound requires two iterations
|
||||||
|
for (uint32_t circular_buffer_segment = 0; circular_buffer_segment < 2;
|
||||||
|
circular_buffer_segment++) {
|
||||||
|
// Iterate records in buffer
|
||||||
|
for (uint32_t ii = record_idx_lo; ii < record_idx_hi; ii++) {
|
||||||
|
auto p_record = (ModeERecordRaw*)(m_pma_buffer_cpu_va) + ii;
|
||||||
|
auto p_record_common_prefix = (PmRecordSocCommonPrefix*)(p_record);
|
||||||
|
uint32_t record_perfmon_id = p_record_common_prefix->GetPerfmonId();
|
||||||
|
|
||||||
|
if (record_perfmon_id == PMA_PerfmonId) { // PMA Record
|
||||||
|
const PmaRecordSoc* p_pma_record =
|
||||||
|
(const PmaRecordSoc*)(p_record_common_prefix);
|
||||||
|
const uint64_t timestamp = p_pma_record->GetPtimer();
|
||||||
|
if (!m_first_pma_timestamp) {
|
||||||
|
m_first_pma_timestamp = timestamp;
|
||||||
|
}
|
||||||
|
m_last_pma_timestamp = timestamp;
|
||||||
|
m_num_pma_records++;
|
||||||
|
} else if (record_perfmon_id) { // Mode C/E Record
|
||||||
|
if (m_record_format == RecordFormatType::ModeC) {
|
||||||
|
auto p_mode_c_record = (ModeCRecordVolta_12x16*)p_record;
|
||||||
|
uint16_t sample_count = p_mode_c_record->GetSampleCount();
|
||||||
|
bool delayed_sampled = p_mode_c_record->IsDelayedSampled();
|
||||||
|
|
||||||
|
// Mode C record does not have TOTAL_TRIG_RCV
|
||||||
|
if (!sample_count && !delayed_sampled) {
|
||||||
|
m_num_overflow_records++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_num_valid_records++;
|
||||||
|
m_num_samples += sample_count;
|
||||||
|
|
||||||
|
if (sample_count > 1) {
|
||||||
|
m_merged_samples_detected = true;
|
||||||
|
}
|
||||||
|
if (delayed_sampled) {
|
||||||
|
m_delayed_sample_detected = true;
|
||||||
|
}
|
||||||
|
for (uint32_t counter_idx = 0; counter_idx < 12;
|
||||||
|
counter_idx++) {
|
||||||
|
m_sum_counter_values += p_mode_c_record->counter[counter_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mode C record does not have TOTAL_TRIG_RCV
|
||||||
|
m_perfmon_id_trigger_count_map.emplace(record_perfmon_id, 0);
|
||||||
|
|
||||||
|
// Local trigger field checks
|
||||||
|
const uint16_t local_trigger_count =
|
||||||
|
p_mode_c_record->counter[10];
|
||||||
|
m_num_local_triggers += local_trigger_count;
|
||||||
|
|
||||||
|
const uint16_t local_trigger_bookmark =
|
||||||
|
p_mode_c_record->counter[11];
|
||||||
|
if (local_trigger_bookmark != LOCAL_TRIGGER_BOOKMARK_VAL) {
|
||||||
|
m_local_trigger_bookmark_mismatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Timestamp monotonic increment check
|
||||||
|
if (!p_mode_c_record->GetTimestamp()) {
|
||||||
|
m_zero_timestamp_detected = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto p_mode_e_record = (ModeERecordVolta*)p_record;
|
||||||
|
uint16_t sample_count = p_mode_e_record->GetSampleCount();
|
||||||
|
bool delayed_sampled = p_mode_e_record->IsDelayedSampled();
|
||||||
|
const uint32_t total_trigger_count = p_mode_e_record->zero2;
|
||||||
|
auto map_entry = m_perfmon_id_trigger_count_map.find(
|
||||||
|
record_perfmon_id);
|
||||||
|
|
||||||
|
// sys0 timestamp
|
||||||
|
if (record_perfmon_id == 0x70B) { // FIXME: halify!!!
|
||||||
|
uint64_t timestamp = p_mode_e_record->GetTimestamp();
|
||||||
|
if (!m_first_sys0_timestamp) {
|
||||||
|
m_first_sys0_timestamp = timestamp;
|
||||||
|
}
|
||||||
|
m_last_sys0_timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sample_count && !delayed_sampled &&
|
||||||
|
(map_entry == m_perfmon_id_trigger_count_map.end() ||
|
||||||
|
map_entry->second == total_trigger_count)) {
|
||||||
|
m_num_overflow_records++;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_num_valid_records++;
|
||||||
|
m_num_samples += sample_count;
|
||||||
|
|
||||||
|
if (sample_count > 1) {
|
||||||
|
m_merged_samples_detected = true;
|
||||||
|
}
|
||||||
|
if (delayed_sampled) {
|
||||||
|
m_delayed_sample_detected = true;
|
||||||
|
}
|
||||||
|
m_sum_counter_values += p_mode_e_record->counter[0] +
|
||||||
|
p_mode_e_record->counter[1] +
|
||||||
|
p_mode_e_record->counter[2] +
|
||||||
|
p_mode_e_record->counter[3];
|
||||||
|
|
||||||
|
// TOTAL_TRIG_RCV monotonic check
|
||||||
|
if (map_entry != m_perfmon_id_trigger_count_map.end()) {
|
||||||
|
if (map_entry->second >= total_trigger_count) {
|
||||||
|
m_reversed_trigger_count_detected = true;
|
||||||
|
}
|
||||||
|
map_entry->second = total_trigger_count;
|
||||||
|
} else {
|
||||||
|
m_perfmon_id_trigger_count_map.emplace(record_perfmon_id,
|
||||||
|
total_trigger_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local trigger field checks
|
||||||
|
const uint16_t local_trigger_count =
|
||||||
|
p_mode_e_record->zero3 & 0xFFFF;
|
||||||
|
m_num_local_triggers += local_trigger_count;
|
||||||
|
|
||||||
|
const uint16_t local_trigger_bookmark =
|
||||||
|
p_mode_e_record->zero3 >> 16;
|
||||||
|
if (local_trigger_bookmark != LOCAL_TRIGGER_BOOKMARK_VAL) {
|
||||||
|
m_local_trigger_bookmark_mismatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Timestamp monotonic increment check
|
||||||
|
if (!p_mode_e_record->GetTimestamp()) {
|
||||||
|
m_zero_timestamp_detected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reach the end of valid records
|
||||||
|
valid_record_end_detected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_record_end_detected) {
|
||||||
|
// Early escape when buffer wraparound does not occur
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Buffer wraparound detected! Alter buffer segment bounds
|
||||||
|
record_idx_lo = 0;
|
||||||
|
record_idx_hi = m_unread_head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetNumValidRecords()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_num_valid_records;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetNumOverflowRecords()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_num_overflow_records;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetNumPmaRecords()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_num_pma_records;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetNumSamples()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_num_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::IsDelayedSampleDetected()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_delayed_sample_detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::IsMergedSamplesDetected()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_merged_samples_detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SocModeEBuffer::GetCounterValueSum()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_sum_counter_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetNumUniquePerfmonID()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_perfmon_id_trigger_count_map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetNumLocalTriggers()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_num_local_triggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::IsZeroTimestampDetected()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_zero_timestamp_detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::IsReversedTriggerCountDetected()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_reversed_trigger_count_detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::IsLocalTriggerBookmarkMismatchDetected()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_local_trigger_bookmark_mismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SocModeEBuffer::GetMemBytes()
|
||||||
|
{
|
||||||
|
// Emulation: Wait for in-flight mem_bytes to arrive.
|
||||||
|
usleep(10000);
|
||||||
|
|
||||||
|
auto* p_mem_bytes_addr = (uint32_t*)(m_mem_bytes_buffer_cpu_va);
|
||||||
|
return *p_mem_bytes_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SocModeEBuffer::GetPmaRecordElapsedTime()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return (m_last_pma_timestamp - m_first_pma_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SocModeEBuffer::GetSysRecordElapsedCycles()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return (m_last_sys0_timestamp - m_first_sys0_timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SocModeEBuffer::GetFirstPmaTimestamp()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_first_pma_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SocModeEBuffer::GetLastPmaTimestamp()
|
||||||
|
{
|
||||||
|
ParseRecords();
|
||||||
|
return m_last_pma_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocModeEBuffer::PrintRecord(PmRecordSocCommonPrefix* record, bool is_pma_record, bool is_mode_c)
|
||||||
|
{
|
||||||
|
char str_buffer[256];
|
||||||
|
|
||||||
|
if (is_pma_record)
|
||||||
|
{
|
||||||
|
auto p_pma_record = (PmaRecordSoc*)(record);
|
||||||
|
sprintf(str_buffer,
|
||||||
|
"[ PMA ] PTIMER %9" PRIu64 ", DR %d, TRIG %d, START %d, END %d, BKMRK %d\n",
|
||||||
|
p_pma_record->GetPtimer(),
|
||||||
|
p_pma_record->IsDroppedRecord(),
|
||||||
|
p_pma_record->GetTotalTriggerCount(),
|
||||||
|
p_pma_record->GetStartTriggerCount(),
|
||||||
|
p_pma_record->GetStopTriggerCount(),
|
||||||
|
p_pma_record->GetBookmark()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (is_mode_c)
|
||||||
|
{
|
||||||
|
auto p_mode_c_record = (ModeCRecordVolta_12x16*)(record);
|
||||||
|
sprintf(str_buffer,
|
||||||
|
"[MODEC] PERFMON %3x, TS %9" PRIu64 ", DS %d, SMPLCNT %d, C0 %d, C1 %d, C2 %d, C3 %d, C4 %d, C5 %d, C6 %d, C7 %d, C8 %d, C9 %d, C10 %d, C11 %d\n",
|
||||||
|
p_mode_c_record->GetPerfmonId(),
|
||||||
|
p_mode_c_record->GetTimestamp(),
|
||||||
|
p_mode_c_record->IsDelayedSampled(),
|
||||||
|
p_mode_c_record->GetSampleCount(),
|
||||||
|
p_mode_c_record->counter[0],
|
||||||
|
p_mode_c_record->counter[1],
|
||||||
|
p_mode_c_record->counter[2],
|
||||||
|
p_mode_c_record->counter[3],
|
||||||
|
p_mode_c_record->counter[4],
|
||||||
|
p_mode_c_record->counter[5],
|
||||||
|
p_mode_c_record->counter[6],
|
||||||
|
p_mode_c_record->counter[7],
|
||||||
|
p_mode_c_record->counter[8],
|
||||||
|
p_mode_c_record->counter[9],
|
||||||
|
p_mode_c_record->counter[10],
|
||||||
|
p_mode_c_record->counter[11]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto p_mode_e_record = (ModeERecordVolta*)(record);
|
||||||
|
sprintf(str_buffer,
|
||||||
|
"[MODEE] PERFMON %3x, TS %9" PRIu64 ", DS %d, SMPLCNT %d, EVENT %d, TRIG0 %d, TRIG1 %d, SAMPL %d, ZERO2 %x, ZERO3 %x\n",
|
||||||
|
p_mode_e_record->GetPerfmonId(),
|
||||||
|
p_mode_e_record->GetTimestamp(),
|
||||||
|
p_mode_e_record->IsDelayedSampled(),
|
||||||
|
p_mode_e_record->GetSampleCount(),
|
||||||
|
p_mode_e_record->event,
|
||||||
|
p_mode_e_record->trig0,
|
||||||
|
p_mode_e_record->trig1,
|
||||||
|
p_mode_e_record->sampl,
|
||||||
|
p_mode_e_record->zero2,
|
||||||
|
p_mode_e_record->zero3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::cerr << str_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function parses the unread records in the PMA buffer and flushes them
|
||||||
|
// as a part of the KEEP_LATEST + buffer wraparound testing. Note that the
|
||||||
|
// parsing/flush operations are done in real time without stopping the PMA
|
||||||
|
// pulse and without doing MEM_BYTES and MEM_BUMP operations.
|
||||||
|
bool SocModeEBuffer::RealtimeParseFlush(SocRealtimeParseFlushData& stats, bool verbose)
|
||||||
|
{
|
||||||
|
// clear output stats
|
||||||
|
stats = {};
|
||||||
|
|
||||||
|
// initialize buffer parsing and bookkeeping variables
|
||||||
|
uint32_t record_idx_lo = m_unread_head;
|
||||||
|
uint32_t record_idx_hi = m_max_records;
|
||||||
|
bool valid_record_end_detected = false;
|
||||||
|
uint64_t last_pma_timestamp = 0;
|
||||||
|
uint32_t last_trigger_count = 0;
|
||||||
|
|
||||||
|
// PART 1: Parse unread records
|
||||||
|
// ============================
|
||||||
|
|
||||||
|
// Buffer wraparound requires two iterations
|
||||||
|
auto p_records = (ModeERecordRaw*)(m_pma_buffer_cpu_va); // FIXME: always Mode E?
|
||||||
|
for (uint32_t circular_buffer_segment = 0; circular_buffer_segment < 2; circular_buffer_segment++)
|
||||||
|
{
|
||||||
|
// Iterate records in buffer
|
||||||
|
for (uint32_t ii = record_idx_lo; ii < record_idx_hi; ii++)
|
||||||
|
{
|
||||||
|
auto p_record_common_prefix = (PmRecordSocCommonPrefix*)(p_records + ii);
|
||||||
|
uint32_t record_perfmon_id = p_record_common_prefix->GetPerfmonId();
|
||||||
|
|
||||||
|
if (record_perfmon_id)
|
||||||
|
{
|
||||||
|
if (record_perfmon_id == PMA_PerfmonId)
|
||||||
|
{
|
||||||
|
auto p_pma_record = (PmaRecordSoc*)p_record_common_prefix;
|
||||||
|
uint64_t curr_ptimer = p_pma_record->GetPtimer();
|
||||||
|
uint32_t total_trig_cnt = p_pma_record->GetTotalTriggerCount();
|
||||||
|
|
||||||
|
if (!curr_ptimer)
|
||||||
|
{
|
||||||
|
// Assume that complete record is not streamed
|
||||||
|
stats.m_incomplete_record_detected = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Incomplete PMA record: ptimer == 0\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!total_trig_cnt)
|
||||||
|
{
|
||||||
|
// Assume that complete record is not streamed
|
||||||
|
stats.m_incomplete_record_detected = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Incomplete PMA record: totalTrigCnt == 0\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (curr_ptimer <= last_pma_timestamp)
|
||||||
|
{
|
||||||
|
stats.m_malformed_record = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Malformed PMA record: ptimer " << curr_ptimer << " <= lastPtimer " << last_pma_timestamp << "\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (total_trig_cnt <= last_trigger_count)
|
||||||
|
{
|
||||||
|
stats.m_malformed_record = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Malformed PMA record: totalTrigCnt " << (int)total_trig_cnt << " <= lastTriggerCount " << (int)last_trigger_count << "\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Ptimer and trigger count for bookkeeping
|
||||||
|
last_pma_timestamp = curr_ptimer;
|
||||||
|
last_trigger_count = total_trig_cnt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto p_mode_e_record = (ModeERecordVolta*)p_record_common_prefix;
|
||||||
|
uint64_t timestamp = p_mode_e_record->GetTimestamp();
|
||||||
|
const uint32_t total_trigger_count = p_mode_e_record->zero2;
|
||||||
|
auto map_entry = m_perfmon_id_trigger_count_map.find(record_perfmon_id);
|
||||||
|
|
||||||
|
if (!timestamp)
|
||||||
|
{
|
||||||
|
// Assume that complete record is not streamed
|
||||||
|
stats.m_incomplete_record_detected = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Incomplete ModeE record: timestamp == 0\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!total_trigger_count)
|
||||||
|
{
|
||||||
|
// Assume that complete record is not streamed
|
||||||
|
stats.m_incomplete_record_detected = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Incomplete ModeE record: totalTriggerCount == 0\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map_entry != m_perfmon_id_trigger_count_map.end())
|
||||||
|
{
|
||||||
|
if (map_entry->second >= total_trigger_count)
|
||||||
|
{
|
||||||
|
stats.m_malformed_record = true;
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
std::cerr << "Malformed ModeE record: totalTriggerCount " << (int)total_trigger_count << " <= lastTriggerCount " << (int)map_entry->second << "\n";
|
||||||
|
PrintRecord(p_record_common_prefix, /*is_pma_record*/ false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
map_entry->second = total_trigger_count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_perfmon_id_trigger_count_map.emplace(record_perfmon_id, total_trigger_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reached here, we consumed one more record
|
||||||
|
stats.m_num_records_consumed++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reach the end of valid records
|
||||||
|
valid_record_end_detected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.m_malformed_record || stats.m_incomplete_record_detected || valid_record_end_detected)
|
||||||
|
{
|
||||||
|
// Early escape when incomplete/malformed record is read, or buffer wraparound does not occur
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Buffer wraparound detected! Alter buffer segment bounds for the second parsing loop
|
||||||
|
stats.m_buffer_wraparound = true;
|
||||||
|
record_idx_lo = 0;
|
||||||
|
record_idx_hi = m_unread_head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PART 2: Flush
|
||||||
|
// =============
|
||||||
|
|
||||||
|
if (stats.m_malformed_record || !stats.m_num_records_consumed)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bytes_to_flush = stats.m_num_records_consumed * sizeof(ModeERecordRaw);
|
||||||
|
if (m_unread_head + stats.m_num_records_consumed <= m_max_records) // Single segment
|
||||||
|
{
|
||||||
|
memset(&p_records[m_unread_head], 0, bytes_to_flush);
|
||||||
|
// Move unread head back to 0 if unreadHead + numRecordsConsumed == maxRecords
|
||||||
|
m_unread_head = (m_unread_head + stats.m_num_records_consumed) % m_max_records;
|
||||||
|
}
|
||||||
|
else // Two segments
|
||||||
|
{
|
||||||
|
int num_records_first_segment = m_max_records - m_unread_head;
|
||||||
|
int num_records_second_segment = stats.m_num_records_consumed - num_records_first_segment;
|
||||||
|
memset(&p_records[m_unread_head], 0, sizeof(ModeERecordRaw) * num_records_first_segment);
|
||||||
|
memset(&p_records[0], 0, sizeof(ModeERecordRaw) * num_records_second_segment);
|
||||||
|
m_unread_head = num_records_second_segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocModeEBuffer::FlushRecordsInBuffer(const uint32_t bytes_to_flush)
|
||||||
|
{
|
||||||
|
// Empty flush
|
||||||
|
if (!bytes_to_flush) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t num_records_to_flush = bytes_to_flush / sizeof(ModeERecordRaw);
|
||||||
|
auto p_records = (ModeERecordRaw*)(m_pma_buffer_cpu_va);
|
||||||
|
if (m_unread_head + num_records_to_flush <= m_max_records) // Single segment
|
||||||
|
{
|
||||||
|
memset(&p_records[m_unread_head], 0, bytes_to_flush);
|
||||||
|
// Move unread head back to 0 if unreadHead + numRecordsToFlush == maxRecords
|
||||||
|
m_unread_head = (m_unread_head + num_records_to_flush) % m_max_records;
|
||||||
|
}
|
||||||
|
else // Two segments
|
||||||
|
{
|
||||||
|
int num_records_first_segment = m_max_records - m_unread_head;
|
||||||
|
int num_records_second_segment = num_records_to_flush - num_records_first_segment;
|
||||||
|
memset(&p_records[m_unread_head], 0, sizeof(ModeERecordRaw) * num_records_first_segment);
|
||||||
|
memset(&p_records[0], 0, sizeof(ModeERecordRaw) * num_records_second_segment);
|
||||||
|
m_unread_head = num_records_second_segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_to_flush == m_pma_buffer_size) {
|
||||||
|
std::cout << "WARNING: Buffer is full! Reset PMA MEM_HEAD to guarantee HW-SW consistency...\n";
|
||||||
|
// TODO: reset PMA MEM_HEAD need regops
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report flushed bytes to HW
|
||||||
|
nv_soc_hwpm_pma_channel_state_params param = {};
|
||||||
|
param.in_mem_bump = bytes_to_flush;
|
||||||
|
param.in_stream_mem_bytes = 0;
|
||||||
|
param.in_check_overflow = 0;
|
||||||
|
param.in_read_mem_head = 0;
|
||||||
|
if (m_api_table.nv_soc_hwpm_session_set_get_pma_state_fn(
|
||||||
|
m_session, ¶m)) {
|
||||||
|
std::cerr << "ERROR: SOC HWPM session set get pma state mem bump failed!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocModeEBuffer::PrintRecords(const size_t num_records_to_print) const
|
||||||
|
{
|
||||||
|
char str_buffer[256];
|
||||||
|
std::deque<std::string> record_strings;
|
||||||
|
if (m_record_format == RecordFormatType::ModeC)
|
||||||
|
{
|
||||||
|
printf("No. PerfmonID Elaps_cyc DS SmpCt C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 \n");
|
||||||
|
printf("---- --------- --------- -- ----- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("No. PerfmonID Elaps_cyc DS SmpCt Count0 Count1 Count2 Count3 TrgB TrgA \n");
|
||||||
|
printf("---- --------- --------- -- ----- ------- ------- ------- ------- -------- --------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t record_idx_lo = m_unread_head;
|
||||||
|
uint32_t record_idx_hi = m_max_records;
|
||||||
|
bool valid_record_end_detected = false;
|
||||||
|
|
||||||
|
for (uint32_t circular_buffer_segment = 0; circular_buffer_segment < 2; circular_buffer_segment++)
|
||||||
|
{
|
||||||
|
// Iterate records in buffer
|
||||||
|
for (uint32_t ii = record_idx_lo; ii < record_idx_hi; ii++)
|
||||||
|
{
|
||||||
|
auto p_record = (ModeERecordRaw*)(m_pma_buffer_cpu_va) + ii;
|
||||||
|
auto p_record_common_prefix = (PmRecordSocCommonPrefix*)(p_record);
|
||||||
|
uint32_t perfmon_id = p_record_common_prefix->GetPerfmonId();
|
||||||
|
|
||||||
|
if (perfmon_id && perfmon_id != PMA_PerfmonId) // Mode C/E Record
|
||||||
|
{
|
||||||
|
if (m_record_format == RecordFormatType::ModeC)
|
||||||
|
{
|
||||||
|
auto p_mode_c_record = (ModeCRecordVolta_12x16*)p_record;
|
||||||
|
uint64_t timestamp = p_mode_c_record->GetTimestamp();
|
||||||
|
bool is_delayed_sampled = p_mode_c_record->IsDelayedSampled();
|
||||||
|
uint32_t sample_cnt = p_mode_c_record->GetSampleCount();
|
||||||
|
|
||||||
|
sprintf(str_buffer,
|
||||||
|
"%4d %9x %9" PRIu64 " %2x %5d %4x %4x %4x %4x %4x %4x %4x %4x %4x %4x %4x %4x\n",
|
||||||
|
ii,
|
||||||
|
perfmon_id,
|
||||||
|
timestamp,
|
||||||
|
is_delayed_sampled,
|
||||||
|
sample_cnt,
|
||||||
|
p_mode_c_record->counter[0],
|
||||||
|
p_mode_c_record->counter[1],
|
||||||
|
p_mode_c_record->counter[2],
|
||||||
|
p_mode_c_record->counter[3],
|
||||||
|
p_mode_c_record->counter[4],
|
||||||
|
p_mode_c_record->counter[5],
|
||||||
|
p_mode_c_record->counter[6],
|
||||||
|
p_mode_c_record->counter[7],
|
||||||
|
p_mode_c_record->counter[8],
|
||||||
|
p_mode_c_record->counter[9],
|
||||||
|
p_mode_c_record->counter[10],
|
||||||
|
p_mode_c_record->counter[11]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto p_mode_e_record = (ModeERecordVolta*)p_record;
|
||||||
|
uint64_t timestamp = p_mode_e_record->GetTimestamp();
|
||||||
|
bool is_delayed_sampled = p_mode_e_record->IsDelayedSampled();
|
||||||
|
uint32_t sample_cnt = p_mode_e_record->GetSampleCount();
|
||||||
|
|
||||||
|
sprintf(str_buffer,
|
||||||
|
"%4d %9x %9" PRIu64 " %2x %5d %7d %7d %7d %7d %8x %8x\n",
|
||||||
|
ii,
|
||||||
|
perfmon_id,
|
||||||
|
timestamp,
|
||||||
|
is_delayed_sampled,
|
||||||
|
sample_cnt,
|
||||||
|
p_mode_e_record->event,
|
||||||
|
p_mode_e_record->trig0,
|
||||||
|
p_mode_e_record->trig1,
|
||||||
|
p_mode_e_record->sampl,
|
||||||
|
p_mode_e_record->zero2,
|
||||||
|
p_mode_e_record->zero3
|
||||||
|
);
|
||||||
|
}
|
||||||
|
record_strings.emplace_back(std::string(str_buffer));
|
||||||
|
|
||||||
|
if (record_strings.size() > num_records_to_print)
|
||||||
|
{
|
||||||
|
record_strings.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (perfmon_id == PMA_PerfmonId)
|
||||||
|
{
|
||||||
|
// Do not print PMA records in this function
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reach the end of valid records
|
||||||
|
valid_record_end_detected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_record_end_detected)
|
||||||
|
{
|
||||||
|
// Early escape when buffer wraparound does not occur
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Buffer wraparound
|
||||||
|
record_idx_lo = 0;
|
||||||
|
record_idx_hi = m_unread_head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t ii = 0; ii < record_strings.size(); ii++)
|
||||||
|
{
|
||||||
|
std::cout << record_strings[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump the complete buffer starting from beginning to end. Try to parse
|
||||||
|
// records if possible, but don't count on it. ONLY FOR DEBUG!
|
||||||
|
void SocModeEBuffer::DumpBuffer()
|
||||||
|
{
|
||||||
|
auto p_records = (ModeERecordRaw*)(m_pma_buffer_cpu_va);
|
||||||
|
auto p_record_common_prefix = (PmRecordSocCommonPrefix*)(p_records);
|
||||||
|
auto perfmon_id = p_record_common_prefix->GetPerfmonId();
|
||||||
|
|
||||||
|
// Print the first record
|
||||||
|
if (perfmon_id == PMA_PerfmonId)
|
||||||
|
{
|
||||||
|
PrintRecord(p_record_common_prefix, true /* isPmaRecord */);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintRecord(p_record_common_prefix, false /* isPmaRecord */, m_record_format == RecordFormatType::ModeC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through remaining records
|
||||||
|
uint32_t matching_records = 0;
|
||||||
|
for (uint32_t ii = 1; ii < m_max_records; ii++)
|
||||||
|
{
|
||||||
|
auto p_record = (ModeERecordRaw*)(m_pma_buffer_cpu_va) + ii;
|
||||||
|
|
||||||
|
auto p_record_last = (ModeERecordRaw*)(m_pma_buffer_cpu_va) + ii - 1;
|
||||||
|
if (memcmp(p_record, p_record_last, sizeof(ModeERecordRaw)) == 0)
|
||||||
|
{
|
||||||
|
// One more record identical to the previous one: just count it and continue
|
||||||
|
++matching_records;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Record mismatch
|
||||||
|
if (matching_records)
|
||||||
|
{
|
||||||
|
// If we have counted identical records, dump the count and reset it
|
||||||
|
std::cout << matching_records << " more records identical to the previous one...\n";
|
||||||
|
matching_records = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the new record
|
||||||
|
auto p_record_common_prefix = (PmRecordSocCommonPrefix*)(p_record);
|
||||||
|
auto perfmon_id = p_record_common_prefix->GetPerfmonId();
|
||||||
|
if (perfmon_id == PMA_PerfmonId)
|
||||||
|
{
|
||||||
|
PrintRecord(p_record_common_prefix, true /* isPmaRecord */);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintRecord(p_record_common_prefix, false /* isPmaRecord */, m_record_format == RecordFormatType::ModeC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have accumulated any identical records at the end, print it
|
||||||
|
if (matching_records)
|
||||||
|
{
|
||||||
|
std::cout << matching_records << " more records identical to the previous one...\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SocModeEBuffer::PrintPmaRecords(const size_t num_records_to_print) const
|
||||||
|
{
|
||||||
|
char str_buffer[256];
|
||||||
|
std::deque<std::string> record_strings;
|
||||||
|
printf("No. Ptimer DR TotalTrig StartTrig StopTrig Bookmark \n");
|
||||||
|
printf("---- --------- -- --------- --------- --------- ---------\n");
|
||||||
|
|
||||||
|
uint32_t record_idx_lo = m_unread_head;
|
||||||
|
uint32_t record_idx_hi = m_max_records;
|
||||||
|
bool valid_record_end_detected = false;
|
||||||
|
|
||||||
|
for (uint32_t circular_buffer_segment = 0;
|
||||||
|
circular_buffer_segment < 2;
|
||||||
|
circular_buffer_segment++)
|
||||||
|
{
|
||||||
|
// Iterate records in buffer
|
||||||
|
for (uint32_t ii = record_idx_lo; ii < record_idx_hi; ii++)
|
||||||
|
{
|
||||||
|
auto p_records = (ModeERecordVolta*)(m_pma_buffer_cpu_va);
|
||||||
|
auto p_record_common_prefix =
|
||||||
|
(PmRecordSocCommonPrefix*)(&p_records[ii]);
|
||||||
|
uint32_t perfmon_id = p_record_common_prefix->GetPerfmonId();
|
||||||
|
|
||||||
|
if (perfmon_id == PMA_PerfmonId) // PMA Record
|
||||||
|
{
|
||||||
|
const PmaRecordSoc* p_pma_record =
|
||||||
|
(const PmaRecordSoc*)(p_record_common_prefix);
|
||||||
|
uint64_t timestamp = p_pma_record->GetPtimer();
|
||||||
|
uint32_t total_trig_cnt =
|
||||||
|
p_pma_record->GetTotalTriggerCount();
|
||||||
|
uint32_t start_trig_cnt =
|
||||||
|
p_pma_record->GetStartTriggerCount();
|
||||||
|
uint32_t stop_trig_cnt =
|
||||||
|
p_pma_record->GetStopTriggerCount();
|
||||||
|
uint32_t bookmark = p_pma_record->GetBookmark();
|
||||||
|
bool is_dropped_record =
|
||||||
|
p_pma_record->IsDroppedRecord();
|
||||||
|
|
||||||
|
sprintf(str_buffer,
|
||||||
|
"%4d %9" PRIu64 " %2x %9d %9d %9d %9d\n",
|
||||||
|
ii,
|
||||||
|
timestamp,
|
||||||
|
is_dropped_record,
|
||||||
|
total_trig_cnt,
|
||||||
|
start_trig_cnt,
|
||||||
|
stop_trig_cnt,
|
||||||
|
bookmark
|
||||||
|
);
|
||||||
|
record_strings.emplace_back(std::string(str_buffer));
|
||||||
|
|
||||||
|
if (record_strings.size() > num_records_to_print)
|
||||||
|
{
|
||||||
|
record_strings.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (perfmon_id) // Mode C/E Record
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reach the end of valid records
|
||||||
|
valid_record_end_detected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid_record_end_detected)
|
||||||
|
{
|
||||||
|
// Early escape when buffer wraparound does not occur
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Buffer wraparound
|
||||||
|
record_idx_lo = 0;
|
||||||
|
record_idx_hi = m_unread_head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t ii = 0; ii < record_strings.size(); ii++)
|
||||||
|
{
|
||||||
|
std::cout << record_strings[ii];
|
||||||
|
}
|
||||||
|
}
|
||||||
116
libnvsochwpm/test/soc_mode_e_buffer.h
Normal file
116
libnvsochwpm/test/soc_mode_e_buffer.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm_loader.hpp"
|
||||||
|
#include "hwpm_record_format.h"
|
||||||
|
|
||||||
|
enum RecordFormatType
|
||||||
|
{
|
||||||
|
ModeC,
|
||||||
|
ModeE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// realtime parse-flush
|
||||||
|
struct SocRealtimeParseFlushData
|
||||||
|
{
|
||||||
|
uint32_t m_num_records_consumed;
|
||||||
|
bool m_buffer_wraparound;
|
||||||
|
bool m_incomplete_record_detected;
|
||||||
|
bool m_malformed_record;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SocModeEBuffer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
void ResetParsedData();
|
||||||
|
void ParseRecords();
|
||||||
|
void PrintRecord(PmRecordSocCommonPrefix* record, bool is_pma_record,
|
||||||
|
bool is_mode_c = false);
|
||||||
|
|
||||||
|
nv_soc_hwpm_api_table m_api_table;
|
||||||
|
nv_soc_hwpm_session m_session;
|
||||||
|
|
||||||
|
RecordFormatType m_record_format;
|
||||||
|
|
||||||
|
// Parsed data
|
||||||
|
uint32_t m_num_valid_records;
|
||||||
|
uint32_t m_num_overflow_records;
|
||||||
|
uint32_t m_num_pma_records;
|
||||||
|
uint32_t m_num_samples;
|
||||||
|
bool m_delayed_sample_detected;
|
||||||
|
bool m_merged_samples_detected;
|
||||||
|
uint64_t m_sum_counter_values;
|
||||||
|
uint32_t m_num_local_triggers;
|
||||||
|
bool m_zero_timestamp_detected;
|
||||||
|
bool m_reversed_trigger_count_detected;
|
||||||
|
bool m_local_trigger_bookmark_mismatch;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> m_perfmon_id_trigger_count_map;
|
||||||
|
|
||||||
|
uint64_t m_first_pma_timestamp;
|
||||||
|
uint64_t m_last_pma_timestamp;
|
||||||
|
|
||||||
|
uint64_t m_first_sys0_timestamp;
|
||||||
|
uint64_t m_last_sys0_timestamp;
|
||||||
|
|
||||||
|
uint8_t* m_pma_buffer;
|
||||||
|
uint8_t* m_membytes_buffer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t m_max_records;
|
||||||
|
uint32_t m_unread_head;
|
||||||
|
size_t m_pma_buffer_size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void* m_pma_buffer_cpu_va;
|
||||||
|
void* m_mem_bytes_buffer_cpu_va;
|
||||||
|
|
||||||
|
SocModeEBuffer(
|
||||||
|
nv_soc_hwpm_api_table& api_table,
|
||||||
|
nv_soc_hwpm_session session);
|
||||||
|
~SocModeEBuffer();
|
||||||
|
bool Initialize();
|
||||||
|
void SetRecordFormat(const RecordFormatType record_format_type);
|
||||||
|
|
||||||
|
uint32_t GetNumValidRecords();
|
||||||
|
uint32_t GetNumOverflowRecords();
|
||||||
|
uint32_t GetNumPmaRecords();
|
||||||
|
uint32_t GetNumSamples();
|
||||||
|
bool IsDelayedSampleDetected();
|
||||||
|
bool IsMergedSamplesDetected();
|
||||||
|
uint64_t GetCounterValueSum();
|
||||||
|
uint32_t GetNumUniquePerfmonID();
|
||||||
|
uint32_t GetNumLocalTriggers();
|
||||||
|
bool IsZeroTimestampDetected();
|
||||||
|
bool IsReversedTriggerCountDetected();
|
||||||
|
bool IsLocalTriggerBookmarkMismatchDetected();
|
||||||
|
uint32_t GetMemBytes();
|
||||||
|
uint64_t GetPmaRecordElapsedTime();
|
||||||
|
uint64_t GetSysRecordElapsedCycles();
|
||||||
|
uint64_t GetFirstPmaTimestamp();
|
||||||
|
uint64_t GetLastPmaTimestamp();
|
||||||
|
|
||||||
|
bool FlushRecordsInBuffer(const uint32_t bytes_to_flush);
|
||||||
|
bool RealtimeParseFlush(SocRealtimeParseFlushData& stats, bool verbose);
|
||||||
|
void PrintRecords(const size_t num_records_to_print) const;
|
||||||
|
void PrintPmaRecords(const size_t num_records_to_print) const;
|
||||||
|
void DumpBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
1755
libnvsochwpm/test/t241_test.cpp
Normal file
1755
libnvsochwpm/test/t241_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
103
libnvsochwpm/test/t241_test.h
Normal file
103
libnvsochwpm/test/t241_test.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef T241_TEST_H
|
||||||
|
#define T241_TEST_H
|
||||||
|
|
||||||
|
#include "nv_soc_hwpm_test.h"
|
||||||
|
|
||||||
|
#define T241_MAX_SOCKETS 4
|
||||||
|
|
||||||
|
class T241Tests : public NvSocHwpmTests
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
T241Tests();
|
||||||
|
~T241Tests() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct PmaConfigurationParams
|
||||||
|
{
|
||||||
|
PmaConfigurationParams()
|
||||||
|
{
|
||||||
|
enable_streaming = false;
|
||||||
|
pulse_interval = 0;
|
||||||
|
enable_pma_record = false;
|
||||||
|
keep_latest = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enable_streaming;
|
||||||
|
uint32_t pulse_interval;
|
||||||
|
bool enable_pma_record;
|
||||||
|
bool keep_latest;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PmmConfigurationParams
|
||||||
|
{
|
||||||
|
enum Mode {
|
||||||
|
MODE_B,
|
||||||
|
MODE_C,
|
||||||
|
MODE_E
|
||||||
|
};
|
||||||
|
|
||||||
|
PmmConfigurationParams()
|
||||||
|
{
|
||||||
|
mode = MODE_B;
|
||||||
|
perfmon_idx = 0;
|
||||||
|
enable_local_triggering = false;
|
||||||
|
enable_overflow_priming = false;
|
||||||
|
collect_one = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Mode mode;
|
||||||
|
uint32_t perfmon_idx;
|
||||||
|
|
||||||
|
bool enable_local_triggering;
|
||||||
|
bool enable_overflow_priming;
|
||||||
|
bool collect_one;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SetUp() override;
|
||||||
|
void TearDown() override;
|
||||||
|
|
||||||
|
void GetDevices();
|
||||||
|
|
||||||
|
void TestRegopsRead(nv_soc_hwpm_session session,
|
||||||
|
uint64_t pma_record_buffer_pma_va,
|
||||||
|
size_t record_buffer_size);
|
||||||
|
void TestRegopsWrite(nv_soc_hwpm_session session);
|
||||||
|
|
||||||
|
void RegOpWrite32(
|
||||||
|
nv_soc_hwpm_session session, uint64_t address, uint32_t value, uint32_t mask);
|
||||||
|
void RegOpRead32(
|
||||||
|
nv_soc_hwpm_session session, uint64_t address, uint32_t *value);
|
||||||
|
|
||||||
|
void SetupPma(nv_soc_hwpm_session session, const PmaConfigurationParams& params);
|
||||||
|
void EnablePmaStreaming(nv_soc_hwpm_session session, const PmaConfigurationParams& params);
|
||||||
|
void SetupPmm(nv_soc_hwpm_session session, const PmmConfigurationParams& params);
|
||||||
|
void SetupWatchbus(nv_soc_hwpm_session session, const PmmConfigurationParams& params);
|
||||||
|
void TeardownPma(nv_soc_hwpm_session session);
|
||||||
|
void TeardownPmm(nv_soc_hwpm_session session, const PmmConfigurationParams& params);
|
||||||
|
void TeardownPerfmux(nv_soc_hwpm_session session);
|
||||||
|
void IssuePmaTrigger(nv_soc_hwpm_session session);
|
||||||
|
void HarvestCounters(
|
||||||
|
nv_soc_hwpm_session session,
|
||||||
|
const PmmConfigurationParams& params,
|
||||||
|
const uint32_t sig_val[4]);
|
||||||
|
|
||||||
|
nv_soc_hwpm_device t241_dev[T241_MAX_SOCKETS];
|
||||||
|
uint32_t t241_dev_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // T241_TEST_H
|
||||||
31
libnvsochwpm/tmake/lib/Makefile.interface.tmk
Normal file
31
libnvsochwpm/tmake/lib/Makefile.interface.tmk
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
################################### tell Emacs this is a -*- makefile-gmake -*-
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# tmake for SW Mobile component makefile
|
||||||
|
#
|
||||||
|
# libnvsochwpm: shared and static library interface
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
ifdef NV_INTERFACE_FLAG_SHARED_LIBRARY_SECTION
|
||||||
|
NV_INTERFACE_NAME := nvsochwpm
|
||||||
|
NV_INTERFACE_EXPORTS := ../../os/lnx/libnvsochwpm
|
||||||
|
NV_INTERFACE_PUBLIC_INCLUDES := ../../include
|
||||||
|
NV_INTERFACE_COMPONENT_DIR := .
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef NV_INTERFACE_FLAG_STATIC_LIBRARY_SECTION
|
||||||
|
NV_INTERFACE_NAME := nvsochwpm_static
|
||||||
|
NV_INTERFACE_COMPONENT_DIR := .
|
||||||
|
endif
|
||||||
71
libnvsochwpm/tmake/lib/Makefile.tmk
Normal file
71
libnvsochwpm/tmake/lib/Makefile.tmk
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
################################### tell Emacs this is a -*- makefile-gmake -*-
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# tmake for SW Mobile component makefile
|
||||||
|
#
|
||||||
|
# libnvsochwpm: shared and static library
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# Common part of shared and static library build
|
||||||
|
define nvsochwpm_common_make
|
||||||
|
|
||||||
|
NV_COMPONENT_OWN_INTERFACE_DIR := .
|
||||||
|
|
||||||
|
_top_hwpm_dir = ../../../
|
||||||
|
|
||||||
|
_soc_hwpm_dir = ../../
|
||||||
|
|
||||||
|
NV_COMPONENT_SOURCES := \
|
||||||
|
$$(_soc_hwpm_dir)/common/log.c \
|
||||||
|
$$(_soc_hwpm_dir)/os/lnx/nv_soc_hwpm_lnx.c \
|
||||||
|
$$(_soc_hwpm_dir)/nv_soc_hwpm.c
|
||||||
|
|
||||||
|
NV_COMPONENT_INCLUDES += \
|
||||||
|
$$(_soc_hwpm_dir) \
|
||||||
|
$$(_soc_hwpm_dir)/include \
|
||||||
|
$$(_top_hwpm_dir)/include \
|
||||||
|
|
||||||
|
# clear variables
|
||||||
|
_soc_hwpm_dir :=
|
||||||
|
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Build shared library
|
||||||
|
ifdef NV_COMPONENT_FLAG_SHARED_LIBRARY_SECTION
|
||||||
|
include $(NV_BUILD_START_COMPONENT)
|
||||||
|
|
||||||
|
NV_COMPONENT_NAME := nvsochwpm
|
||||||
|
|
||||||
|
$(eval $(nvsochwpm_common_make))
|
||||||
|
|
||||||
|
include $(NV_BUILD_SHARED_LIBRARY)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Build static library for test
|
||||||
|
ifdef NV_COMPONENT_FLAG_STATIC_LIBRARY_SECTION
|
||||||
|
include $(NV_BUILD_START_COMPONENT)
|
||||||
|
|
||||||
|
NV_COMPONENT_NAME := nvsochwpm_static
|
||||||
|
|
||||||
|
$(eval $(nvsochwpm_common_make))
|
||||||
|
|
||||||
|
include $(NV_BUILD_STATIC_LIBRARY)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# indent-tabs-mode: t
|
||||||
|
# tab-width: 8
|
||||||
|
# End:
|
||||||
|
# vi: set tabstop=8 noexpandtab:
|
||||||
56
libnvsochwpm/tmake/test/Makefile.tmk
Normal file
56
libnvsochwpm/tmake/test/Makefile.tmk
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
################################### tell Emacs this is a -*- makefile-gmake -*-
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# tmake for SW Mobile component makefile
|
||||||
|
#
|
||||||
|
# nv_soc_test: unit testing for libnvsochwpm
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
ifdef NV_COMPONENT_FLAG_NVTEST_EXECUTABLE_SECTION
|
||||||
|
include $(NV_BUILD_START_COMPONENT)
|
||||||
|
|
||||||
|
NV_COMPONENT_NAME := nv_soc_hwpm_test
|
||||||
|
|
||||||
|
NV_COMPONENT_SOURCES := \
|
||||||
|
nv_soc_hwpm_test.cpp \
|
||||||
|
t241_test.cpp
|
||||||
|
|
||||||
|
_soc_hwpm_dir = ../../
|
||||||
|
|
||||||
|
NV_COMPONENT_CFLAGS := -DNV_IS_LDK=1 -Wall
|
||||||
|
|
||||||
|
NV_COMPONENT_INCLUDES := \
|
||||||
|
$(_common_includes) \
|
||||||
|
$(NV_SOURCE)/3rdparty/google/googletest/googletest/include \
|
||||||
|
$(NV_SOURCE)/3rdparty/google/googletest/googlemock/include \
|
||||||
|
$$(_soc_hwpm_dir)/include
|
||||||
|
|
||||||
|
NV_COMPONENT_NEEDED_STATIC_INTERFACE_DIRS := \
|
||||||
|
$(NV_SOURCE)/3rdparty/google/googletest/googletest \
|
||||||
|
$(NV_SOURCE)/3rdparty/google/googletest/googlemock
|
||||||
|
|
||||||
|
ifeq ($(NV_BUILD_CONFIGURATION_IS_COVERAGE),1)
|
||||||
|
NV_COMPONENT_CFLAGS += --coverage
|
||||||
|
endif
|
||||||
|
|
||||||
|
NV_COMPONENT_SYSTEM_SHARED_LIBRARIES := \
|
||||||
|
stdc++ \
|
||||||
|
dl \
|
||||||
|
pthread
|
||||||
|
|
||||||
|
NV_COMPONENT_CODE_GENERATION := c++11
|
||||||
|
|
||||||
|
include $(NV_BUILD_NVTEST_EXECUTABLE)
|
||||||
|
endif
|
||||||
Reference in New Issue
Block a user