pva: mirror from gitlab cv/pva-sys-sw

Gitlab commit 54b5ea8396784 ("Revert "deploy: Update NvSCI p...")

Changes since last deployment:

54b5ea83: Revert "deploy: Update NvSCI path in tegra tree"
1d42b346: Revert "deploy: update nvidia-oot path"
5819cf8b: Fix Misra defect of type 5.1
d9561abf: Fw: Fix Misra defects
ec8941c0: coverity: Qnx safety upload job timout increase
66fb1410: Fix pva_waiter_thread_func in umd tests.
0f06989c: Misra defect fixes in QNX KMD
76532814: Static defect fixes
1cbd5a36: Fix Misra defects
0deee89b: Fix misra defects
60335a28: Fix Misra defects
dbd5301d: Port pva_intf_test to pva_umd_tests
d2e0b878: fw: Fix CCM violations in DMA cmds
f4bc3069: Misra fixes in QNX KMD
f07460f1: fw: Make pva_fw_bm_sections.h private include
cf3c9eaa: pva_fw: prevent interrupt storm on print flush
8d11e690: tests: tag tests with negative and long_duration
e2c592dc: Add dmesg checks for non-negative UMD tests
c162d5d4: deploy: fix scatter file dependency
920f6439: tests: Mark negative tests with prefix negative_
bf855422: fw: Fix abort message overflow
00fa97d6: fw: refactor: remove unused or empty files
34d3f41f: fw: refactor: use _init_ in boot unit file names
ca0dfd16: fw: refactor: clean-up function scopes
8215ec86: Static defect fixes(Misra 10.3, CERT INT31-C)
4ffaaf80: Static defects in QNX KMD
0a8af77b: kmd: DMA validation disabled for test_mode
21063625: perf: add new perf metrics
38532a9b: ci: exclude pva_fw_bm_sections.h from checkpatch
19adcb9a: fw: refactor baremetal v3 folder
f03503ba: fw: refactor baremetal wdt folder
6530b0f1: fw: refactor baremetal utility folder
46c373fb: fw: refactor baremetal pe folder
4c3e2ccf: fw: refactor baremetal hal folder
f0f2e0d3: fw: refactor baremetal dma folder
b95e6512: fw: refactor baremetal boot code
9a8552c6: Static defect fixes
7377ba1c: coverity: fix coverity file permissions
79437d05: coverity: upload cert data for non safety
b9d4eb16: pva: Update allowed state APIs in UMD
7ea85e62: Fix static defects pfsd part 3
d83d03fc: fw: Refactor switch-case statements
d562a635: fw: Fix MISRA violation
040a1a29: Update CI/CD pipeline builds
d88e3378: fw: fix static defects in l2sram changes
d6c0b729: Increasing SIM timeout
f34c1707: L2SRAM Bug Fix
d8ea3fe5: fw: Fix MISRA defects (10.3, 10.4, 1.5)
d585b0f9: tests: Port Security Checks from V2
ef70bab8: Port interaface ests to pva_umd_tests
188fbbed: Misra Violation Fixes
421c1fc0: Static defects in QNX KMD
b0cddda4: cmake: Fix cupva build
af5d307d: Fix GENERIC_CLOCK_FRQ & eventlib_write call, others
849a4a9e: fw: remove PE interrupt log print
da3c1a16: PVA: export pva_get_api_restrictions umd library
884c1617: Standardize baremetal src code
b9ea40ac: Re-enable the tests filtered out in the bug
4016fbaf: fw: Move R5 OCD code to DRAM
d50803b1: fw: Fix CERT defects
6b699175: dvms: Update the public API for DVMS state
c5b550bc: cmake: fix precedence of CLI arg
20af216d: docker: update coverity license
33a28dbd: Fix MISRA 10.4 defects in QNX KMD
187b4414: Fix static defects in pfsd change
91cea667: ci: Add Parallel SQA Stress Test Pipeline
ec8d5f6a: Fix MISRA defects in QNX KMD
b8dd4b72: Fix static defects in pfsd change
98b52770: Port the following pva_intf_test to pva_umd_tests.
2e8e48b0: Updates in QNX KMD: MISRA Fixes
ca4a4e47: Update elfs to fix PPE parity error
c1e97e29: Fix CERT defects in QNX KMD
9f012192: fw: Fix static defects
0434d413: Update deploy script to use PROD and DEV profiles
79c141a3: kmd: bugfix: enforce ctx init for sync ops
c2d19878: fw: Fix Cert defects
2ef3651b: fw: Fix CERT defects
668e92f6: Update device probe in Linux KMD
96c4c365: Fix FW error printing for baremetal
10e76b98: Port the following interface tests to umd tests.
01e68097: Enable pva_fw_utests in CI/CD.
e7928a62: Fix CERT defects in QNX KMD
82af1ecb: tests: mark negative UMD tests with prefix
72400087: kmd: fix incorrect log level
d5d1ac35: Update kernel API class_create
72e01b15: deploy: Add nvplayfair to tests template
1237841a: Add pfsd support
6c481474: Update tests and CI for safety builds
88346e94: Add PROD, DEV and INTERNAL build profiles
872f814f: Add build flag for Tegrastats
2ea9c786: Add build flag for MODS test support
4cb0c338: Add build flag for error injection
4d530991: Add build flags for FW profiling and tracepoints
4a02d022: Add build flag for debug prints
fc2aa7aa: Add build flag for VPU OCD (DOIP)
5ccf9d23: Add build flag for HWPM
c69dc657: Add build flag for golden reg checks
21529167: fw: Fix Cert defects
80e032c9: fw: Fix CCM violations in FW cmds
e170cc47: fw: Fix L2SRAM CCM violation
02b82f60: Fix QNX KMD Misra Violations
6594180b: fw: Fix CCM violations
b34f050d: umd: Misra Dir 4.7 defects fix
7a5d7f74: umd: Fix CERT and Top25 defects
7d49aeea: umd: Fix cert INT31 INT34 INT36 defects
aaef325b: fw: Fix dma cmds CCM violations
a1bcadcd: Fix HWPM base address and init failures
437bdeec: Cleanup device probe and wrapper indirections in Linux kernel
0bd92f89: fw: Fix CCM violations
9c01c5c2: fw: Fix L2SRAM CCM violations
25d314fe: doxy: Update Doxygen comments to make it more generic
cfd6fcbe: KMD: Added documentation for common
e7b93f9a: doxy: Add Doxygen to all KMD shim APIs
da32cbea: doxy: Add Doxygen comments for KMD QNX files
5e22bb15: ci: Reduce test iteration count
2a91d9e5: ci: Remove testing for debug build
b56ead62: fw: Fix pe CCM violations
1ac4c005: fw: Fix DMA CCM violations
e223d5ee: fw: Fix PE CCM violations
75d229cc: Improve error path for FW coverage dump
2d5be991: Do not use GSC when testing in CI
c81f3b72: dedicated coverage tests script
8e8ab336: ci: Add firmware vectorcast build to CI
eb7ea48d: vcast.py: Add firmware support
f3e344af: Add vcast build + test to CI
8e5db8ba: Add vectorcast support
5bc91a84: Add vectorcast to docker image
02d82e46: Fix KMD Misra Rule 10.1 violations
e2386c0c: Dump PVA FW Coverage
3996decf: umd: Fix CERT and MISRA defects
d9fe5c5d: Add QNX SR support in CI/CD
d1c991a9: pva: coverity 7.2 release update
754c74ec: Port the following intreface tests to umd tests
25fe8a38: pva_fw: Setup DMA to also support memcpy
4f9d9f79: fw: Fix basic MISRA defects
62393350: umd tests: add perf test
ae2fbfa3: libs: Fix mul overflow CCM violation
0cbfa44f: Update VPU apps
e86a22ee: Fix Vpu error tests
435a16ea: ci: Modify Interface Test filter
1953f2d7: Port the following tests
90ac41ef: Implement synchronous memory unregistration
e29aaead: kmd: Fix DVMS CCM violations
7a46bc75: kmd: Fix hwseq validate CCM violation
3d8691cf: libs: Fix CCM violation in muls64 helper
98ca3972: kmd: Fix shared buffer CCM violation
4ba27920: kmd: Fix devctl CCM violations
640a7d58: perf: Fetch asl binaries for linux perf tests
4f25e30d: pva_fw: Add fast dma setup for transfers
3a73eb6c: kmd: Fix CCM violation in kmd context
72de95cf: kmd: Fix CCM violations in qnx_main and silicon exec
200a0fe6: ci: Remove checkGitlabJob.py
8bd635ce: coverity: Upgrade versions of Coverity and MISRA config
9c44087f: fw: Isolate VPU HW state reading retries
bee65065: kmd: Log error at the correct level
a5e9570a: deploy: Consider forked branch for commit message
91f1ceb4: tests: Fix VPU OCD expected value
7742f0ae: Add testing support for qnx nsr thor in CI/CD.
0ec69957: umd: Fix basic MISRA defects
beac9313: pva: update _PULSE_CODE_COIDDEATH handling
46192073: doip test: Add test to r/w to CSITE reg
accb2184: kmd: Fix dma_cfg_validate CCM violations
6da720c1: kmd: Fix misc CCM violations
e73779dc: Integrate PVA QNX KMD with DVMS Framework
4556b3f3: kmd: Fix op handler CCM violation
59da12ec: kmd: Fix CCM violation in DMA binding
3404ab99: pva_kmd: Fix a double free static defect
f99ff7c0: umd: Fix CCM Violations in queue_create and cuextend impl
d41fe841: pva_fw: Fixed unsigned type mismatch issues
dbc71f66: Port the following pva_intf_test to pva_umd_tests
b871295e: Change FAILED to failed
fe5c0ec3: ci: Unload default KMD driver on launch
0744de61: Skip duplicated memset in pva_fw_init_cmd_runner
c482932e: Update UMD export file
7f68160f: Fix parallel_scheduling_test_SingleProcessOnly
a869d997: Add VPU return code to context error struct
65108714: fw: Fix macro based type mismatch
3c28728e: Update tests affected by context error
fa208034: Add string representation of context error
71c91d38: umd: Fix nvsci import CCM Violations
6b7c1c05: Remove foreign syncpoint wait support
e512f5d4: Remove qnx/src path from deployment
63cce5ea: cursor: Update prebuilt image path
c14e51d5: docs: Add docs for async error handling
f90d047b: Implement asynchronous error report
5e9eb1f0: umd: Fix Data Channel CCM violation
1cdb79ed: umd: Fix CCM violations in NvSci export and image functions
87592b3f: ci: remove tcu_muxer support
fbf18cdb: DOIP: Fix overflow in Linux
b075f8cf: umd: Fix CCM violation in pva_context_create
a68a617a: Increase timeout value to handle big queues
fb356df3: KMD: Add support for DOIP in QNX
d560be9a: ci: support to track pva solutions algo perf
52111da4: umd: Fix CCM violation in cuextend_validate_memory_unregister
2f05b223: umd: Fix CCM violations in CUExtend memory register functions
c4803585: coverage: add umd code coverage support
3ed84a70: coverity: support safety build for qnx and baremetal
61cbe299: pva: fix static defects
5d07da65: Remove unused fields in UMD context
9f5a2654: Add foreign syncpoint waiter
4e388d3b: Remove limit on concurrent syncpoint wait
ab7e9bc8: nsight: update fence tracepoint
109a7368: nsight: Disable nsight support in safety builds
c9a66b30: nsight: fix engine reservation tracing
13024df9: nsight: clean-up and rename several fields
20cb20cb: nsight: Support redesigned tracepoints on QNX
ab55d48a: nsight: redesign tracepoints for V3 stack
7d6c1630: ci: install xxd tool for build env

Forked changes (dropped):

b2843456: pva: fix static defects
11700626: Revert "Remove WAR of skipping symbol type check"
121b314d: Revert "native: Add symbol type check for native"
b389a5fe: Revert "deploy: Update NvSCI path in tegra tree"
d240f306: Update pva_umd_host_misc.c license
78929b03: Revert "deploy: update nvidia-oot path"
7012c123: Remove unused fields in UMD context
4b7d4634: Add foreign syncpoint waiter
fdb28e8e: Remove limit on concurrent syncpoint wait
Change-Id: I5610d6936207a780668a391f4f7fea0a4cd685dd
Signed-off-by: nanwa <nanwa@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3508228
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
nanwa
2025-12-09 22:45:32 +00:00
committed by mobile promotions
parent 005042f3eb
commit 058eca0e23
133 changed files with 2828170 additions and 3221 deletions

View File

@@ -27,11 +27,15 @@ pva_objs += \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_dma_cfg_binding.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_dma_cfg_binding.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_dma_cfg_validate.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_dma_cfg_validate.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_dma_cfg_write.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_dma_cfg_write.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_fw_debug.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_fw_debug_printf.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_fw_profiler.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_fw_tracepoints.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_hwseq_validate.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_hwseq_validate.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_msg.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_msg.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_op_handler.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_op_handler.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_pfsd.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_pfsd_data.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_pfsd_t23x_dma_cfg.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_pfsd_t26x_dma_cfg.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_pm.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_pm.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_queue.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_queue.o \
$(PVA_SYS_DIR)/src/kmd/common/pva_kmd_resource_table.o \ $(PVA_SYS_DIR)/src/kmd/common/pva_kmd_resource_table.o \
@@ -82,12 +86,22 @@ pva_def_flags += \
-DPVA_BUILD_MODE_SIM=4 \ -DPVA_BUILD_MODE_SIM=4 \
-DPVA_DEV_MAIN_COMPATIBLE=1 \ -DPVA_DEV_MAIN_COMPATIBLE=1 \
-DPVA_ENABLE_CUDA=1 \ -DPVA_ENABLE_CUDA=1 \
-DPVA_ENABLE_DEBUG_ASSERT=0 \
-DPVA_ENABLE_DEBUG_PRINTS=0 \
-DPVA_ENABLE_FW_PROFILING=0 \
-DPVA_ENABLE_FW_TRACEPOINTS=1 \
-DPVA_ENABLE_GOLDEN_REGISTER_CHECKS=1 \
-DPVA_ENABLE_HWPM=1 \
-DPVA_ENABLE_NSYS_PROFILING=1 \ -DPVA_ENABLE_NSYS_PROFILING=1 \
-DPVA_ENABLE_R5_OCD=0 \ -DPVA_ENABLE_R5_OCD=0 \
-DPVA_IS_DEBUG=0 \ -DPVA_ENABLE_TEGRASTATS=1 \
-DPVA_ENABLE_VPU_OCD=1 \
-DPVA_ENABLE_VPU_PRINTFS=1 \
-DPVA_ERR_INJECT=0 \
-DPVA_SAFETY=0 \ -DPVA_SAFETY=0 \
-DPVA_SKIP_SYMBOL_TYPE_CHECK \
-DPVA_SUPPORT_XBAR_RAW=1 \ -DPVA_SUPPORT_XBAR_RAW=1 \
-DPVA_VCAST=0 \
-DSYSTEM_TESTS_ENABLED=1 \
-Dpva_kmd_linux_dummy_EXPORTS \ -Dpva_kmd_linux_dummy_EXPORTS \
###### End generated section ###### ###### End generated section ######

View File

@@ -14,6 +14,7 @@
#define PVA_CMD_PRIV_OPCODE_FLAG (1U << 7U) #define PVA_CMD_PRIV_OPCODE_FLAG (1U << 7U)
#define PVA_RESOURCE_ID_BASE 1U #define PVA_RESOURCE_ID_BASE 1U
struct pva_resource_entry { struct pva_resource_entry {
uint8_t access_flags : 2; // 1: RO, 2: WO, 3: RW uint8_t access_flags : 2; // 1: RO, 2: WO, 3: RW
uint8_t reserved : 4; uint8_t reserved : 4;
@@ -42,9 +43,11 @@ struct pva_cmd_init_resource_table {
* 1-7 are users'. */ * 1-7 are users'. */
uint8_t resource_table_id; uint8_t resource_table_id;
uint8_t resource_table_addr_hi; uint8_t resource_table_addr_hi;
uint8_t pad[2]; uint8_t ctx_status_addr_hi;
uint8_t pad[1];
uint32_t resource_table_addr_lo; uint32_t resource_table_addr_lo;
uint32_t max_n_entries; uint32_t max_n_entries;
uint32_t ctx_status_addr_lo;
}; };
struct pva_cmd_deinit_resource_table { struct pva_cmd_deinit_resource_table {
@@ -156,7 +159,13 @@ struct pva_cmd_get_version {
uint32_t buffer_iova_lo; uint32_t buffer_iova_lo;
}; };
#define PVA_CMD_PRIV_OPCODE_COUNT 15U struct pva_cmd_set_pfsd_cmd_buffer_size {
#define PVA_CMD_OPCODE_SET_PFSD_CMD_BUFFER_SIZE (15U | PVA_CMD_PRIV_OPCODE_FLAG)
struct pva_cmd_header header;
uint32_t cmd_buffer_size;
};
#define PVA_CMD_PRIV_OPCODE_COUNT 16U
struct pva_fw_prefence { struct pva_fw_prefence {
uint8_t offset_hi; uint8_t offset_hi;
@@ -172,7 +181,7 @@ struct pva_fw_postfence {
/** Privileged user queue may need to trigger fence that exists in user's own /** Privileged user queue may need to trigger fence that exists in user's own
* resource table. Set this flags to tell FW to use user's resource table when * resource table. Set this flags to tell FW to use user's resource table when
* writing this post fence. This also applies to timestamp resource ID. */ * writing this post fence. This also applies to timestamp resource ID. */
#define PVA_FW_POSTFENCE_FLAGS_USER_FENCE (1 << 0) #define PVA_FW_POSTFENCE_FLAGS_USER_FENCE (1U << 0U)
uint8_t flags; uint8_t flags;
uint8_t pad0; uint8_t pad0;
uint32_t offset_lo; uint32_t offset_lo;
@@ -306,42 +315,42 @@ static inline uint32_t pva_fw_queue_space(uint32_t head, uint32_t tail,
* msg[4] = STATUS6 * msg[4] = STATUS6
* msg[5] = STATUS7 * msg[5] = STATUS7
*/ */
#define PVA_FW_MSG_STATUS_BASE 3 #define PVA_FW_MSG_STATUS_BASE 3U
#define PVA_FW_MSG_STATUS_LAST 8 #define PVA_FW_MSG_STATUS_LAST 8U
#define PVA_FW_MSG_TYPE_MSB 30 #define PVA_FW_MSG_TYPE_MSB 30U
#define PVA_FW_MSG_TYPE_LSB 25 #define PVA_FW_MSG_TYPE_LSB 25U
#define PVA_FW_MSG_LEN_MSB 24 #define PVA_FW_MSG_LEN_MSB 24U
#define PVA_FW_MSG_LEN_LSB 22 #define PVA_FW_MSG_LEN_LSB 22U
/* The remaining bits (0 - 21) of msg[0] can be used for message specific /* The remaining bits (0 - 21) of msg[0] can be used for message specific
* payload */ * payload */
/* Message types: R5 -> CCPLEX */ /* Message types: R5 -> CCPLEX */
#define PVA_FW_MSG_TYPE_ABORT 1 #define PVA_FW_MSG_TYPE_ABORT 1U
#define PVA_FW_MSG_TYPE_BOOT_DONE 2 #define PVA_FW_MSG_TYPE_BOOT_DONE 2U
#define PVA_FW_MSG_TYPE_FLUSH_PRINT 3 #define PVA_FW_MSG_TYPE_FLUSH_PRINT 3U
#define PVA_FW_MSG_TYPE_RESOURCE_UNREGISTER 3 #define PVA_FW_MSG_TYPE_FAST_RESET_FAILURE 4U
/* Message types: CCPLEX -> R5 */ /* Message types: CCPLEX -> R5 */
#define PVA_FW_MSG_TYPE_UPDATE_TAIL 32 #define PVA_FW_MSG_TYPE_UPDATE_TAIL 32U
/* Parameters for message ABORT /* Parameters for message ABORT
* ABORT message contains a short string (up to 22 chars). * ABORT message contains a short string (up to 22 chars).
* The first two charactors are in the message header (bit 15 - 0). * The first two charactors are in the message header (bit 15 - 0).
*/ */
#define PVA_FW_MSG_ABORT_STR_MAX_LEN 22 #define PVA_FW_MSG_ABORT_STR_MAX_LEN 22U
/* Parameters for message BOOT_DONE */ /* Parameters for message BOOT_DONE */
#define PVA_FW_MSG_R5_START_TIME_LO_IDX 1 #define PVA_FW_MSG_R5_START_TIME_LO_IDX 1U
#define PVA_FW_MSG_R5_START_TIME_HI_IDX 2 #define PVA_FW_MSG_R5_START_TIME_HI_IDX 2U
#define PVA_FW_MSG_R5_READY_TIME_LO_IDX 3 #define PVA_FW_MSG_R5_READY_TIME_LO_IDX 3U
#define PVA_FW_MSG_R5_READY_TIME_HI_IDX 4 #define PVA_FW_MSG_R5_READY_TIME_HI_IDX 4U
#define PVA_MAX_DEBUG_LOG_MSG_CHARACTERS 100 #define PVA_MAX_DEBUG_LOG_MSG_CHARACTERS 100U
/* Parameters for message FLUSH PRINT */ /* Parameters for message FLUSH PRINT */
struct pva_fw_print_buffer_header { struct pva_fw_print_buffer_header {
#define PVA_FW_PRINT_BUFFER_OVERFLOWED (1 << 0) #define PVA_FW_PRINT_BUFFER_OVERFLOWED (1U << 0U)
#define PVA_FW_PRINT_FAILURE (1 << 1) #define PVA_FW_PRINT_FAILURE (1U << 1U)
uint32_t flags; uint32_t flags;
uint32_t head; uint32_t head;
uint32_t tail; uint32_t tail;
@@ -351,8 +360,8 @@ struct pva_fw_print_buffer_header {
/* Parameters for message resource unregister */ /* Parameters for message resource unregister */
/* Table ID is stored in msg[0], bit: 0 - 7 */ /* Table ID is stored in msg[0], bit: 0 - 7 */
#define PVA_FW_MSG_RESOURCE_TABLE_ID_MSB 7 #define PVA_FW_MSG_RESOURCE_TABLE_ID_MSB 7U
#define PVA_FW_MSG_RESOURCE_TABLE_ID_LSB 0 #define PVA_FW_MSG_RESOURCE_TABLE_ID_LSB 0U
/* Followed by up to 5 resource IDs. The actual number of resource ID is /* Followed by up to 5 resource IDs. The actual number of resource ID is
* indicated by the message length. */ * indicated by the message length. */
@@ -388,35 +397,45 @@ struct pva_fw_event_message {
// Each event is one of the following types. This should fit within 3 bits // Each event is one of the following types. This should fit within 3 bits
enum pva_fw_events_type { enum pva_fw_events_type {
EVENT_TRY = 0U, PVA_EVENT_CMD_ATTEMPTING = 0U,
EVENT_START, PVA_EVENT_CMD_STARTED,
EVENT_YIELD, PVA_EVENT_CMD_YIELDED,
EVENT_DONE, PVA_EVENT_CMD_COMPLETED,
EVENT_ERROR, PVA_EVENT_CMD_FAILED,
EVENT_TYPE_MAX = 7U PVA_EVENT_TYPE_MAX = 7U
}; };
static inline const char *event_type_to_string(enum pva_fw_events_type status) static inline const char *event_type_to_string(enum pva_fw_events_type status)
{ {
const char *result = "";
switch (status) { switch (status) {
case EVENT_TRY: case PVA_EVENT_CMD_ATTEMPTING:
return "TRY"; result = "TRY";
case EVENT_START: break;
return "START"; case PVA_EVENT_CMD_STARTED:
case EVENT_YIELD: result = "START";
return "YIELD"; break;
case EVENT_DONE: case PVA_EVENT_CMD_YIELDED:
return "DONE"; result = "YIELD";
case EVENT_ERROR: break;
return "ERROR"; case PVA_EVENT_CMD_COMPLETED:
result = "DONE";
break;
case PVA_EVENT_CMD_FAILED:
result = "ERROR";
break;
default: default:
return ""; result = "";
break;
} }
return result;
} }
enum pva_fw_timestamp_t { enum pva_fw_timestamp_t {
TIMESTAMP_TYPE_TSE = 0, TIMESTAMP_TYPE_TSE = 0U,
TIMESTAMP_TYPE_CYCLE_COUNT = 1 TIMESTAMP_TYPE_CYCLE_COUNT = 1U
}; };
/* End of PVA FW Event profiling definitions */ /* End of PVA FW Event profiling definitions */
@@ -436,8 +455,8 @@ enum pva_fw_timestamp_t {
// buffer size properties as KMD might use this for validation of buffer accesses. // buffer size properties as KMD might use this for validation of buffer accesses.
// If FW somehow corrupts 'size', KMD might end up accessing out of bounds. // If FW somehow corrupts 'size', KMD might end up accessing out of bounds.
struct pva_fw_shared_buffer_header { struct pva_fw_shared_buffer_header {
#define PVA_KMD_FW_BUF_FLAG_OVERFLOW (1 << 0) #define PVA_KMD_FW_BUF_FLAG_OVERFLOW (1U << 0U)
#define PVA_KMD_FW_BUF_FLAG_ERROR (1 << 1) #define PVA_KMD_FW_BUF_FLAG_ERROR (1U << 1U)
uint32_t flags; uint32_t flags;
uint32_t element_size; uint32_t element_size;
uint32_t head; uint32_t head;
@@ -445,13 +464,13 @@ struct pva_fw_shared_buffer_header {
}; };
struct pva_kmd_fw_buffer_msg_header { struct pva_kmd_fw_buffer_msg_header {
#define PVA_KMD_FW_BUF_MSG_TYPE_FW_EVENT 0 #define PVA_KMD_FW_BUF_MSG_TYPE_FW_EVENT 0U
#define PVA_KMD_FW_BUF_MSG_TYPE_CMD_BUF_TRACE 1 #define PVA_KMD_FW_BUF_MSG_TYPE_CMD_BUF_TRACE 1U
#define PVA_KMD_FW_BUF_MSG_TYPE_VPU_TRACE 2 #define PVA_KMD_FW_BUF_MSG_TYPE_VPU_TRACE 2U
#define PVA_KMD_FW_BUF_MSG_TYPE_FENCE_TRACE 3 #define PVA_KMD_FW_BUF_MSG_TYPE_FENCE_TRACE 3U
#define PVA_KMD_FW_BUF_MSG_TYPE_ENGINE_ACQUIRE_TRACE 4 #define PVA_KMD_FW_BUF_MSG_TYPE_ENGINE_ACQUIRE_TRACE 4U
#define PVA_KMD_FW_BUF_MSG_TYPE_RES_UNREG 5 #define PVA_KMD_FW_BUF_MSG_TYPE_RES_UNREG 5U
#define PVA_KMD_FW_BUF_MSG_TYPE_FW_TRACEPOINT 6 #define PVA_KMD_FW_BUF_MSG_TYPE_FW_TRACEPOINT 6U
uint32_t type : 8; uint32_t type : 8;
// Size of payload in bytes. Includes the size of the header. // Size of payload in bytes. Includes the size of the header.
uint32_t size : 24; uint32_t size : 24;
@@ -523,10 +542,10 @@ struct pva_kmd_fw_tegrastats {
uint64_t total_utilization[PVA_NUM_PVE]; uint64_t total_utilization[PVA_NUM_PVE];
}; };
#define PVA_MAX_CMDBUF_CHUNK_LEN 1024 #define PVA_MAX_CMDBUF_CHUNK_LEN 1024U
#define PVA_MAX_CMDBUF_CHUNK_SIZE (sizeof(uint32_t) * PVA_MAX_CMDBUF_CHUNK_LEN) #define PVA_MAX_CMDBUF_CHUNK_SIZE (sizeof(uint32_t) * PVA_MAX_CMDBUF_CHUNK_LEN)
#define PVA_TEST_MODE_MAX_CMDBUF_CHUNK_LEN 256 #define PVA_TEST_MODE_MAX_CMDBUF_CHUNK_LEN 256U
#define PVA_TEST_MODE_MAX_CMDBUF_CHUNK_SIZE \ #define PVA_TEST_MODE_MAX_CMDBUF_CHUNK_SIZE \
(sizeof(uint32_t) * PVA_TEST_MODE_MAX_CMDBUF_CHUNK_LEN) (sizeof(uint32_t) * PVA_TEST_MODE_MAX_CMDBUF_CHUNK_LEN)
@@ -563,60 +582,89 @@ struct pva_fw_tracepoint {
static inline const char *pva_fw_tracepoint_type_to_string(uint32_t type) static inline const char *pva_fw_tracepoint_type_to_string(uint32_t type)
{ {
const char *result = "UNKNOWN";
switch (type) { switch (type) {
case PVA_FW_TP_LVL_NONE: case PVA_FW_TP_LVL_NONE:
return "NONE"; result = "NONE";
break;
case PVA_FW_TP_LVL_CMD_BUF: case PVA_FW_TP_LVL_CMD_BUF:
return "CMD_BUF"; result = "CMD_BUF";
break;
case PVA_FW_TP_LVL_VPU: case PVA_FW_TP_LVL_VPU:
return "VPU"; result = "VPU";
break;
case PVA_FW_TP_LVL_DMA: case PVA_FW_TP_LVL_DMA:
return "DMA"; result = "DMA";
break;
case PVA_FW_TP_LVL_L2SRAM: case PVA_FW_TP_LVL_L2SRAM:
return "L2SRAM"; result = "L2SRAM";
break;
case PVA_FW_TP_LVL_PPE: case PVA_FW_TP_LVL_PPE:
return "PPE"; result = "PPE";
break;
default: default:
return "UNKNOWN"; result = "UNKNOWN";
break;
} }
return result;
} }
static inline const char *pva_fw_tracepoint_flags_to_string(uint32_t flags) static inline const char *pva_fw_tracepoint_flags_to_string(uint32_t flags)
{ {
const char *result = "UNKNOWN";
switch (flags) { switch (flags) {
case PVA_FW_TP_FLAG_NONE: case PVA_FW_TP_FLAG_NONE:
return "NONE"; result = "NONE";
break;
case PVA_FW_TP_FLAG_START: case PVA_FW_TP_FLAG_START:
return "START"; result = "START";
break;
case PVA_FW_TP_FLAG_END: case PVA_FW_TP_FLAG_END:
return "END"; result = "END";
break;
case PVA_FW_TP_FLAG_ERROR: case PVA_FW_TP_FLAG_ERROR:
return "ERROR"; result = "ERROR";
break;
default: default:
return "UNKNOWN"; result = "UNKNOWN";
break;
} }
return result;
} }
static inline const char *pva_fw_tracepoint_slot_id_to_string(uint32_t slot_id) static inline const char *pva_fw_tracepoint_slot_id_to_string(uint32_t slot_id)
{ {
const char *result = "UNKNOWN";
switch (slot_id) { switch (slot_id) {
case 0: case 0:
return "PRIV_SLOT"; result = "PRIV_SLOT";
break;
case 1: case 1:
return "USER_SLOT_1"; result = "USER_SLOT_1";
break;
case 2: case 2:
return "USER_SLOT_2"; result = "USER_SLOT_2";
break;
case 3: case 3:
return "USER_PRIV_SLOT"; result = "USER_PRIV_SLOT";
break;
default: default:
return "UNKNOWN"; result = "UNKNOWN";
break;
} }
return result;
} }
#define PVA_R5_OCD_TYPE_MMIO_READ 1 #define PVA_R5_OCD_TYPE_MMIO_READ 1U
#define PVA_R5_OCD_TYPE_MMIO_WRITE 2 #define PVA_R5_OCD_TYPE_MMIO_WRITE 2U
#define PVA_R5_OCD_TYPE_REG_READ 3 #define PVA_R5_OCD_TYPE_REG_READ 3U
#define PVA_R5_OCD_TYPE_REG_WRITE 4 #define PVA_R5_OCD_TYPE_REG_WRITE 4U
#define PVA_R5_OCD_MAX_DATA_SIZE FW_TRACE_BUFFER_SIZE #define PVA_R5_OCD_MAX_DATA_SIZE FW_TRACE_BUFFER_SIZE
@@ -627,4 +675,11 @@ struct pva_r5_ocd_request {
//followed by data if any //followed by data if any
}; };
#define PVA_FW_ASYNC_ERROR_STR_MAX_LEN (1024 * 3)
struct pva_fw_async_error {
struct pva_async_error error_info;
uint32_t failure_reason_str_len;
char failure_reason[PVA_FW_ASYNC_ERROR_STR_MAX_LEN];
};
#endif // PVA_FW_H #endif // PVA_FW_H

View File

@@ -30,36 +30,36 @@
/** /**
* @brief R5 address of reset exception vector * @brief R5 address of reset exception vector
*/ */
#define EVP_RESET_VECTOR 0x60040C00 #define PVA_EVP_RESET_VECTOR 0x60040C00
/** /**
* @brief R5 address of undefined instruction exception vector * @brief R5 address of undefined instruction exception vector
*/ */
#define EVP_UNDEFINED_INSTRUCTION_VECTOR (EVP_RESET_VECTOR + 0x400 * 1) #define PVA_EVP_UNDEFINED_INSTRUCTION_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 1)
/** /**
* @brief R5 address of svc exception vector * @brief R5 address of svc exception vector
*/ */
#define EVP_SVC_VECTOR (EVP_RESET_VECTOR + 0x400 * 2) #define PVA_EVP_SVC_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 2)
/** /**
* @brief R5 address of prefetch abort exception vector * @brief R5 address of prefetch abort exception vector
*/ */
#define EVP_PREFETCH_ABORT_VECTOR (EVP_RESET_VECTOR + 0x400 * 3) #define PVA_EVP_PREFETCH_ABORT_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 3)
/** /**
* @brief R5 address of data abort exception vector * @brief R5 address of data abort exception vector
*/ */
#define EVP_DATA_ABORT_VECTOR (EVP_RESET_VECTOR + 0x400 * 4) #define PVA_EVP_DATA_ABORT_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 4)
/** /**
* @brief R5 address of reserved exception vector. * @brief R5 address of reserved exception vector.
* It points to a dummy handler. * It points to a dummy handler.
*/ */
#define EVP_RESERVED_VECTOR (EVP_RESET_VECTOR + 0x400 * 5) #define PVA_EVP_RESERVED_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 5)
/** /**
* @brief R5 address of IRQ exception vector * @brief R5 address of IRQ exception vector
*/ */
#define EVP_IRQ_VECTOR (EVP_RESET_VECTOR + 0x400 * 6) #define PVA_EVP_IRQ_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 6)
/** /**
* @brief R5 address of FIQ exception vector * @brief R5 address of FIQ exception vector
*/ */
#define EVP_FIQ_VECTOR (EVP_RESET_VECTOR + 0x400 * 7) #define PVA_EVP_FIQ_VECTOR (PVA_EVP_RESET_VECTOR + 0x400 * 7)
/** @} */ /** @} */
/** /**
@@ -129,23 +129,23 @@
/** /**
* @brief EVP SCR firewall to enable only CCPLEX read/write access. * @brief EVP SCR firewall to enable only CCPLEX read/write access.
*/ */
#define PVA_EVP_SCR_VAL 0x19000202 #define PVA_EVP_SCR_VAL 0x19000202U
/** /**
* @brief PRIV SCR firewall to enable only CCPLEX and R5 read/write access. * @brief PRIV SCR firewall to enable only CCPLEX and R5 read/write access.
*/ */
#define PVA_PRIV_SCR_VAL 0x1F008282 #define PVA_PRIV_SCR_VAL 0x1F008282U
/** /**
* @brief CCQ SCR firewall to enable only CCPLEX write access and R5 read access. * @brief CCQ SCR firewall to enable only CCPLEX write access and R5 read access.
*/ */
#define PVA_CCQ_SCR_VAL 0x19000280 #define PVA_CCQ_SCR_VAL 0x19000280U
/** /**
* @brief Status Ctl SCR firewall to enable only CCPLEX read access and R5 read/write access. * @brief Status Ctl SCR firewall to enable only CCPLEX read access and R5 read/write access.
*/ */
#define PVA_STATUS_CTL_SCR_VAL 0x1f008082 #define PVA_STATUS_CTL_SCR_VAL 0x1f008082U
#define PVA_STATUS_CTL_SCR_VAL_SIM 0x1f008282 #define PVA_STATUS_CTL_SCR_VAL_SIM 0x1f008282U
/** @} */ /** @} */
/** /**

View File

@@ -105,8 +105,8 @@
* msg[0] = mailbox 1 -> generate interrupt to R5 * msg[0] = mailbox 1 -> generate interrupt to R5
* msg[1] = mailbox 0 * msg[1] = mailbox 0
*/ */
#define PVA_FW_MBOX_TO_R5_BASE 0 #define PVA_FW_MBOX_TO_R5_BASE 0U
#define PVA_FW_MBOX_TO_R5_LAST 1 #define PVA_FW_MBOX_TO_R5_LAST 1U
/* When R5 send messages to hypervisor through mailboxes, we use mailbox 2 - 7 /* When R5 send messages to hypervisor through mailboxes, we use mailbox 2 - 7
* msg[0] = mailbox 7 -> generate interrupt to hypervisor * msg[0] = mailbox 7 -> generate interrupt to hypervisor
@@ -116,8 +116,8 @@
* msg[4] = mailbox 5 * msg[4] = mailbox 5
* msg[5] = mailbox 6 * msg[5] = mailbox 6
*/ */
#define PVA_FW_MBOX_TO_HYP_BASE 2 #define PVA_FW_MBOX_TO_HYP_BASE 2U
#define PVA_FW_MBOX_TO_HYP_LAST 7 #define PVA_FW_MBOX_TO_HYP_LAST 7U
#define PVA_FW_MBOX_FULL_BIT PVA_BIT(31) #define PVA_FW_MBOX_FULL_BIT PVA_BIT(31)

View File

@@ -88,7 +88,8 @@ static inline uint32_t get_slot_size(struct pva_fw_dma_slot const *slot)
return size; return size;
} }
tmp_size = slot->end_addr - slot->start_addr; tmp_size = slot->end_addr - slot->start_addr;
if (tmp_size > (int64_t)UINT32_MAX) { /* Check for both negative (overflow) and too large values */
if ((tmp_size < 0) || (tmp_size > (int64_t)UINT32_MAX)) {
return size; return size;
} }
size = (uint32_t)tmp_size; size = (uint32_t)tmp_size;
@@ -198,7 +199,7 @@ pva_dma_resource_map_add_triggers(struct pva_dma_resource_map *map)
// If an application is running on VPU, it has access to all the triggers // If an application is running on VPU, it has access to all the triggers
// Only FW and DMA-only workloads can initiate transfers in parallel to // Only FW and DMA-only workloads can initiate transfers in parallel to
// a running VPU application, but they do not require triggers. // a running VPU application, but they do not require triggers.
map->triggers |= 1; map->triggers |= 1U;
} }
static inline void static inline void
@@ -299,36 +300,38 @@ static inline struct pva_fw_dma_slot *
pva_dma_config_get_slots(struct pva_dma_config_resource *dma_config) pva_dma_config_get_slots(struct pva_dma_config_resource *dma_config)
{ {
return (struct pva_fw_dma_slot return (struct pva_fw_dma_slot
*)((uint8_t *)dma_config + *)(uintptr_t)((uint8_t *)dma_config +
sizeof(struct pva_dma_config_resource)); sizeof(struct pva_dma_config_resource));
} }
static inline struct pva_fw_dma_reloc * static inline struct pva_fw_dma_reloc *
pva_dma_config_get_relocs(struct pva_dma_config_resource *dma_config) pva_dma_config_get_relocs(struct pva_dma_config_resource *dma_config)
{ {
return (struct pva_fw_dma_reloc return (struct pva_fw_dma_reloc
*)((uint8_t *)pva_dma_config_get_slots(dma_config) + *)(uintptr_t)((uint8_t *)pva_dma_config_get_slots(
sizeof(struct pva_fw_dma_slot) * dma_config) +
dma_config->num_dynamic_slots); sizeof(struct pva_fw_dma_slot) *
dma_config->num_dynamic_slots);
} }
static inline struct pva_fw_dma_channel * static inline struct pva_fw_dma_channel *
pva_dma_config_get_channels(struct pva_dma_config_resource *dma_config) pva_dma_config_get_channels(struct pva_dma_config_resource *dma_config)
{ {
return (struct pva_fw_dma_channel *)((uint8_t *) return (struct pva_fw_dma_channel
pva_dma_config_get_relocs( *)(uintptr_t)((uint8_t *)pva_dma_config_get_relocs(
dma_config) + dma_config) +
sizeof(struct pva_fw_dma_reloc) * sizeof(struct pva_fw_dma_reloc) *
dma_config->num_relocs); dma_config->num_relocs);
} }
static inline struct pva_fw_dma_descriptor * static inline struct pva_fw_dma_descriptor *
pva_dma_config_get_descriptors(struct pva_dma_config_resource *dma_config) pva_dma_config_get_descriptors(struct pva_dma_config_resource *dma_config)
{ {
return (struct pva_fw_dma_descriptor return (struct pva_fw_dma_descriptor
*)((uint8_t *)pva_dma_config_get_channels(dma_config) + *)(uintptr_t)((uint8_t *)pva_dma_config_get_channels(
sizeof(struct pva_fw_dma_channel) * dma_config) +
dma_config->num_channels); sizeof(struct pva_fw_dma_channel) *
dma_config->num_channels);
} }
#endif // PVA_RESOURCE_H #endif // PVA_RESOURCE_H

View File

@@ -105,15 +105,17 @@ enum pva_error pva_memory_cpu_unmap(struct pva_memory *mem, void *va);
void pva_memory_free(struct pva_memory *mem); void pva_memory_free(struct pva_memory *mem);
/** /**
* @brief Wait for a syncpoint to reach a value. * @brief Wait for a PVA-owned syncpoint to reach a value.
*
* This function does not work for imported syncpoints.
* *
* @param[in] ctx Pointer to the context. * @param[in] ctx Pointer to the context.
* @param[in] syncpiont_id Syncpoint ID to wait on. * @param[in] syncpoint_id Syncpoint ID to wait on.
* @param[in] value Value to wait for. * @param[in] value Value to wait for.
* @param[in] timeout_us Timeout in microseconds. PVA_SUBMIT_TIMEOUT_INF for infinite. * @param[in] timeout_us Timeout in microseconds. PVA_SUBMIT_TIMEOUT_INF for infinite.
*/ */
enum pva_error pva_syncpoint_wait(struct pva_context *ctx, enum pva_error pva_syncpoint_wait(struct pva_context *ctx,
uint32_t syncpiont_id, uint32_t value, uint32_t syncpoint_id, uint32_t value,
uint64_t timeout_us); uint64_t timeout_us);
/** /**
@@ -213,11 +215,70 @@ enum pva_error pva_memory_import_id_create(struct pva_context *ctx,
*/ */
enum pva_error pva_memory_import_id_destroy(uint64_t import_id); enum pva_error pva_memory_import_id_destroy(uint64_t import_id);
/**
* @brief Get the asynchronous error for a context.
*
* Note that other fields are valid only if out_error->error is not PVA_SUCCESS.
*
* @param[in] ctx Pointer to the context.
* @param[out] out_error Pointer to the asynchronous error.
* @param[out] out_failure_reason Pointer to a null-terminated string describing the failure reason.
*/
enum pva_error pva_get_async_error(struct pva_context *ctx,
struct pva_async_error *out_error,
const char **out_failure_reason);
/**
* @brief Query runtime policy for API usage restrictions.
*
* Returns the current policy for which categories of the public PVA API are
* permitted. Implementations may consult an underlying system-state facility to
* determine whether certain API categories (for example, initialization flows)
* should be restricted in the current state. If such a facility exists, the
* implementation sets api_restrictions accordingly. If no facility exists
* or it is unsupported, the implementation returns @ref PVA_API_ALL_ALLOWED.
*
* @param[out] api_restrictions Pointer that receives the API restriction flags.
* On success, set to one of: PVA_API_ALL_ALLOWED
* or PVA_API_INIT_NOT_ALLOWED.
* @return enum pva_error
* - PVA_SUCCESS: Query succeeded and @p api_restrictions is valid
* - PVA_ERR_DVMS_GET_VM_STATE_FAILED: Underlying state facility query
* failed (when such a facility is used by the implementation)
* - PVA_INTERNAL: Internal error when hardware version is not supported
*/
enum pva_error pva_get_api_restrictions(uint32_t *api_restrictions);
/**
* @brief Get the number of PFSD tests supported by PVA system SW.
*
* PFSD is not supported on T19x and Linux platforms; in these cases, the function
* will indicate that PFSD is not supported by returning zero.
* On other supported platforms, it will return the number of PFSD tests supported.
*
* @param[in] ctx Pointer to the PVA context.
* @param[out] pfsd_test_count Pointer to uint32_t to receive the test count.
* @return enum pva_error Error status.
*/
enum pva_error pva_get_pfsd_test_count(struct pva_context *ctx,
uint32_t *test_count);
/**
* @brief Register a PFSD command buffer.
*
* @param[in] ctx Pointer to the PVA context.
* @param[in] test_id Test ID. From 0 to test_count - 1.
* @param[out] cmd_buffer_resource_id Command buffer resource ID.
* @return enum pva_error Error status.
*/
enum pva_error pva_get_pfsd_info(struct pva_context *ctx, uint32_t test_id,
uint32_t *cmd_buffer_resource_id);
/** \brief Specifies the PVA system software major version. */ /** \brief Specifies the PVA system software major version. */
#define PVA_SYSSW_MAJOR_VERSION (2U) #define PVA_SYSSW_MAJOR_VERSION (2U)
/** \brief Specifies the PVA system software minor version. */ /** \brief Specifies the PVA system software minor version. */
#define PVA_SYSSW_MINOR_VERSION (8U) #define PVA_SYSSW_MINOR_VERSION (9U)
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -52,7 +52,7 @@ struct pva_dma_misr {
}; };
struct pva_user_dma_allowance { struct pva_user_dma_allowance {
#define PVA_USER_DMA_ALLOWANCE_ADB_STEP_SIZE 8 #define PVA_USER_DMA_ALLOWANCE_ADB_STEP_SIZE (uint16_t)8
/*desc start index and descriptor count should be multiple of 4*/ /*desc start index and descriptor count should be multiple of 4*/
uint32_t channel_idx : 4; uint32_t channel_idx : 4;
uint32_t desc_start_idx : 7; uint32_t desc_start_idx : 7;
@@ -253,7 +253,7 @@ struct pva_cmd_set_vpu_parameter_with_address {
uint32_t dram_offset_lo; uint32_t dram_offset_lo;
}; };
#define PVA_MAX_DMA_SETS_PER_DMA_ENGINE 4 #define PVA_MAX_DMA_SETS_PER_DMA_ENGINE 4U
/** This command first acquires the TCM scratch and then fetches DMA configuration /** This command first acquires the TCM scratch and then fetches DMA configuration
* into the scratch. The command does not modify DMA * into the scratch. The command does not modify DMA

View File

@@ -82,19 +82,19 @@ struct pva_dma_transfer_attr {
/** When dynamic slot flag is set, it means the memory location will be /** When dynamic slot flag is set, it means the memory location will be
* relocated by commands. * relocated by commands.
*/ */
#define PVA_DMA_DYNAMIC_SLOT (1 << 15) #define PVA_DMA_DYNAMIC_SLOT ((uint16_t)1U << 15)
#define PVA_DMA_STATIC_SLOT (1 << 14) #define PVA_DMA_STATIC_SLOT ((uint16_t)1U << 14)
#define PVA_DMA_SLOT_INVALID 0 #define PVA_DMA_SLOT_INVALID 0
#define PVA_DMA_SLOT_ID_MASK 0xFF #define PVA_DMA_SLOT_ID_MASK 0xFFU
#define PVA_DMA_MAX_NUM_SLOTS 256 #define PVA_DMA_MAX_NUM_SLOTS 256
uint16_t slot; uint16_t slot;
/** Line pitch in pixels */ /** Line pitch in pixels */
uint16_t line_pitch; uint16_t line_pitch;
uint32_t cb_start; uint32_t cb_start;
uint32_t cb_size; uint32_t cb_size;
int32_t adv1; uint32_t adv1;
int32_t adv2; uint32_t adv2;
int32_t adv3; uint32_t adv3;
uint64_t offset; uint64_t offset;
}; };
@@ -225,7 +225,7 @@ enum pva_dma_static_binding_type {
}; };
/** Max block height is 32 GOB */ /** Max block height is 32 GOB */
#define PVA_DMA_MAX_LOG2_BLOCK_HEIGHT 5 #define PVA_DMA_MAX_LOG2_BLOCK_HEIGHT 5U
struct pva_dma_dram_binding { struct pva_dma_dram_binding {
/** enum pva_surface_format */ /** enum pva_surface_format */

View File

@@ -26,7 +26,7 @@ struct pva_ops_memory {
* until memory->size is reached. * until memory->size is reached.
*/ */
struct pva_ops_buffer { struct pva_ops_buffer {
struct pva_ops_memory *memory; /**< Pointer to buffer memory */ struct pva_ops_memory *mem_ptr; /**< Pointer to buffer memory */
uint64_t start_offset; /**< Start offset in buffer memory */ uint64_t start_offset; /**< Start offset in buffer memory */
uint64_t end_offset; /**< End offset (exclusive) in buffer memory */ uint64_t end_offset; /**< End offset (exclusive) in buffer memory */
}; };

View File

@@ -2,12 +2,18 @@
/* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ /* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_API_TYPES_H #ifndef PVA_API_TYPES_H
#define PVA_API_TYPES_H #define PVA_API_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(__KERNEL__) #if !defined(__KERNEL__)
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <string.h> #include <string.h>
/* Use offsetof to avoid INT36-C violation from NULL pointer arithmetic */
#define container_of(ptr, type, member) \ #define container_of(ptr, type, member) \
(type *)((char *)(ptr) - (char *)&((type *)0)->member) ((type *)((char *)(ptr)-offsetof(type, member)))
#else #else
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/types.h> #include <linux/types.h>
@@ -17,10 +23,6 @@
#define UINT32_MAX U32_MAX #define UINT32_MAX U32_MAX
#endif #endif
#ifndef NULL
#define NULL ((void *)0)
#endif
#define FOREACH_ERR(ACT) \ #define FOREACH_ERR(ACT) \
ACT(PVA_SUCCESS) \ ACT(PVA_SUCCESS) \
ACT(PVA_UNKNOWN_ERROR) \ ACT(PVA_UNKNOWN_ERROR) \
@@ -135,6 +137,11 @@
ACT(PVA_ERR_GOLDEN_REG_MISMATCH) \ ACT(PVA_ERR_GOLDEN_REG_MISMATCH) \
ACT(PVA_ERR_CRITICAL_REG_MISMATCH) \ ACT(PVA_ERR_CRITICAL_REG_MISMATCH) \
ACT(PVA_ERR_CONFIG_REG_MISMATCH) \ ACT(PVA_ERR_CONFIG_REG_MISMATCH) \
ACT(PVA_ERR_BAD_CONTEXT) \
ACT(PVA_ERR_BAD_DEVICE) \
ACT(PVA_ERR_FAST_RESET_FAILURE) \
ACT(PVA_ERR_DVMS_GET_VM_STATE_FAILED) \
ACT(PVA_ERR_INVALID_VPU_SYSCALL) \
ACT(PVA_ERR_CODE_COUNT) ACT(PVA_ERR_CODE_COUNT)
enum pva_error { enum pva_error {
@@ -156,6 +163,20 @@ enum pva_hw_gen {
PVA_HW_GEN3, PVA_HW_GEN3,
}; };
/**
* @brief API restriction flags reported by @ref pva_get_api_restrictions.
*
* These flags indicate which categories of the public API are permitted by the
* current platform/runtime policy. Implementations currently set exactly one
* of the flags below, but the type is defined as bit-flags for forward
* compatibility.
*/
/** No restrictions: all API categories are permitted. */
#define PVA_API_ALL_ALLOWED (0U)
/** Initialization-related APIs are not permitted in the current state.
* Callers must defer creation/initialization flows until allowed. */
#define PVA_API_INIT_NOT_ALLOWED (1U)
/* Opaque API data types */ /* Opaque API data types */
struct pva_context; struct pva_context;
struct pva_queue; struct pva_queue;
@@ -282,10 +303,10 @@ struct pva_symbol_info {
// unify timeout to uint64_t, in microseconds // unify timeout to uint64_t, in microseconds
#define PVA_SUBMIT_TIMEOUT_INF UINT64_MAX /**< Infinite timeout */ #define PVA_SUBMIT_TIMEOUT_INF UINT64_MAX /**< Infinite timeout */
#define PVA_MAX_NUM_INPUT_STATUS 2 /**< Maximum number of input statuses */ #define PVA_MAX_NUM_INPUT_STATUS 2U /**< Maximum number of input statuses */
#define PVA_MAX_NUM_OUTPUT_STATUS 2 /**< Maximum number of output statuses */ #define PVA_MAX_NUM_OUTPUT_STATUS 2U /**< Maximum number of output statuses */
#define PVA_MAX_NUM_PREFENCES 2 /**< Maximum number of pre-fences */ #define PVA_MAX_NUM_PREFENCES 2U /**< Maximum number of pre-fences */
#define PVA_MAX_NUM_POSTFENCES 2 /**< Maximum number of post-fences */ #define PVA_MAX_NUM_POSTFENCES 2U /**< Maximum number of post-fences */
/** Maximum number of timestamps */ /** Maximum number of timestamps */
#define PVA_MAX_NUM_TIMESTAMPS PVA_MAX_NUM_POSTFENCES #define PVA_MAX_NUM_TIMESTAMPS PVA_MAX_NUM_POSTFENCES
@@ -296,8 +317,8 @@ struct pva_cmdbuf_submit_info {
uint8_t num_output_status; uint8_t num_output_status;
uint8_t num_timestamps; uint8_t num_timestamps;
#define PVA_ENGINE_AFFINITY_NONE 0 #define PVA_ENGINE_AFFINITY_NONE 0
#define PVA_ENGINE_AFFINITY_ENGINE0 (1 << 0) #define PVA_ENGINE_AFFINITY_ENGINE0 (1U << 0)
#define PVA_ENGINE_AFFINITY_ENGINE1 (1 << 1) #define PVA_ENGINE_AFFINITY_ENGINE1 (1U << 1)
#define PVA_ENGINE_AFFINITY_ANY \ #define PVA_ENGINE_AFFINITY_ANY \
(PVA_ENGINE_AFFINITY_ENGINE0 | PVA_ENGINE_AFFINITY_ENGINE1) (PVA_ENGINE_AFFINITY_ENGINE0 | PVA_ENGINE_AFFINITY_ENGINE1)
uint8_t engine_affinity; uint8_t engine_affinity;
@@ -311,7 +332,7 @@ struct pva_cmdbuf_submit_info {
uint64_t first_chunk_offset; uint64_t first_chunk_offset;
/** Execution timeout is in ms */ /** Execution timeout is in ms */
#define PVA_EXEC_TIMEOUT_INF UINT32_MAX #define PVA_EXEC_TIMEOUT_INF UINT32_MAX
#define PVA_EXEC_TIMEOUT_REUSE (UINT32_MAX - 1) #define PVA_EXEC_TIMEOUT_REUSE (UINT32_MAX - 1U)
/** Execution Timeout */ /** Execution Timeout */
uint32_t execution_timeout_ms; uint32_t execution_timeout_ms;
struct pva_fence prefences[PVA_MAX_NUM_PREFENCES]; struct pva_fence prefences[PVA_MAX_NUM_PREFENCES];
@@ -355,8 +376,8 @@ struct pva_characteristics {
* !!!! DO NOT MODIFY !!!!!! * !!!! DO NOT MODIFY !!!!!!
* These values are defined as per DriveOS guidelines * These values are defined as per DriveOS guidelines
*/ */
#define PVA_INPUT_STATUS_SUCCESS (0) #define PVA_INPUT_STATUS_SUCCESS ((uint16_t)(0))
#define PVA_INPUT_STATUS_INVALID (0xFFFF) #define PVA_INPUT_STATUS_INVALID ((uint16_t)(0xFFFF))
/** /**
* @brief Context attribute keys. * @brief Context attribute keys.
@@ -374,4 +395,16 @@ struct pva_ctx_attr_max_cmdbuf_chunk_size {
uint16_t max_size; uint16_t max_size;
}; };
struct pva_async_error {
uint32_t error;
uint32_t queue_id;
uint32_t cmd_idx;
int32_t vpu_retcode;
uint64_t submit_id;
};
#ifdef __cplusplus
}
#endif
#endif // PVA_API_TYPES_H #endif // PVA_API_TYPES_H

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,256 @@
0,
10,
20,
30,
40,
50,
60,
70,
80,
90,
100,
110,
120,
130,
140,
150,
160,
170,
180,
190,
200,
210,
220,
230,
240,
250,
260,
270,
280,
290,
300,
310,
320,
330,
340,
350,
360,
370,
380,
390,
400,
410,
420,
430,
440,
450,
460,
470,
480,
490,
500,
510,
520,
530,
540,
550,
560,
570,
580,
590,
600,
610,
620,
630,
640,
650,
660,
670,
680,
690,
700,
710,
720,
730,
740,
750,
760,
770,
780,
790,
800,
810,
820,
830,
840,
850,
860,
870,
880,
890,
900,
910,
920,
930,
940,
950,
960,
970,
980,
990,
1000,
1010,
1020,
1030,
1040,
1050,
1060,
1070,
1080,
1090,
1100,
1110,
1120,
1130,
1140,
1150,
1160,
1170,
1180,
1190,
1200,
1210,
1220,
1230,
1240,
1250,
1260,
1270,
1280,
1290,
1300,
1310,
1320,
1330,
1340,
1350,
1360,
1370,
1380,
1390,
1400,
1410,
1420,
1430,
1440,
1450,
1460,
1470,
1480,
1490,
1500,
1510,
1520,
1530,
1540,
1550,
1560,
1570,
1580,
1590,
1600,
1610,
1620,
1630,
1640,
1650,
1660,
1670,
1680,
1690,
1700,
1710,
1720,
1730,
1740,
1750,
1760,
1770,
1780,
1790,
1800,
1810,
1820,
1830,
1840,
1850,
1860,
1870,
1880,
1890,
1900,
1910,
1920,
1930,
1940,
1950,
1960,
1970,
1980,
1990,
2000,
2010,
2020,
2030,
2040,
2050,
2060,
2070,
2080,
2090,
2100,
2110,
2120,
2130,
2140,
2150,
2160,
2170,
2180,
2190,
2200,
2210,
2220,
2230,
2240,
2250,
2260,
2270,
2280,
2290,
2300,
2310,
2320,
2330,
2340,
2350,
2360,
2370,
2380,
2390,
2400,
2410,
2420,
2430,
2440,
2450,
2460,
2470,
2480,
2490,
2500,
2510,
2520,
2530,
2540,
2550,
1 0
2 10
3 20
4 30
5 40
6 50
7 60
8 70
9 80
10 90
11 100
12 110
13 120
14 130
15 140
16 150
17 160
18 170
19 180
20 190
21 200
22 210
23 220
24 230
25 240
26 250
27 260
28 270
29 280
30 290
31 300
32 310
33 320
34 330
35 340
36 350
37 360
38 370
39 380
40 390
41 400
42 410
43 420
44 430
45 440
46 450
47 460
48 470
49 480
50 490
51 500
52 510
53 520
54 530
55 540
56 550
57 560
58 570
59 580
60 590
61 600
62 610
63 620
64 630
65 640
66 650
67 660
68 670
69 680
70 690
71 700
72 710
73 720
74 730
75 740
76 750
77 760
78 770
79 780
80 790
81 800
82 810
83 820
84 830
85 840
86 850
87 860
88 870
89 880
90 890
91 900
92 910
93 920
94 930
95 940
96 950
97 960
98 970
99 980
100 990
101 1000
102 1010
103 1020
104 1030
105 1040
106 1050
107 1060
108 1070
109 1080
110 1090
111 1100
112 1110
113 1120
114 1130
115 1140
116 1150
117 1160
118 1170
119 1180
120 1190
121 1200
122 1210
123 1220
124 1230
125 1240
126 1250
127 1260
128 1270
129 1280
130 1290
131 1300
132 1310
133 1320
134 1330
135 1340
136 1350
137 1360
138 1370
139 1380
140 1390
141 1400
142 1410
143 1420
144 1430
145 1440
146 1450
147 1460
148 1470
149 1480
150 1490
151 1500
152 1510
153 1520
154 1530
155 1540
156 1550
157 1560
158 1570
159 1580
160 1590
161 1600
162 1610
163 1620
164 1630
165 1640
166 1650
167 1660
168 1670
169 1680
170 1690
171 1700
172 1710
173 1720
174 1730
175 1740
176 1750
177 1760
178 1770
179 1780
180 1790
181 1800
182 1810
183 1820
184 1830
185 1840
186 1850
187 1860
188 1870
189 1880
190 1890
191 1900
192 1910
193 1920
194 1930
195 1940
196 1950
197 1960
198 1970
199 1980
200 1990
201 2000
202 2010
203 2020
204 2030
205 2040
206 2050
207 2060
208 2070
209 2080
210 2090
211 2100
212 2110
213 2120
214 2130
215 2140
216 2150
217 2160
218 2170
219 2180
220 2190
221 2200
222 2210
223 2220
224 2230
225 2240
226 2250
227 2260
228 2270
229 2280
230 2290
231 2300
232 2310
233 2320
234 2330
235 2340
236 2350
237 2360
238 2370
239 2380
240 2390
241 2400
242 2410
243 2420
244 2430
245 2440
246 2450
247 2460
248 2470
249 2480
250 2490
251 2500
252 2510
253 2520
254 2530
255 2540
256 2550

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
108U,107U,107U,108U,107U,105U,105U,105U,105U,105U,106U,107U,108U,108U,108U,108U,108U,111U,111U,111U,110U,108U,108U,108U,110U,112U,117U,126U,144U,162U,172U,175U,175U,175U,172U,172U,172U,173U,174U,175U,174U,176U,176U,175U,175U,175U,175U,175U,175U,175U,175U,175U,178U,175U,174U,174U,174U,175U,176U,174U,174U,174U,172U,172U,169U,170U,170U,161U,134U,108U,93U,89U,93U,98U,97U,97U,96U,93U,91U,91U,92U,94U,92U,91U,90U,89U,90U,91U,93U,94U,96U,94U,65535U,65535U,65535U,65535U,65535U,65535U,
113U,112U,113U,114U,113U,112U,112U,111U,111U,111U,111U,112U,112U,112U,112U,112U,112U,114U,114U,116U,117U,117U,114U,116U,116U,121U,133U,147U,160U,169U,174U,175U,175U,175U,174U,173U,174U,175U,174U,174U,175U,174U,174U,175U,175U,175U,175U,175U,175U,175U,175U,175U,176U,175U,174U,176U,176U,175U,174U,173U,173U,173U,172U,171U,169U,168U,167U,151U,126U,109U,102U,102U,104U,105U,106U,105U,103U,102U,103U,103U,102U,102U,100U,98U,98U,99U,100U,102U,103U,103U,104U,103U,65535U,65535U,65535U,65535U,65535U,65535U,
118U,117U,119U,118U,117U,117U,117U,117U,117U,118U,117U,117U,117U,116U,116U,116U,116U,117U,118U,117U,119U,120U,120U,121U,125U,137U,150U,162U,171U,175U,176U,176U,176U,175U,175U,175U,176U,176U,176U,175U,175U,174U,174U,175U,175U,175U,175U,175U,174U,174U,175U,175U,175U,175U,176U,178U,178U,178U,178U,175U,175U,173U,171U,171U,168U,166U,159U,143U,123U,112U,111U,113U,113U,111U,114U,113U,110U,109U,109U,110U,109U,106U,106U,105U,105U,107U,107U,110U,109U,109U,107U,106U,65535U,65535U,65535U,65535U,65535U,65535U,
120U,119U,118U,117U,116U,116U,117U,118U,119U,120U,120U,119U,119U,117U,118U,120U,121U,121U,120U,119U,118U,121U,122U,122U,136U,152U,162U,169U,174U,178U,178U,176U,175U,175U,174U,174U,175U,175U,175U,175U,174U,174U,174U,174U,174U,174U,174U,174U,173U,173U,174U,174U,175U,176U,178U,178U,178U,179U,180U,179U,179U,174U,169U,166U,164U,162U,153U,137U,122U,117U,118U,118U,118U,119U,121U,120U,119U,118U,116U,113U,113U,114U,116U,114U,114U,116U,117U,119U,118U,118U,119U,118U,65535U,65535U,65535U,65535U,65535U,65535U,
122U,122U,122U,121U,121U,122U,124U,125U,125U,126U,129U,127U,127U,129U,130U,129U,130U,132U,131U,131U,132U,133U,134U,136U,147U,161U,167U,173U,175U,175U,178U,178U,174U,175U,177U,177U,175U,177U,175U,175U,174U,175U,177U,174U,174U,174U,174U,174U,174U,174U,174U,174U,176U,178U,178U,178U,179U,179U,181U,181U,179U,174U,171U,165U,161U,160U,154U,143U,134U,134U,134U,134U,134U,136U,137U,138U,139U,139U,136U,131U,132U,136U,137U,136U,132U,132U,132U,134U,134U,136U,143U,143U,65535U,65535U,65535U,65535U,65535U,65535U,
138U,143U,147U,150U,147U,147U,148U,150U,152U,153U,154U,152U,150U,151U,152U,150U,150U,152U,152U,153U,157U,159U,159U,160U,162U,166U,171U,174U,175U,175U,176U,176U,177U,177U,179U,178U,177U,177U,177U,177U,177U,175U,175U,175U,174U,174U,174U,174U,174U,174U,174U,175U,176U,176U,176U,176U,176U,176U,180U,180U,176U,174U,171U,166U,161U,161U,164U,164U,161U,161U,161U,161U,161U,161U,162U,165U,165U,167U,165U,159U,160U,165U,166U,166U,162U,161U,160U,161U,161U,162U,172U,172U,65535U,65535U,65535U,65535U,65535U,65535U,
162U,164U,169U,174U,176U,179U,179U,179U,181U,181U,179U,179U,176U,175U,175U,172U,172U,174U,174U,174U,175U,178U,176U,175U,173U,171U,172U,174U,175U,176U,178U,179U,178U,178U,179U,179U,177U,177U,177U,177U,177U,175U,174U,175U,175U,175U,174U,174U,174U,174U,174U,175U,176U,176U,175U,175U,174U,174U,175U,174U,172U,169U,169U,166U,162U,165U,173U,180U,183U,183U,183U,182U,181U,181U,183U,183U,183U,183U,183U,180U,181U,185U,185U,183U,181U,180U,179U,180U,180U,181U,185U,186U,65535U,65535U,65535U,65535U,65535U,65535U,
168U,161U,169U,179U,189U,195U,195U,193U,192U,190U,189U,192U,192U,190U,188U,187U,188U,188U,189U,186U,184U,183U,179U,176U,175U,173U,173U,174U,174U,177U,178U,178U,178U,178U,179U,179U,179U,179U,177U,178U,177U,174U,175U,177U,177U,174U,174U,174U,174U,174U,175U,177U,176U,174U,173U,173U,172U,172U,171U,169U,168U,167U,168U,166U,164U,168U,178U,185U,187U,188U,188U,188U,187U,188U,189U,189U,187U,188U,189U,188U,186U,187U,187U,186U,186U,185U,182U,183U,185U,185U,185U,186U,65535U,65535U,65535U,65535U,65535U,65535U,
166U,158U,165U,172U,181U,188U,189U,190U,189U,188U,189U,192U,193U,193U,193U,190U,192U,192U,193U,191U,187U,182U,176U,174U,174U,175U,174U,174U,174U,177U,177U,177U,178U,179U,180U,180U,182U,180U,179U,178U,177U,175U,175U,175U,175U,174U,174U,173U,173U,174U,175U,175U,175U,173U,173U,172U,172U,172U,171U,171U,169U,169U,168U,166U,166U,168U,175U,180U,181U,181U,181U,183U,185U,186U,187U,186U,186U,187U,187U,187U,185U,183U,185U,185U,185U,183U,183U,183U,183U,185U,186U,186U,65535U,65535U,65535U,65535U,65535U,65535U,
173U,169U,168U,169U,169U,169U,171U,173U,175U,179U,187U,192U,190U,190U,192U,192U,190U,192U,193U,189U,184U,180U,174U,173U,174U,174U,174U,177U,175U,177U,178U,179U,180U,180U,181U,181U,181U,179U,179U,179U,179U,177U,177U,175U,175U,175U,175U,174U,173U,175U,175U,174U,174U,173U,172U,171U,171U,172U,172U,171U,171U,171U,168U,165U,165U,167U,171U,175U,179U,179U,179U,182U,183U,185U,186U,186U,187U,187U,185U,183U,183U,185U,185U,185U,185U,185U,186U,186U,186U,186U,187U,188U,65535U,65535U,65535U,65535U,65535U,65535U,
183U,183U,181U,178U,171U,161U,155U,154U,161U,169U,183U,193U,192U,190U,192U,193U,192U,192U,193U,187U,182U,179U,174U,173U,174U,174U,177U,178U,178U,179U,179U,180U,181U,182U,182U,181U,181U,180U,179U,180U,180U,178U,177U,177U,176U,175U,175U,176U,177U,178U,177U,174U,174U,174U,173U,172U,172U,172U,173U,172U,169U,168U,168U,168U,167U,168U,172U,176U,180U,181U,182U,185U,186U,186U,187U,188U,189U,188U,185U,185U,186U,187U,188U,187U,186U,187U,189U,188U,189U,188U,189U,190U,65535U,65535U,65535U,65535U,65535U,65535U,
190U,189U,190U,193U,181U,167U,152U,147U,155U,165U,169U,183U,193U,192U,190U,192U,194U,193U,192U,185U,176U,171U,171U,171U,174U,176U,177U,178U,180U,180U,181U,181U,182U,185U,183U,182U,181U,179U,180U,179U,178U,177U,176U,178U,178U,176U,175U,176U,179U,181U,183U,182U,181U,179U,177U,176U,176U,176U,176U,176U,173U,167U,168U,172U,171U,172U,174U,177U,180U,181U,185U,186U,186U,187U,186U,186U,188U,188U,189U,189U,187U,187U,187U,187U,186U,187U,188U,187U,187U,188U,189U,189U,65535U,65535U,65535U,65535U,65535U,65535U,
190U,190U,190U,194U,192U,185U,173U,162U,154U,148U,148U,162U,183U,193U,192U,190U,192U,189U,186U,180U,172U,165U,164U,166U,171U,178U,178U,178U,179U,180U,180U,180U,181U,180U,180U,182U,178U,175U,176U,176U,174U,174U,176U,178U,179U,178U,175U,178U,180U,180U,182U,182U,180U,173U,172U,173U,172U,170U,169U,169U,169U,166U,164U,164U,165U,167U,168U,170U,173U,177U,179U,181U,181U,181U,181U,182U,186U,186U,187U,187U,186U,185U,185U,185U,186U,185U,185U,185U,185U,186U,187U,186U,65535U,65535U,65535U,65535U,65535U,65535U,
194U,194U,195U,197U,197U,194U,193U,182U,159U,139U,141U,157U,179U,195U,199U,197U,194U,190U,188U,181U,178U,174U,174U,174U,178U,180U,180U,180U,181U,181U,181U,180U,178U,176U,178U,180U,177U,178U,180U,181U,180U,178U,180U,179U,181U,185U,185U,182U,181U,180U,179U,176U,173U,171U,171U,169U,167U,165U,164U,162U,164U,160U,157U,158U,163U,165U,168U,172U,174U,178U,178U,179U,182U,185U,185U,184U,182U,182U,182U,184U,186U,187U,189U,192U,192U,192U,192U,192U,193U,192U,193U,193U,65535U,65535U,65535U,65535U,65535U,65535U,
213U,213U,211U,211U,210U,207U,210U,195U,172U,155U,171U,187U,200U,210U,216U,215U,210U,207U,206U,201U,201U,202U,201U,201U,199U,197U,195U,195U,195U,196U,196U,195U,196U,195U,194U,193U,193U,194U,196U,196U,195U,194U,200U,200U,203U,207U,207U,203U,201U,200U,199U,197U,196U,199U,199U,189U,188U,192U,192U,188U,172U,154U,161U,180U,189U,192U,193U,195U,198U,200U,201U,200U,207U,209U,207U,205U,203U,203U,203U,205U,207U,209U,210U,213U,213U,213U,213U,213U,214U,214U,215U,215U,65535U,65535U,65535U,65535U,65535U,65535U,
236U,235U,234U,234U,233U,233U,218U,200U,193U,199U,218U,230U,231U,230U,234U,235U,235U,236U,235U,235U,236U,237U,237U,237U,232U,223U,214U,213U,214U,214U,215U,219U,221U,223U,225U,225U,227U,228U,226U,225U,225U,225U,225U,225U,226U,227U,230U,233U,233U,231U,230U,230U,229U,229U,228U,227U,221U,221U,222U,222U,182U,153U,172U,208U,225U,226U,227U,227U,227U,228U,228U,228U,230U,232U,230U,229U,229U,229U,230U,232U,232U,232U,232U,232U,234U,236U,237U,238U,238U,237U,237U,237U,65535U,65535U,65535U,65535U,65535U,65535U,
239U,239U,240U,240U,240U,240U,221U,200U,207U,223U,240U,243U,240U,238U,238U,240U,241U,240U,240U,237U,236U,236U,235U,233U,223U,214U,199U,199U,200U,201U,203U,208U,214U,220U,221U,221U,223U,223U,222U,221U,220U,220U,219U,220U,221U,221U,223U,226U,227U,229U,228U,228U,227U,226U,226U,226U,226U,224U,220U,213U,183U,159U,184U,223U,239U,238U,238U,238U,238U,238U,237U,238U,235U,233U,230U,230U,230U,229U,230U,230U,232U,233U,233U,234U,236U,238U,238U,238U,237U,236U,235U,233U,65535U,65535U,65535U,65535U,65535U,65535U,
220U,221U,223U,224U,226U,220U,196U,176U,183U,202U,222U,230U,224U,222U,222U,222U,220U,216U,214U,211U,207U,204U,202U,196U,191U,186U,185U,184U,182U,181U,181U,182U,186U,189U,192U,194U,196U,195U,193U,193U,192U,191U,191U,191U,192U,192U,193U,194U,195U,199U,199U,199U,199U,197U,197U,196U,201U,196U,185U,172U,160U,157U,183U,210U,222U,220U,218U,220U,221U,222U,221U,220U,213U,208U,206U,208U,208U,208U,207U,207U,208U,209U,212U,212U,213U,212U,209U,208U,207U,207U,207U,206U,65535U,65535U,65535U,65535U,65535U,65535U,
193U,193U,199U,203U,201U,192U,172U,152U,150U,164U,190U,206U,202U,199U,197U,195U,193U,190U,192U,193U,193U,190U,186U,182U,180U,181U,181U,180U,178U,175U,177U,174U,175U,175U,177U,178U,181U,180U,178U,179U,179U,179U,178U,178U,179U,179U,179U,180U,182U,182U,183U,182U,181U,180U,179U,179U,179U,173U,167U,158U,153U,157U,181U,194U,197U,194U,193U,193U,192U,192U,193U,193U,191U,189U,192U,194U,194U,192U,189U,189U,189U,191U,192U,193U,191U,187U,185U,184U,185U,186U,187U,188U,65535U,65535U,65535U,65535U,65535U,65535U,
181U,182U,186U,189U,187U,179U,158U,141U,133U,143U,164U,186U,190U,188U,186U,181U,179U,179U,178U,181U,183U,183U,186U,186U,186U,187U,187U,186U,185U,184U,180U,182U,181U,180U,180U,179U,180U,181U,181U,183U,183U,185U,183U,183U,182U,182U,181U,181U,182U,181U,181U,180U,180U,179U,178U,174U,171U,164U,161U,161U,164U,171U,181U,189U,192U,189U,188U,187U,185U,185U,187U,188U,188U,189U,189U,191U,188U,186U,185U,184U,184U,184U,185U,185U,185U,185U,185U,185U,186U,187U,188U,189U,65535U,65535U,65535U,65535U,65535U,65535U,
179U,180U,181U,181U,179U,171U,151U,141U,139U,147U,164U,179U,183U,182U,181U,181U,181U,182U,185U,185U,187U,188U,187U,187U,186U,187U,186U,186U,186U,185U,184U,184U,182U,182U,181U,181U,183U,183U,185U,185U,185U,185U,183U,185U,185U,183U,182U,182U,181U,182U,180U,181U,180U,180U,179U,172U,162U,155U,150U,158U,173U,182U,189U,192U,193U,193U,192U,187U,189U,192U,190U,192U,192U,192U,191U,191U,189U,189U,188U,187U,187U,188U,191U,191U,193U,193U,192U,191U,191U,191U,192U,193U,65535U,65535U,65535U,65535U,65535U,65535U,
178U,178U,180U,178U,175U,166U,151U,146U,155U,166U,179U,181U,180U,180U,181U,182U,183U,185U,185U,186U,186U,187U,187U,187U,186U,187U,186U,186U,186U,185U,185U,185U,184U,184U,181U,181U,183U,183U,183U,183U,183U,183U,182U,182U,182U,183U,182U,182U,182U,182U,181U,181U,180U,180U,180U,173U,161U,150U,145U,157U,174U,186U,189U,189U,191U,188U,187U,186U,188U,189U,189U,190U,191U,188U,188U,191U,191U,191U,189U,188U,188U,189U,192U,192U,193U,193U,191U,191U,191U,191U,193U,194U,65535U,65535U,65535U,65535U,65535U,65535U,
176U,176U,178U,175U,172U,165U,159U,159U,165U,173U,186U,181U,178U,178U,181U,181U,183U,185U,186U,187U,188U,188U,188U,187U,186U,187U,186U,186U,186U,186U,186U,185U,185U,184U,182U,181U,183U,183U,183U,182U,182U,183U,182U,182U,182U,183U,182U,182U,182U,182U,182U,181U,180U,181U,182U,176U,162U,150U,146U,158U,176U,187U,189U,191U,191U,187U,187U,188U,187U,187U,189U,193U,191U,188U,189U,192U,191U,189U,189U,189U,189U,191U,189U,192U,193U,193U,192U,193U,193U,193U,194U,195U,65535U,65535U,65535U,65535U,65535U,65535U,
179U,180U,179U,175U,173U,167U,167U,168U,171U,173U,174U,178U,176U,179U,183U,183U,183U,185U,187U,187U,188U,188U,189U,189U,188U,188U,187U,187U,186U,186U,186U,186U,185U,185U,182U,182U,182U,182U,183U,183U,182U,183U,183U,182U,182U,182U,182U,182U,182U,182U,182U,181U,181U,181U,182U,178U,162U,151U,150U,160U,176U,187U,192U,193U,192U,190U,190U,190U,189U,189U,190U,192U,191U,189U,191U,192U,192U,192U,191U,191U,191U,191U,192U,192U,193U,193U,194U,194U,195U,195U,195U,195U,65535U,65535U,65535U,65535U,65535U,65535U,
180U,181U,180U,179U,175U,173U,168U,159U,155U,157U,162U,172U,176U,180U,183U,183U,186U,186U,187U,187U,187U,188U,189U,189U,188U,188U,187U,187U,186U,186U,186U,186U,185U,185U,184U,184U,184U,182U,183U,183U,182U,182U,182U,181U,182U,182U,182U,182U,182U,182U,181U,181U,181U,180U,181U,178U,165U,155U,158U,165U,179U,188U,192U,194U,193U,192U,190U,190U,190U,190U,190U,190U,188U,188U,189U,191U,192U,192U,191U,191U,191U,191U,192U,192U,192U,193U,194U,194U,195U,195U,196U,196U,65535U,65535U,65535U,65535U,65535U,65535U,
181U,181U,181U,181U,179U,175U,171U,154U,138U,137U,146U,165U,176U,181U,183U,183U,186U,188U,186U,186U,187U,188U,188U,188U,188U,188U,187U,187U,186U,186U,186U,186U,186U,185U,184U,184U,185U,184U,185U,183U,182U,182U,182U,181U,182U,182U,182U,182U,182U,182U,181U,181U,180U,180U,179U,175U,172U,164U,168U,173U,180U,186U,192U,193U,192U,192U,190U,190U,190U,189U,188U,189U,187U,188U,192U,191U,191U,192U,192U,192U,192U,192U,192U,192U,192U,193U,194U,194U,195U,196U,196U,196U,65535U,65535U,65535U,65535U,65535U,65535U,
180U,181U,180U,180U,179U,178U,174U,164U,146U,139U,145U,161U,176U,182U,183U,183U,186U,187U,186U,186U,187U,187U,188U,188U,188U,188U,186U,186U,186U,185U,185U,185U,185U,184U,184U,184U,184U,182U,183U,183U,182U,182U,182U,182U,182U,182U,182U,182U,182U,182U,181U,180U,181U,181U,180U,178U,174U,172U,174U,178U,180U,186U,192U,193U,192U,192U,192U,190U,190U,188U,188U,188U,186U,188U,191U,191U,191U,192U,192U,192U,192U,192U,192U,192U,192U,193U,194U,194U,195U,196U,196U,196U,65535U,65535U,65535U,65535U,65535U,65535U,
182U,180U,179U,179U,179U,179U,176U,176U,167U,158U,154U,165U,175U,182U,183U,185U,185U,186U,186U,186U,186U,187U,188U,188U,188U,188U,186U,186U,186U,185U,185U,185U,185U,184U,184U,184U,184U,182U,183U,182U,182U,182U,181U,181U,182U,182U,181U,181U,181U,181U,180U,180U,182U,182U,181U,178U,175U,174U,175U,178U,182U,187U,192U,192U,192U,192U,192U,190U,188U,187U,186U,186U,186U,187U,189U,189U,191U,191U,192U,192U,192U,192U,192U,192U,192U,193U,193U,194U,195U,195U,196U,194U,65535U,65535U,65535U,65535U,65535U,65535U,
183U,182U,180U,179U,180U,181U,179U,179U,173U,166U,165U,168U,178U,185U,185U,185U,185U,185U,186U,186U,187U,187U,187U,187U,187U,187U,186U,186U,185U,185U,185U,185U,185U,184U,184U,184U,184U,182U,183U,182U,182U,182U,181U,181U,181U,181U,181U,181U,181U,181U,181U,182U,181U,181U,181U,180U,176U,176U,178U,179U,183U,189U,192U,192U,192U,190U,189U,188U,187U,186U,185U,186U,186U,187U,188U,189U,191U,191U,192U,192U,192U,192U,192U,192U,192U,192U,193U,193U,194U,194U,194U,193U,65535U,65535U,65535U,65535U,65535U,65535U,
183U,182U,180U,180U,180U,179U,176U,174U,171U,167U,168U,175U,182U,185U,185U,185U,185U,185U,185U,185U,186U,187U,187U,187U,187U,187U,185U,185U,185U,184U,184U,184U,184U,184U,182U,182U,182U,182U,183U,182U,182U,182U,181U,181U,181U,181U,180U,180U,180U,180U,178U,178U,180U,179U,178U,178U,174U,176U,179U,181U,186U,190U,192U,192U,192U,189U,188U,188U,187U,186U,186U,186U,186U,187U,189U,189U,191U,191U,191U,192U,192U,192U,192U,192U,192U,192U,193U,193U,193U,192U,193U,193U,65535U,65535U,65535U,65535U,65535U,65535U,
185U,185U,182U,180U,176U,174U,172U,172U,172U,171U,172U,179U,185U,185U,185U,185U,185U,185U,185U,185U,186U,187U,187U,187U,187U,187U,185U,185U,185U,184U,184U,184U,184U,182U,182U,182U,182U,181U,182U,182U,181U,181U,181U,181U,181U,181U,180U,180U,179U,179U,175U,173U,171U,171U,169U,169U,169U,175U,180U,183U,186U,190U,192U,190U,190U,189U,188U,188U,187U,187U,187U,188U,187U,188U,188U,189U,191U,191U,191U,191U,192U,192U,192U,192U,192U,192U,191U,192U,193U,192U,193U,193U,65535U,65535U,65535U,65535U,65535U,65535U,
187U,185U,181U,178U,172U,169U,169U,172U,173U,174U,179U,181U,185U,185U,185U,185U,185U,185U,185U,186U,186U,186U,187U,187U,187U,187U,185U,185U,185U,184U,184U,184U,184U,182U,182U,182U,182U,181U,182U,182U,181U,181U,181U,181U,180U,180U,179U,179U,178U,175U,173U,171U,167U,161U,162U,164U,167U,175U,182U,186U,187U,188U,189U,189U,189U,189U,189U,189U,189U,189U,188U,188U,188U,188U,191U,191U,191U,191U,191U,191U,191U,192U,191U,191U,192U,191U,191U,191U,192U,192U,192U,193U,65535U,65535U,65535U,65535U,65535U,65535U,
187U,183U,180U,174U,169U,168U,171U,174U,176U,182U,185U,183U,185U,185U,185U,185U,185U,185U,185U,186U,186U,186U,186U,186U,186U,186U,185U,185U,184U,184U,184U,184U,184U,182U,182U,182U,182U,181U,182U,182U,181U,181U,181U,181U,180U,180U,179U,178U,176U,175U,174U,172U,168U,165U,165U,166U,169U,179U,183U,187U,188U,188U,189U,189U,189U,189U,190U,192U,189U,189U,189U,189U,188U,189U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
188U,185U,179U,172U,166U,169U,174U,178U,180U,185U,186U,186U,185U,185U,185U,185U,185U,185U,185U,185U,185U,186U,186U,186U,186U,186U,184U,184U,184U,182U,182U,182U,182U,182U,181U,181U,181U,181U,182U,182U,181U,181U,181U,181U,180U,180U,179U,178U,176U,175U,175U,173U,172U,171U,171U,173U,178U,185U,187U,187U,188U,189U,189U,189U,189U,189U,189U,190U,190U,190U,192U,190U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
190U,185U,176U,166U,165U,169U,179U,183U,183U,186U,187U,187U,185U,185U,185U,185U,185U,185U,185U,185U,185U,186U,186U,186U,186U,186U,184U,184U,184U,182U,182U,182U,182U,181U,181U,181U,181U,180U,181U,181U,181U,181U,181U,181U,180U,180U,179U,178U,176U,176U,175U,174U,174U,175U,175U,179U,182U,186U,188U,188U,189U,189U,189U,189U,189U,189U,190U,190U,190U,192U,193U,192U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
190U,178U,162U,164U,164U,172U,180U,183U,186U,187U,187U,187U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,186U,186U,186U,186U,184U,184U,184U,182U,182U,182U,182U,181U,181U,181U,181U,180U,181U,181U,181U,181U,181U,181U,180U,180U,180U,179U,179U,179U,176U,176U,176U,176U,178U,180U,183U,186U,188U,188U,189U,189U,189U,189U,189U,190U,192U,192U,192U,193U,193U,193U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
185U,168U,154U,161U,172U,179U,182U,183U,187U,187U,187U,187U,186U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,184U,184U,182U,182U,182U,182U,182U,181U,181U,181U,181U,180U,181U,181U,181U,181U,181U,180U,181U,181U,180U,180U,180U,180U,179U,178U,178U,179U,179U,181U,183U,186U,188U,189U,189U,189U,190U,189U,189U,192U,192U,192U,193U,193U,193U,193U,192U,192U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,191U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
175U,161U,155U,166U,176U,180U,182U,183U,186U,185U,185U,186U,186U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,185U,183U,183U,183U,183U,183U,182U,182U,182U,182U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,180U,180U,180U,180U,180U,181U,182U,185U,187U,188U,189U,190U,190U,190U,192U,190U,190U,192U,192U,192U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
167U,157U,160U,173U,180U,181U,181U,182U,185U,183U,183U,185U,185U,185U,185U,185U,185U,185U,185U,185U,183U,183U,185U,185U,185U,185U,183U,183U,183U,183U,183U,182U,182U,182U,182U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,182U,182U,185U,187U,189U,190U,192U,192U,193U,193U,192U,190U,192U,192U,192U,193U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
163U,157U,164U,178U,181U,181U,182U,183U,183U,183U,183U,185U,183U,183U,183U,183U,183U,185U,183U,183U,183U,183U,185U,185U,185U,185U,185U,183U,183U,183U,183U,183U,182U,182U,182U,182U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,182U,182U,182U,182U,182U,183U,187U,187U,188U,190U,192U,193U,193U,193U,193U,192U,190U,192U,192U,193U,193U,193U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
161U,160U,172U,180U,182U,181U,182U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,185U,185U,183U,183U,183U,183U,183U,183U,183U,183U,182U,182U,182U,182U,181U,181U,181U,181U,181U,181U,181U,181U,180U,182U,182U,182U,182U,182U,182U,185U,187U,189U,192U,193U,193U,193U,193U,193U,193U,190U,190U,192U,192U,193U,193U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
161U,166U,175U,180U,181U,182U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,182U,182U,181U,182U,183U,185U,185U,183U,183U,183U,183U,183U,183U,183U,183U,183U,182U,182U,182U,182U,181U,181U,181U,181U,180U,181U,181U,178U,179U,179U,179U,178U,179U,180U,183U,187U,190U,193U,195U,195U,195U,194U,193U,192U,189U,189U,192U,193U,193U,193U,194U,194U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
154U,168U,181U,181U,180U,181U,183U,183U,182U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,183U,183U,183U,183U,183U,183U,183U,183U,183U,183U,182U,182U,182U,181U,182U,182U,181U,181U,181U,179U,180U,180U,179U,174U,172U,173U,173U,172U,171U,178U,185U,187U,190U,194U,196U,199U,199U,196U,194U,192U,188U,189U,190U,193U,195U,195U,194U,194U,194U,193U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
154U,167U,180U,181U,180U,180U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,181U,182U,183U,183U,183U,182U,183U,183U,183U,183U,182U,181U,181U,181U,180U,181U,181U,181U,181U,180U,179U,180U,178U,174U,172U,168U,166U,166U,166U,167U,175U,182U,186U,188U,193U,195U,199U,199U,196U,192U,190U,188U,189U,190U,190U,194U,195U,195U,194U,194U,193U,193U,193U,193U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
175U,175U,178U,179U,179U,180U,180U,181U,181U,181U,180U,181U,181U,180U,180U,180U,180U,180U,180U,180U,181U,181U,181U,181U,181U,182U,182U,182U,181U,182U,182U,181U,181U,181U,181U,181U,180U,180U,179U,179U,179U,176U,174U,174U,174U,171U,167U,164U,160U,159U,159U,164U,172U,179U,183U,187U,192U,194U,196U,199U,196U,193U,192U,189U,190U,190U,192U,194U,195U,195U,194U,192U,192U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
201U,189U,178U,176U,179U,179U,180U,180U,180U,181U,181U,181U,179U,179U,179U,179U,179U,179U,179U,180U,180U,181U,180U,181U,181U,181U,182U,182U,181U,182U,182U,182U,182U,181U,181U,181U,180U,180U,179U,179U,179U,176U,176U,172U,168U,166U,164U,159U,155U,153U,153U,158U,167U,176U,185U,189U,192U,194U,196U,196U,195U,195U,193U,193U,193U,193U,194U,194U,195U,195U,194U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,65535U,65535U,65535U,65535U,65535U,65535U,
225U,203U,180U,175U,177U,177U,179U,179U,179U,180U,181U,180U,179U,179U,179U,179U,179U,179U,179U,180U,180U,180U,181U,181U,180U,181U,181U,181U,180U,182U,182U,181U,181U,181U,180U,179U,180U,180U,180U,180U,181U,186U,190U,193U,186U,175U,165U,158U,151U,145U,145U,151U,164U,175U,183U,188U,188U,190U,194U,194U,195U,195U,194U,194U,194U,195U,196U,196U,196U,196U,195U,193U,193U,193U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,190U,65535U,65535U,65535U,65535U,65535U,65535U,
235U,207U,180U,176U,177U,177U,179U,180U,181U,181U,181U,181U,179U,179U,179U,179U,179U,179U,179U,179U,179U,180U,181U,180U,180U,181U,181U,181U,180U,180U,180U,180U,179U,181U,181U,179U,178U,180U,182U,181U,179U,188U,215U,229U,223U,197U,169U,159U,148U,143U,141U,147U,161U,174U,185U,188U,188U,188U,192U,192U,192U,192U,194U,193U,193U,194U,195U,196U,196U,196U,195U,193U,192U,192U,190U,190U,190U,190U,190U,190U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,192U,190U,65535U,65535U,65535U,65535U,65535U,65535U,
227U,202U,179U,175U,176U,177U,179U,181U,182U,182U,181U,182U,180U,178U,179U,179U,179U,179U,179U,180U,179U,180U,182U,181U,180U,180U,181U,181U,179U,179U,179U,179U,178U,180U,181U,181U,179U,180U,181U,181U,176U,187U,208U,224U,220U,196U,178U,160U,147U,138U,137U,146U,161U,176U,185U,189U,190U,190U,190U,192U,192U,192U,192U,190U,189U,188U,189U,192U,195U,194U,192U,193U,192U,192U,188U,188U,189U,190U,189U,190U,192U,192U,190U,190U,190U,190U,190U,190U,190U,192U,192U,190U,65535U,65535U,65535U,65535U,65535U,65535U,
225U,202U,177U,174U,175U,178U,180U,181U,181U,181U,181U,181U,179U,178U,179U,179U,178U,179U,180U,180U,180U,182U,187U,187U,187U,184U,182U,181U,180U,179U,179U,179U,180U,180U,180U,180U,180U,179U,181U,182U,181U,185U,187U,192U,192U,185U,176U,160U,146U,137U,133U,145U,164U,178U,187U,190U,190U,190U,189U,190U,190U,189U,190U,188U,182U,179U,178U,181U,189U,189U,187U,189U,188U,187U,186U,186U,187U,189U,189U,190U,192U,192U,190U,190U,190U,190U,190U,190U,190U,190U,190U,188U,65535U,65535U,65535U,65535U,65535U,65535U,
223U,205U,182U,174U,179U,180U,181U,181U,182U,181U,181U,181U,179U,179U,179U,179U,179U,180U,180U,181U,181U,181U,189U,205U,210U,200U,189U,183U,181U,179U,179U,179U,180U,180U,179U,179U,179U,178U,180U,180U,182U,186U,186U,183U,182U,178U,168U,159U,147U,139U,141U,153U,166U,175U,187U,190U,190U,190U,188U,188U,188U,188U,187U,183U,175U,169U,166U,168U,179U,181U,182U,185U,183U,183U,182U,183U,185U,185U,186U,188U,190U,190U,187U,186U,188U,190U,190U,190U,189U,189U,188U,187U,65535U,65535U,65535U,65535U,65535U,65535U,
221U,205U,184U,177U,180U,181U,181U,182U,182U,182U,181U,181U,180U,179U,179U,180U,180U,180U,181U,181U,182U,184U,191U,207U,212U,204U,193U,185U,181U,179U,178U,179U,179U,178U,178U,176U,176U,175U,176U,176U,180U,190U,196U,203U,201U,190U,186U,170U,152U,146U,151U,160U,166U,174U,177U,181U,182U,182U,182U,185U,187U,186U,182U,178U,173U,165U,160U,161U,168U,174U,178U,179U,181U,181U,182U,182U,181U,179U,180U,182U,182U,182U,179U,179U,182U,185U,185U,186U,186U,186U,186U,185U,65535U,65535U,65535U,65535U,65535U,65535U,
204U,195U,184U,179U,181U,181U,181U,182U,182U,181U,181U,181U,180U,179U,179U,180U,179U,179U,180U,180U,181U,184U,187U,187U,188U,186U,182U,180U,176U,174U,176U,178U,178U,176U,176U,175U,175U,174U,173U,172U,175U,192U,209U,222U,221U,214U,210U,186U,158U,152U,155U,163U,163U,167U,167U,167U,167U,167U,169U,173U,176U,174U,171U,171U,169U,164U,159U,160U,165U,168U,171U,172U,172U,172U,173U,172U,171U,169U,171U,171U,172U,172U,172U,172U,174U,176U,178U,179U,181U,185U,183U,182U,65535U,65535U,65535U,65535U,65535U,65535U,
181U,179U,179U,179U,181U,182U,181U,181U,180U,180U,180U,180U,179U,179U,179U,177U,176U,175U,176U,176U,176U,176U,175U,175U,174U,175U,176U,174U,172U,170U,170U,172U,174U,174U,174U,172U,169U,169U,167U,161U,166U,186U,204U,217U,219U,216U,214U,194U,162U,146U,152U,156U,160U,161U,159U,157U,156U,156U,155U,159U,163U,161U,158U,158U,161U,160U,156U,158U,162U,166U,166U,166U,166U,166U,166U,165U,165U,163U,163U,163U,163U,165U,166U,167U,169U,172U,172U,173U,174U,175U,174U,173U,65535U,65535U,65535U,65535U,65535U,65535U,
176U,175U,174U,175U,177U,180U,178U,178U,175U,176U,175U,175U,175U,176U,175U,172U,170U,170U,170U,168U,166U,166U,165U,164U,165U,165U,166U,163U,161U,160U,158U,158U,161U,162U,160U,160U,162U,161U,155U,148U,153U,172U,189U,203U,204U,194U,191U,184U,160U,138U,145U,148U,151U,153U,151U,148U,148U,149U,149U,149U,151U,152U,149U,148U,153U,155U,152U,153U,156U,159U,160U,162U,162U,162U,161U,161U,161U,160U,160U,161U,159U,159U,158U,159U,160U,163U,163U,163U,163U,163U,161U,162U,65535U,65535U,65535U,65535U,65535U,65535U,
175U,173U,172U,171U,173U,174U,175U,175U,174U,173U,173U,173U,171U,172U,170U,168U,167U,167U,167U,163U,161U,159U,157U,154U,152U,152U,151U,148U,148U,146U,144U,145U,147U,148U,148U,149U,151U,142U,135U,135U,151U,174U,188U,200U,193U,174U,155U,151U,139U,127U,129U,133U,137U,140U,141U,144U,146U,147U,147U,147U,147U,148U,148U,147U,148U,148U,149U,149U,152U,154U,154U,156U,157U,157U,158U,158U,159U,158U,159U,158U,156U,154U,153U,153U,155U,153U,154U,154U,155U,158U,158U,158U,65535U,65535U,65535U,65535U,65535U,65535U,
175U,175U,168U,166U,168U,171U,173U,173U,171U,171U,171U,168U,169U,168U,167U,165U,162U,162U,162U,160U,156U,155U,151U,148U,146U,146U,146U,145U,143U,140U,138U,139U,140U,140U,141U,141U,140U,131U,126U,135U,156U,179U,186U,187U,178U,155U,129U,124U,123U,121U,121U,126U,131U,137U,140U,141U,142U,144U,145U,146U,146U,146U,146U,148U,147U,146U,147U,147U,148U,151U,149U,151U,151U,151U,154U,155U,155U,155U,156U,154U,152U,151U,151U,148U,148U,149U,152U,151U,151U,152U,153U,154U,65535U,65535U,65535U,65535U,65535U,65535U,
190U,182U,168U,163U,162U,164U,165U,164U,166U,166U,165U,163U,163U,161U,159U,156U,155U,155U,153U,151U,150U,146U,144U,141U,139U,139U,139U,139U,138U,135U,134U,134U,133U,133U,133U,133U,130U,125U,124U,135U,156U,173U,170U,163U,154U,137U,119U,115U,119U,121U,121U,125U,131U,135U,138U,139U,139U,141U,143U,144U,144U,143U,144U,145U,144U,143U,144U,144U,146U,148U,146U,147U,147U,148U,151U,152U,151U,152U,152U,150U,148U,148U,148U,147U,147U,148U,148U,148U,150U,150U,151U,153U,65535U,65535U,65535U,65535U,65535U,65535U,
200U,184U,168U,163U,159U,158U,158U,158U,159U,159U,159U,156U,153U,151U,149U,149U,148U,146U,144U,141U,140U,139U,138U,135U,133U,133U,133U,132U,132U,131U,128U,128U,128U,130U,128U,128U,126U,123U,123U,130U,142U,152U,147U,140U,133U,125U,121U,120U,120U,122U,123U,127U,133U,138U,138U,139U,139U,140U,140U,141U,143U,143U,144U,144U,143U,143U,144U,143U,145U,146U,145U,146U,147U,148U,148U,148U,150U,150U,150U,150U,148U,148U,148U,148U,148U,148U,147U,147U,148U,148U,148U,151U,65535U,65535U,65535U,65535U,65535U,65535U,
215U,202U,170U,159U,156U,154U,154U,154U,153U,152U,152U,151U,147U,145U,144U,142U,142U,142U,139U,137U,135U,135U,133U,131U,131U,131U,128U,128U,127U,125U,125U,125U,125U,124U,126U,126U,124U,122U,122U,125U,127U,126U,124U,118U,113U,117U,119U,118U,119U,123U,126U,128U,132U,137U,138U,138U,139U,139U,139U,141U,142U,142U,143U,143U,144U,144U,143U,143U,145U,145U,145U,145U,147U,147U,146U,147U,147U,147U,147U,148U,148U,148U,148U,148U,149U,149U,148U,149U,149U,149U,149U,152U,65535U,65535U,65535U,65535U,65535U,65535U,
204U,193U,172U,155U,151U,149U,148U,146U,145U,143U,145U,144U,139U,137U,138U,138U,137U,137U,135U,133U,131U,131U,131U,128U,128U,128U,126U,126U,125U,123U,122U,123U,123U,123U,125U,125U,123U,121U,120U,121U,122U,119U,112U,106U,103U,104U,105U,108U,117U,123U,124U,125U,130U,134U,134U,135U,137U,137U,137U,139U,140U,141U,140U,140U,141U,141U,141U,141U,142U,144U,143U,144U,145U,145U,145U,145U,146U,146U,146U,147U,147U,147U,147U,147U,148U,148U,148U,149U,149U,149U,151U,151U,65535U,65535U,65535U,65535U,65535U,65535U,
182U,173U,165U,151U,146U,144U,141U,141U,141U,139U,139U,139U,138U,135U,135U,135U,134U,132U,131U,128U,127U,127U,127U,127U,127U,127U,125U,125U,125U,123U,122U,123U,122U,121U,123U,124U,122U,119U,117U,113U,110U,105U,99U,98U,93U,91U,96U,105U,114U,121U,122U,125U,128U,131U,132U,134U,135U,135U,137U,139U,139U,139U,138U,138U,138U,139U,139U,140U,141U,141U,140U,140U,141U,141U,141U,141U,143U,143U,143U,145U,145U,145U,146U,147U,147U,147U,148U,148U,148U,149U,151U,151U,65535U,65535U,65535U,65535U,65535U,65535U,
174U,167U,159U,148U,144U,140U,137U,138U,137U,134U,134U,134U,134U,133U,133U,133U,133U,131U,127U,126U,126U,125U,125U,126U,126U,126U,124U,124U,124U,124U,123U,123U,122U,121U,121U,120U,120U,118U,112U,104U,97U,93U,92U,92U,87U,86U,92U,103U,112U,119U,121U,125U,127U,128U,131U,133U,133U,132U,134U,137U,137U,137U,136U,136U,134U,136U,136U,136U,137U,137U,136U,136U,138U,139U,137U,138U,138U,138U,139U,141U,143U,143U,144U,144U,145U,145U,146U,148U,148U,148U,149U,151U,65535U,65535U,65535U,65535U,65535U,65535U,
179U,163U,153U,146U,141U,134U,132U,130U,130U,130U,128U,130U,130U,130U,130U,130U,130U,128U,125U,124U,124U,123U,123U,124U,124U,124U,124U,124U,124U,124U,124U,123U,121U,120U,120U,119U,115U,112U,107U,99U,93U,91U,90U,90U,89U,90U,92U,103U,111U,115U,118U,124U,127U,128U,128U,130U,131U,131U,130U,132U,135U,135U,133U,133U,134U,134U,134U,134U,133U,133U,133U,133U,134U,135U,134U,134U,137U,137U,137U,139U,139U,139U,139U,140U,140U,141U,144U,146U,146U,146U,147U,148U,65535U,65535U,65535U,65535U,65535U,65535U,
161U,152U,147U,145U,138U,128U,125U,125U,124U,123U,125U,125U,125U,126U,126U,125U,123U,122U,122U,121U,122U,123U,123U,124U,124U,124U,124U,124U,125U,125U,123U,121U,121U,121U,120U,117U,111U,107U,106U,98U,92U,90U,89U,91U,93U,96U,98U,103U,108U,112U,113U,122U,126U,128U,130U,130U,131U,130U,130U,131U,132U,132U,131U,133U,133U,132U,132U,132U,131U,131U,131U,131U,133U,133U,133U,134U,134U,134U,135U,135U,137U,137U,137U,138U,138U,138U,140U,140U,141U,142U,142U,144U,65535U,65535U,65535U,65535U,65535U,65535U,
135U,132U,134U,138U,130U,122U,120U,118U,115U,113U,115U,115U,117U,119U,119U,119U,120U,120U,120U,121U,121U,122U,123U,124U,124U,124U,123U,124U,124U,123U,123U,122U,121U,121U,117U,113U,110U,106U,104U,98U,93U,91U,91U,93U,98U,100U,100U,105U,108U,112U,112U,120U,126U,127U,128U,128U,130U,130U,130U,131U,131U,131U,131U,131U,131U,131U,131U,132U,131U,129U,130U,130U,131U,132U,131U,131U,132U,133U,133U,132U,134U,134U,134U,135U,135U,135U,135U,135U,138U,140U,140U,141U,65535U,65535U,65535U,65535U,65535U,65535U,
119U,117U,117U,122U,119U,113U,111U,110U,106U,104U,105U,107U,112U,113U,114U,114U,115U,115U,118U,118U,118U,119U,120U,122U,122U,122U,122U,122U,121U,121U,121U,119U,119U,119U,114U,111U,107U,105U,103U,97U,93U,92U,96U,99U,101U,104U,106U,107U,110U,112U,114U,122U,126U,126U,127U,127U,128U,128U,128U,130U,130U,128U,128U,128U,128U,128U,130U,130U,129U,129U,127U,126U,126U,127U,127U,127U,130U,130U,128U,128U,130U,130U,131U,131U,131U,131U,131U,132U,134U,135U,135U,138U,65535U,65535U,65535U,65535U,65535U,65535U,
108U,106U,107U,110U,110U,107U,105U,105U,105U,105U,106U,108U,108U,110U,112U,112U,113U,114U,114U,114U,114U,113U,113U,114U,115U,119U,120U,122U,121U,121U,119U,115U,114U,114U,113U,110U,106U,104U,100U,96U,93U,94U,97U,101U,105U,108U,108U,108U,110U,113U,115U,122U,125U,125U,126U,126U,126U,127U,128U,128U,127U,127U,127U,127U,126U,127U,127U,128U,127U,125U,124U,124U,123U,125U,125U,124U,125U,126U,125U,126U,127U,127U,127U,127U,127U,127U,127U,128U,131U,133U,133U,134U,65535U,65535U,65535U,65535U,65535U,65535U,
106U,104U,105U,105U,105U,104U,104U,104U,104U,104U,105U,106U,106U,108U,108U,110U,110U,108U,110U,110U,107U,107U,107U,108U,110U,111U,113U,113U,113U,113U,112U,112U,112U,113U,111U,107U,104U,101U,100U,98U,97U,97U,99U,105U,111U,112U,111U,110U,110U,113U,115U,121U,124U,125U,126U,126U,125U,127U,128U,128U,126U,125U,125U,124U,126U,126U,125U,126U,124U,123U,124U,123U,123U,123U,123U,124U,124U,124U,125U,125U,125U,125U,125U,125U,125U,125U,126U,126U,127U,130U,130U,130U,65535U,65535U,65535U,65535U,65535U,65535U,
105U,104U,103U,103U,103U,100U,101U,103U,104U,106U,106U,104U,105U,105U,106U,106U,106U,105U,105U,104U,103U,104U,105U,106U,106U,107U,107U,108U,110U,111U,111U,112U,112U,112U,110U,107U,105U,103U,101U,100U,100U,101U,104U,107U,113U,113U,112U,110U,110U,113U,115U,120U,122U,123U,125U,125U,125U,126U,126U,126U,124U,123U,123U,123U,125U,125U,124U,124U,123U,123U,124U,123U,123U,123U,123U,122U,123U,123U,124U,124U,124U,124U,123U,124U,124U,124U,123U,125U,125U,125U,125U,126U,65535U,65535U,65535U,65535U,65535U,65535U,
105U,105U,104U,103U,103U,100U,101U,103U,106U,106U,106U,104U,105U,105U,105U,106U,105U,106U,106U,104U,104U,107U,108U,110U,108U,108U,110U,110U,112U,114U,113U,114U,114U,112U,111U,110U,107U,106U,105U,105U,105U,107U,108U,113U,113U,113U,111U,108U,110U,113U,117U,120U,121U,122U,124U,124U,124U,124U,124U,124U,124U,123U,123U,122U,123U,123U,123U,123U,123U,122U,122U,122U,122U,122U,121U,122U,122U,122U,123U,123U,123U,123U,123U,123U,123U,123U,122U,123U,123U,123U,124U,126U,65535U,65535U,65535U,65535U,65535U,65535U,
109U,109U,107U,107U,106U,107U,109U,111U,112U,112U,107U,106U,105U,105U,105U,107U,106U,106U,107U,106U,106U,108U,112U,113U,113U,113U,112U,112U,113U,117U,117U,117U,115U,114U,112U,111U,110U,108U,108U,107U,110U,113U,114U,115U,115U,113U,110U,108U,111U,114U,117U,119U,121U,121U,123U,123U,124U,124U,123U,123U,123U,123U,123U,123U,122U,123U,123U,122U,123U,123U,122U,122U,121U,121U,121U,120U,122U,122U,122U,123U,123U,123U,123U,123U,123U,122U,122U,122U,122U,123U,124U,124U,65535U,65535U,65535U,65535U,65535U,65535U,
112U,112U,113U,113U,113U,112U,114U,117U,115U,114U,112U,110U,108U,107U,107U,108U,108U,110U,110U,108U,110U,112U,114U,118U,118U,118U,115U,115U,117U,119U,119U,118U,118U,117U,114U,113U,111U,111U,111U,111U,113U,115U,118U,118U,118U,114U,113U,112U,113U,117U,119U,120U,121U,122U,122U,123U,124U,124U,123U,123U,123U,123U,123U,123U,122U,123U,123U,122U,123U,123U,121U,121U,121U,121U,120U,121U,122U,122U,122U,123U,123U,123U,123U,123U,123U,122U,122U,123U,123U,123U,124U,124U,65535U,65535U,65535U,65535U,65535U,65535U,
115U,115U,117U,118U,118U,117U,118U,118U,119U,119U,115U,114U,112U,110U,111U,111U,112U,113U,112U,112U,112U,113U,115U,118U,118U,118U,118U,118U,118U,120U,120U,120U,119U,119U,118U,115U,114U,113U,113U,114U,115U,118U,118U,118U,117U,117U,115U,115U,118U,119U,121U,121U,122U,123U,122U,123U,124U,124U,123U,123U,123U,123U,123U,123U,122U,123U,123U,122U,122U,122U,121U,121U,121U,121U,120U,121U,123U,123U,123U,124U,124U,124U,124U,124U,124U,123U,123U,124U,124U,124U,124U,124U,65535U,65535U,65535U,65535U,65535U,65535U,
118U,118U,118U,119U,119U,119U,119U,119U,118U,118U,118U,117U,115U,114U,115U,115U,115U,117U,115U,115U,114U,115U,118U,118U,118U,119U,118U,119U,119U,120U,120U,119U,119U,119U,118U,115U,115U,115U,115U,115U,117U,118U,118U,117U,117U,117U,115U,118U,120U,122U,123U,122U,123U,123U,123U,124U,125U,123U,123U,123U,123U,123U,123U,124U,124U,124U,123U,124U,124U,123U,123U,121U,121U,121U,121U,122U,124U,125U,125U,126U,126U,125U,125U,125U,125U,125U,125U,125U,125U,125U,126U,125U,65535U,65535U,65535U,65535U,65535U,65535U,
122U,121U,119U,120U,120U,120U,120U,120U,119U,120U,119U,119U,118U,118U,118U,119U,118U,118U,117U,117U,117U,118U,118U,118U,118U,119U,119U,119U,120U,120U,120U,120U,119U,120U,119U,117U,117U,118U,118U,118U,118U,118U,118U,118U,118U,115U,117U,118U,121U,122U,123U,124U,124U,124U,125U,126U,126U,125U,125U,125U,125U,125U,125U,125U,125U,125U,125U,125U,125U,123U,123U,123U,122U,123U,123U,123U,125U,126U,126U,126U,126U,126U,126U,126U,126U,125U,125U,126U,126U,126U,127U,126U,65535U,65535U,65535U,65535U,65535U,65535U,
121U,120U,120U,120U,121U,121U,121U,120U,121U,121U,121U,121U,120U,118U,118U,119U,120U,119U,119U,118U,118U,118U,118U,119U,119U,119U,119U,119U,120U,120U,121U,120U,119U,120U,120U,119U,119U,120U,119U,119U,119U,119U,120U,120U,120U,119U,118U,119U,122U,123U,124U,124U,125U,125U,126U,126U,126U,126U,126U,126U,126U,126U,126U,126U,126U,126U,126U,126U,125U,125U,125U,123U,124U,124U,124U,124U,125U,126U,126U,126U,126U,126U,126U,126U,127U,127U,127U,128U,128U,127U,127U,127U,65535U,65535U,65535U,65535U,65535U,65535U,
120U,120U,121U,121U,121U,121U,120U,121U,121U,121U,121U,121U,120U,120U,120U,120U,119U,119U,120U,119U,119U,119U,119U,120U,120U,120U,120U,120U,121U,121U,121U,121U,121U,121U,120U,119U,120U,121U,121U,120U,120U,121U,121U,121U,121U,121U,120U,121U,123U,124U,125U,126U,126U,127U,127U,127U,126U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,126U,126U,126U,125U,125U,125U,127U,127U,126U,128U,128U,128U,128U,128U,130U,130U,128U,130U,130U,128U,128U,128U,65535U,65535U,65535U,65535U,65535U,65535U,
119U,120U,121U,121U,121U,120U,121U,122U,122U,122U,122U,121U,121U,122U,122U,120U,119U,120U,121U,121U,121U,121U,121U,120U,120U,121U,121U,121U,121U,121U,121U,121U,121U,121U,120U,120U,120U,121U,121U,120U,120U,121U,121U,121U,122U,122U,122U,124U,126U,126U,126U,127U,128U,130U,130U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,127U,126U,126U,125U,126U,127U,127U,128U,128U,128U,128U,128U,128U,130U,130U,130U,128U,130U,130U,131U,131U,131U,131U,65535U,65535U,65535U,65535U,65535U,65535U,
119U,120U,119U,120U,121U,121U,121U,122U,122U,122U,122U,122U,120U,120U,120U,119U,119U,120U,121U,121U,121U,121U,121U,121U,121U,122U,121U,122U,122U,121U,121U,121U,121U,121U,121U,121U,121U,121U,121U,122U,121U,121U,121U,122U,123U,123U,124U,126U,127U,127U,128U,128U,128U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,128U,128U,128U,127U,127U,128U,128U,128U,128U,128U,128U,128U,128U,128U,130U,130U,130U,130U,131U,131U,131U,132U,65535U,65535U,65535U,65535U,65535U,65535U,
120U,120U,120U,121U,122U,123U,123U,123U,123U,122U,122U,122U,121U,119U,119U,120U,119U,119U,120U,121U,121U,121U,122U,122U,122U,123U,123U,122U,122U,122U,122U,121U,121U,122U,121U,121U,121U,121U,121U,122U,122U,121U,122U,123U,124U,124U,124U,126U,127U,126U,127U,128U,128U,128U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,130U,128U,128U,128U,127U,128U,128U,128U,127U,128U,131U,131U,131U,131U,131U,131U,131U,131U,131U,131U,132U,132U,65535U,65535U,65535U,65535U,65535U,65535U,
123U,124U,124U,124U,124U,125U,125U,125U,124U,124U,123U,124U,124U,122U,121U,121U,120U,120U,121U,121U,121U,123U,123U,123U,123U,123U,123U,123U,123U,122U,122U,122U,122U,122U,122U,121U,121U,121U,121U,122U,122U,123U,123U,123U,124U,124U,125U,126U,126U,127U,127U,127U,130U,130U,130U,130U,128U,128U,128U,128U,128U,128U,128U,128U,128U,128U,127U,127U,127U,127U,130U,127U,127U,127U,128U,128U,128U,128U,130U,130U,131U,131U,131U,131U,131U,131U,131U,131U,131U,131U,132U,132U,65535U,65535U,65535U,65535U,65535U,65535U,
131U,133U,130U,131U,132U,132U,131U,128U,126U,126U,126U,126U,125U,124U,124U,123U,122U,123U,121U,121U,123U,123U,123U,123U,123U,123U,123U,123U,123U,123U,122U,123U,122U,122U,122U,122U,122U,121U,121U,122U,122U,123U,123U,124U,125U,125U,126U,127U,127U,127U,127U,127U,130U,130U,130U,130U,131U,131U,131U,131U,131U,131U,131U,131U,131U,130U,129U,129U,130U,130U,130U,127U,127U,127U,128U,128U,128U,128U,130U,130U,130U,130U,131U,131U,131U,131U,131U,131U,132U,132U,133U,133U,65535U,65535U,65535U,65535U,65535U,65535U,
141U,138U,138U,135U,137U,137U,134U,132U,128U,127U,127U,127U,127U,126U,126U,125U,123U,123U,122U,123U,124U,123U,123U,124U,124U,124U,123U,123U,123U,124U,124U,123U,123U,122U,122U,122U,122U,122U,121U,121U,122U,123U,123U,124U,126U,126U,125U,127U,127U,127U,127U,128U,130U,130U,130U,131U,131U,131U,131U,131U,131U,131U,131U,131U,131U,130U,129U,130U,129U,129U,128U,127U,127U,127U,127U,127U,128U,128U,130U,130U,131U,131U,133U,133U,133U,133U,133U,133U,133U,134U,135U,135U,65535U,65535U,65535U,65535U,65535U,65535U,
145U,142U,141U,139U,139U,139U,138U,135U,132U,128U,128U,131U,128U,127U,128U,127U,125U,124U,124U,124U,123U,124U,125U,124U,124U,125U,125U,124U,124U,124U,124U,125U,124U,122U,123U,122U,122U,122U,121U,121U,122U,123U,124U,125U,126U,127U,126U,127U,127U,127U,128U,128U,130U,130U,130U,131U,132U,132U,132U,131U,132U,132U,131U,131U,131U,130U,129U,129U,127U,127U,128U,127U,127U,128U,128U,130U,131U,130U,132U,132U,133U,133U,133U,133U,134U,135U,135U,135U,135U,137U,138U,137U,65535U,65535U,65535U,65535U,65535U,65535U,
146U,145U,142U,141U,141U,141U,139U,137U,135U,133U,131U,133U,131U,131U,131U,130U,128U,127U,126U,126U,125U,126U,126U,126U,126U,127U,126U,125U,124U,125U,125U,125U,125U,123U,125U,124U,122U,121U,121U,121U,122U,123U,124U,125U,126U,127U,127U,128U,128U,128U,128U,128U,130U,131U,131U,131U,132U,132U,132U,132U,132U,132U,131U,131U,130U,128U,127U,129U,127U,127U,130U,128U,130U,130U,131U,132U,133U,134U,134U,134U,135U,135U,135U,135U,137U,137U,137U,138U,138U,138U,139U,138U,65535U,65535U,65535U,65535U,65535U,65535U,
146U,147U,146U,144U,144U,141U,139U,139U,139U,138U,133U,134U,133U,133U,133U,132U,131U,130U,128U,127U,127U,127U,127U,128U,128U,130U,128U,127U,126U,126U,127U,126U,125U,125U,125U,125U,124U,123U,122U,122U,123U,123U,125U,125U,126U,127U,127U,130U,130U,130U,130U,130U,131U,132U,132U,132U,132U,132U,132U,132U,132U,132U,131U,131U,131U,130U,129U,130U,129U,127U,130U,130U,131U,132U,132U,133U,135U,137U,137U,138U,138U,138U,139U,139U,139U,139U,139U,139U,139U,139U,139U,139U,65535U,65535U,65535U,65535U,65535U,65535U,
146U,148U,148U,146U,144U,141U,140U,141U,140U,139U,135U,135U,135U,134U,135U,134U,132U,131U,130U,130U,130U,130U,130U,131U,131U,132U,132U,131U,130U,130U,129U,127U,127U,126U,126U,126U,124U,123U,122U,122U,123U,124U,124U,125U,126U,127U,128U,128U,128U,130U,130U,130U,131U,131U,132U,132U,132U,132U,132U,132U,132U,133U,133U,132U,132U,131U,130U,130U,130U,131U,131U,131U,132U,132U,135U,135U,137U,139U,140U,140U,140U,140U,140U,140U,140U,140U,140U,139U,139U,139U,139U,138U,65535U,65535U,65535U,65535U,65535U,65535U,
146U,148U,149U,147U,145U,142U,144U,144U,142U,141U,139U,139U,138U,138U,138U,137U,134U,134U,132U,132U,131U,131U,132U,132U,131U,132U,133U,131U,131U,131U,130U,129U,129U,127U,127U,127U,125U,123U,121U,121U,122U,123U,124U,125U,126U,127U,128U,128U,128U,130U,130U,130U,131U,131U,131U,132U,132U,133U,132U,133U,133U,133U,132U,132U,132U,131U,130U,131U,131U,131U,131U,132U,132U,132U,135U,135U,137U,139U,140U,140U,140U,140U,140U,140U,140U,140U,139U,139U,138U,139U,138U,138U,65535U,65535U,65535U,65535U,65535U,65535U,
147U,150U,151U,149U,147U,146U,146U,145U,142U,141U,141U,141U,140U,140U,140U,138U,138U,138U,135U,135U,134U,134U,134U,134U,133U,133U,133U,131U,130U,130U,130U,129U,129U,129U,129U,127U,125U,123U,122U,122U,123U,124U,124U,125U,127U,128U,128U,127U,128U,130U,130U,131U,131U,131U,131U,132U,132U,133U,133U,133U,133U,133U,132U,132U,132U,132U,132U,132U,132U,132U,132U,133U,133U,133U,132U,133U,134U,135U,135U,135U,138U,139U,139U,139U,139U,139U,138U,138U,138U,138U,138U,138U,65535U,65535U,65535U,65535U,65535U,65535U,
146U,148U,151U,151U,149U,149U,148U,146U,144U,141U,140U,141U,140U,140U,140U,138U,139U,139U,137U,135U,137U,134U,134U,135U,134U,133U,132U,132U,132U,131U,130U,131U,130U,130U,131U,127U,125U,124U,124U,124U,125U,125U,126U,127U,128U,128U,127U,127U,127U,128U,130U,130U,131U,131U,132U,132U,132U,133U,133U,133U,133U,134U,134U,133U,133U,133U,133U,133U,133U,133U,133U,133U,133U,133U,132U,132U,133U,133U,132U,133U,135U,137U,138U,138U,138U,138U,138U,138U,137U,138U,137U,135U,65535U,65535U,65535U,65535U,65535U,65535U,
141U,144U,146U,146U,146U,146U,147U,146U,141U,139U,138U,140U,141U,140U,140U,139U,139U,139U,137U,137U,138U,135U,135U,135U,135U,134U,133U,133U,132U,132U,133U,133U,131U,131U,131U,129U,128U,128U,125U,125U,126U,128U,128U,130U,131U,130U,127U,127U,126U,127U,127U,128U,131U,132U,133U,134U,133U,133U,133U,133U,133U,134U,134U,133U,133U,133U,133U,133U,133U,133U,133U,133U,133U,133U,132U,132U,132U,132U,130U,131U,133U,135U,137U,137U,138U,138U,138U,138U,137U,137U,137U,135U,65535U,65535U,65535U,65535U,65535U,65535U,
139U,138U,139U,140U,139U,139U,141U,140U,139U,138U,137U,138U,139U,139U,139U,138U,138U,138U,137U,135U,135U,135U,135U,134U,135U,134U,134U,133U,132U,132U,133U,133U,132U,131U,131U,130U,131U,131U,128U,130U,131U,131U,132U,133U,134U,133U,130U,127U,126U,126U,127U,128U,132U,134U,135U,135U,135U,135U,135U,134U,134U,134U,133U,133U,133U,134U,134U,133U,133U,133U,134U,134U,135U,135U,134U,134U,134U,132U,130U,131U,133U,134U,135U,137U,137U,137U,137U,137U,137U,137U,135U,134U,65535U,65535U,65535U,65535U,65535U,65535U,
1 108U 107U 107U 108U 107U 105U 105U 105U 105U 105U 106U 107U 108U 108U 108U 108U 108U 111U 111U 111U 110U 108U 108U 108U 110U 112U 117U 126U 144U 162U 172U 175U 175U 175U 172U 172U 172U 173U 174U 175U 174U 176U 176U 175U 175U 175U 175U 175U 175U 175U 175U 175U 178U 175U 174U 174U 174U 175U 176U 174U 174U 174U 172U 172U 169U 170U 170U 161U 134U 108U 93U 89U 93U 98U 97U 97U 96U 93U 91U 91U 92U 94U 92U 91U 90U 89U 90U 91U 93U 94U 96U 94U 65535U 65535U 65535U 65535U 65535U 65535U
2 113U 112U 113U 114U 113U 112U 112U 111U 111U 111U 111U 112U 112U 112U 112U 112U 112U 114U 114U 116U 117U 117U 114U 116U 116U 121U 133U 147U 160U 169U 174U 175U 175U 175U 174U 173U 174U 175U 174U 174U 175U 174U 174U 175U 175U 175U 175U 175U 175U 175U 175U 175U 176U 175U 174U 176U 176U 175U 174U 173U 173U 173U 172U 171U 169U 168U 167U 151U 126U 109U 102U 102U 104U 105U 106U 105U 103U 102U 103U 103U 102U 102U 100U 98U 98U 99U 100U 102U 103U 103U 104U 103U 65535U 65535U 65535U 65535U 65535U 65535U
3 118U 117U 119U 118U 117U 117U 117U 117U 117U 118U 117U 117U 117U 116U 116U 116U 116U 117U 118U 117U 119U 120U 120U 121U 125U 137U 150U 162U 171U 175U 176U 176U 176U 175U 175U 175U 176U 176U 176U 175U 175U 174U 174U 175U 175U 175U 175U 175U 174U 174U 175U 175U 175U 175U 176U 178U 178U 178U 178U 175U 175U 173U 171U 171U 168U 166U 159U 143U 123U 112U 111U 113U 113U 111U 114U 113U 110U 109U 109U 110U 109U 106U 106U 105U 105U 107U 107U 110U 109U 109U 107U 106U 65535U 65535U 65535U 65535U 65535U 65535U
4 120U 119U 118U 117U 116U 116U 117U 118U 119U 120U 120U 119U 119U 117U 118U 120U 121U 121U 120U 119U 118U 121U 122U 122U 136U 152U 162U 169U 174U 178U 178U 176U 175U 175U 174U 174U 175U 175U 175U 175U 174U 174U 174U 174U 174U 174U 174U 174U 173U 173U 174U 174U 175U 176U 178U 178U 178U 179U 180U 179U 179U 174U 169U 166U 164U 162U 153U 137U 122U 117U 118U 118U 118U 119U 121U 120U 119U 118U 116U 113U 113U 114U 116U 114U 114U 116U 117U 119U 118U 118U 119U 118U 65535U 65535U 65535U 65535U 65535U 65535U
5 122U 122U 122U 121U 121U 122U 124U 125U 125U 126U 129U 127U 127U 129U 130U 129U 130U 132U 131U 131U 132U 133U 134U 136U 147U 161U 167U 173U 175U 175U 178U 178U 174U 175U 177U 177U 175U 177U 175U 175U 174U 175U 177U 174U 174U 174U 174U 174U 174U 174U 174U 174U 176U 178U 178U 178U 179U 179U 181U 181U 179U 174U 171U 165U 161U 160U 154U 143U 134U 134U 134U 134U 134U 136U 137U 138U 139U 139U 136U 131U 132U 136U 137U 136U 132U 132U 132U 134U 134U 136U 143U 143U 65535U 65535U 65535U 65535U 65535U 65535U
6 138U 143U 147U 150U 147U 147U 148U 150U 152U 153U 154U 152U 150U 151U 152U 150U 150U 152U 152U 153U 157U 159U 159U 160U 162U 166U 171U 174U 175U 175U 176U 176U 177U 177U 179U 178U 177U 177U 177U 177U 177U 175U 175U 175U 174U 174U 174U 174U 174U 174U 174U 175U 176U 176U 176U 176U 176U 176U 180U 180U 176U 174U 171U 166U 161U 161U 164U 164U 161U 161U 161U 161U 161U 161U 162U 165U 165U 167U 165U 159U 160U 165U 166U 166U 162U 161U 160U 161U 161U 162U 172U 172U 65535U 65535U 65535U 65535U 65535U 65535U
7 162U 164U 169U 174U 176U 179U 179U 179U 181U 181U 179U 179U 176U 175U 175U 172U 172U 174U 174U 174U 175U 178U 176U 175U 173U 171U 172U 174U 175U 176U 178U 179U 178U 178U 179U 179U 177U 177U 177U 177U 177U 175U 174U 175U 175U 175U 174U 174U 174U 174U 174U 175U 176U 176U 175U 175U 174U 174U 175U 174U 172U 169U 169U 166U 162U 165U 173U 180U 183U 183U 183U 182U 181U 181U 183U 183U 183U 183U 183U 180U 181U 185U 185U 183U 181U 180U 179U 180U 180U 181U 185U 186U 65535U 65535U 65535U 65535U 65535U 65535U
8 168U 161U 169U 179U 189U 195U 195U 193U 192U 190U 189U 192U 192U 190U 188U 187U 188U 188U 189U 186U 184U 183U 179U 176U 175U 173U 173U 174U 174U 177U 178U 178U 178U 178U 179U 179U 179U 179U 177U 178U 177U 174U 175U 177U 177U 174U 174U 174U 174U 174U 175U 177U 176U 174U 173U 173U 172U 172U 171U 169U 168U 167U 168U 166U 164U 168U 178U 185U 187U 188U 188U 188U 187U 188U 189U 189U 187U 188U 189U 188U 186U 187U 187U 186U 186U 185U 182U 183U 185U 185U 185U 186U 65535U 65535U 65535U 65535U 65535U 65535U
9 166U 158U 165U 172U 181U 188U 189U 190U 189U 188U 189U 192U 193U 193U 193U 190U 192U 192U 193U 191U 187U 182U 176U 174U 174U 175U 174U 174U 174U 177U 177U 177U 178U 179U 180U 180U 182U 180U 179U 178U 177U 175U 175U 175U 175U 174U 174U 173U 173U 174U 175U 175U 175U 173U 173U 172U 172U 172U 171U 171U 169U 169U 168U 166U 166U 168U 175U 180U 181U 181U 181U 183U 185U 186U 187U 186U 186U 187U 187U 187U 185U 183U 185U 185U 185U 183U 183U 183U 183U 185U 186U 186U 65535U 65535U 65535U 65535U 65535U 65535U
10 173U 169U 168U 169U 169U 169U 171U 173U 175U 179U 187U 192U 190U 190U 192U 192U 190U 192U 193U 189U 184U 180U 174U 173U 174U 174U 174U 177U 175U 177U 178U 179U 180U 180U 181U 181U 181U 179U 179U 179U 179U 177U 177U 175U 175U 175U 175U 174U 173U 175U 175U 174U 174U 173U 172U 171U 171U 172U 172U 171U 171U 171U 168U 165U 165U 167U 171U 175U 179U 179U 179U 182U 183U 185U 186U 186U 187U 187U 185U 183U 183U 185U 185U 185U 185U 185U 186U 186U 186U 186U 187U 188U 65535U 65535U 65535U 65535U 65535U 65535U
11 183U 183U 181U 178U 171U 161U 155U 154U 161U 169U 183U 193U 192U 190U 192U 193U 192U 192U 193U 187U 182U 179U 174U 173U 174U 174U 177U 178U 178U 179U 179U 180U 181U 182U 182U 181U 181U 180U 179U 180U 180U 178U 177U 177U 176U 175U 175U 176U 177U 178U 177U 174U 174U 174U 173U 172U 172U 172U 173U 172U 169U 168U 168U 168U 167U 168U 172U 176U 180U 181U 182U 185U 186U 186U 187U 188U 189U 188U 185U 185U 186U 187U 188U 187U 186U 187U 189U 188U 189U 188U 189U 190U 65535U 65535U 65535U 65535U 65535U 65535U
12 190U 189U 190U 193U 181U 167U 152U 147U 155U 165U 169U 183U 193U 192U 190U 192U 194U 193U 192U 185U 176U 171U 171U 171U 174U 176U 177U 178U 180U 180U 181U 181U 182U 185U 183U 182U 181U 179U 180U 179U 178U 177U 176U 178U 178U 176U 175U 176U 179U 181U 183U 182U 181U 179U 177U 176U 176U 176U 176U 176U 173U 167U 168U 172U 171U 172U 174U 177U 180U 181U 185U 186U 186U 187U 186U 186U 188U 188U 189U 189U 187U 187U 187U 187U 186U 187U 188U 187U 187U 188U 189U 189U 65535U 65535U 65535U 65535U 65535U 65535U
13 190U 190U 190U 194U 192U 185U 173U 162U 154U 148U 148U 162U 183U 193U 192U 190U 192U 189U 186U 180U 172U 165U 164U 166U 171U 178U 178U 178U 179U 180U 180U 180U 181U 180U 180U 182U 178U 175U 176U 176U 174U 174U 176U 178U 179U 178U 175U 178U 180U 180U 182U 182U 180U 173U 172U 173U 172U 170U 169U 169U 169U 166U 164U 164U 165U 167U 168U 170U 173U 177U 179U 181U 181U 181U 181U 182U 186U 186U 187U 187U 186U 185U 185U 185U 186U 185U 185U 185U 185U 186U 187U 186U 65535U 65535U 65535U 65535U 65535U 65535U
14 194U 194U 195U 197U 197U 194U 193U 182U 159U 139U 141U 157U 179U 195U 199U 197U 194U 190U 188U 181U 178U 174U 174U 174U 178U 180U 180U 180U 181U 181U 181U 180U 178U 176U 178U 180U 177U 178U 180U 181U 180U 178U 180U 179U 181U 185U 185U 182U 181U 180U 179U 176U 173U 171U 171U 169U 167U 165U 164U 162U 164U 160U 157U 158U 163U 165U 168U 172U 174U 178U 178U 179U 182U 185U 185U 184U 182U 182U 182U 184U 186U 187U 189U 192U 192U 192U 192U 192U 193U 192U 193U 193U 65535U 65535U 65535U 65535U 65535U 65535U
15 213U 213U 211U 211U 210U 207U 210U 195U 172U 155U 171U 187U 200U 210U 216U 215U 210U 207U 206U 201U 201U 202U 201U 201U 199U 197U 195U 195U 195U 196U 196U 195U 196U 195U 194U 193U 193U 194U 196U 196U 195U 194U 200U 200U 203U 207U 207U 203U 201U 200U 199U 197U 196U 199U 199U 189U 188U 192U 192U 188U 172U 154U 161U 180U 189U 192U 193U 195U 198U 200U 201U 200U 207U 209U 207U 205U 203U 203U 203U 205U 207U 209U 210U 213U 213U 213U 213U 213U 214U 214U 215U 215U 65535U 65535U 65535U 65535U 65535U 65535U
16 236U 235U 234U 234U 233U 233U 218U 200U 193U 199U 218U 230U 231U 230U 234U 235U 235U 236U 235U 235U 236U 237U 237U 237U 232U 223U 214U 213U 214U 214U 215U 219U 221U 223U 225U 225U 227U 228U 226U 225U 225U 225U 225U 225U 226U 227U 230U 233U 233U 231U 230U 230U 229U 229U 228U 227U 221U 221U 222U 222U 182U 153U 172U 208U 225U 226U 227U 227U 227U 228U 228U 228U 230U 232U 230U 229U 229U 229U 230U 232U 232U 232U 232U 232U 234U 236U 237U 238U 238U 237U 237U 237U 65535U 65535U 65535U 65535U 65535U 65535U
17 239U 239U 240U 240U 240U 240U 221U 200U 207U 223U 240U 243U 240U 238U 238U 240U 241U 240U 240U 237U 236U 236U 235U 233U 223U 214U 199U 199U 200U 201U 203U 208U 214U 220U 221U 221U 223U 223U 222U 221U 220U 220U 219U 220U 221U 221U 223U 226U 227U 229U 228U 228U 227U 226U 226U 226U 226U 224U 220U 213U 183U 159U 184U 223U 239U 238U 238U 238U 238U 238U 237U 238U 235U 233U 230U 230U 230U 229U 230U 230U 232U 233U 233U 234U 236U 238U 238U 238U 237U 236U 235U 233U 65535U 65535U 65535U 65535U 65535U 65535U
18 220U 221U 223U 224U 226U 220U 196U 176U 183U 202U 222U 230U 224U 222U 222U 222U 220U 216U 214U 211U 207U 204U 202U 196U 191U 186U 185U 184U 182U 181U 181U 182U 186U 189U 192U 194U 196U 195U 193U 193U 192U 191U 191U 191U 192U 192U 193U 194U 195U 199U 199U 199U 199U 197U 197U 196U 201U 196U 185U 172U 160U 157U 183U 210U 222U 220U 218U 220U 221U 222U 221U 220U 213U 208U 206U 208U 208U 208U 207U 207U 208U 209U 212U 212U 213U 212U 209U 208U 207U 207U 207U 206U 65535U 65535U 65535U 65535U 65535U 65535U
19 193U 193U 199U 203U 201U 192U 172U 152U 150U 164U 190U 206U 202U 199U 197U 195U 193U 190U 192U 193U 193U 190U 186U 182U 180U 181U 181U 180U 178U 175U 177U 174U 175U 175U 177U 178U 181U 180U 178U 179U 179U 179U 178U 178U 179U 179U 179U 180U 182U 182U 183U 182U 181U 180U 179U 179U 179U 173U 167U 158U 153U 157U 181U 194U 197U 194U 193U 193U 192U 192U 193U 193U 191U 189U 192U 194U 194U 192U 189U 189U 189U 191U 192U 193U 191U 187U 185U 184U 185U 186U 187U 188U 65535U 65535U 65535U 65535U 65535U 65535U
20 181U 182U 186U 189U 187U 179U 158U 141U 133U 143U 164U 186U 190U 188U 186U 181U 179U 179U 178U 181U 183U 183U 186U 186U 186U 187U 187U 186U 185U 184U 180U 182U 181U 180U 180U 179U 180U 181U 181U 183U 183U 185U 183U 183U 182U 182U 181U 181U 182U 181U 181U 180U 180U 179U 178U 174U 171U 164U 161U 161U 164U 171U 181U 189U 192U 189U 188U 187U 185U 185U 187U 188U 188U 189U 189U 191U 188U 186U 185U 184U 184U 184U 185U 185U 185U 185U 185U 185U 186U 187U 188U 189U 65535U 65535U 65535U 65535U 65535U 65535U
21 179U 180U 181U 181U 179U 171U 151U 141U 139U 147U 164U 179U 183U 182U 181U 181U 181U 182U 185U 185U 187U 188U 187U 187U 186U 187U 186U 186U 186U 185U 184U 184U 182U 182U 181U 181U 183U 183U 185U 185U 185U 185U 183U 185U 185U 183U 182U 182U 181U 182U 180U 181U 180U 180U 179U 172U 162U 155U 150U 158U 173U 182U 189U 192U 193U 193U 192U 187U 189U 192U 190U 192U 192U 192U 191U 191U 189U 189U 188U 187U 187U 188U 191U 191U 193U 193U 192U 191U 191U 191U 192U 193U 65535U 65535U 65535U 65535U 65535U 65535U
22 178U 178U 180U 178U 175U 166U 151U 146U 155U 166U 179U 181U 180U 180U 181U 182U 183U 185U 185U 186U 186U 187U 187U 187U 186U 187U 186U 186U 186U 185U 185U 185U 184U 184U 181U 181U 183U 183U 183U 183U 183U 183U 182U 182U 182U 183U 182U 182U 182U 182U 181U 181U 180U 180U 180U 173U 161U 150U 145U 157U 174U 186U 189U 189U 191U 188U 187U 186U 188U 189U 189U 190U 191U 188U 188U 191U 191U 191U 189U 188U 188U 189U 192U 192U 193U 193U 191U 191U 191U 191U 193U 194U 65535U 65535U 65535U 65535U 65535U 65535U
23 176U 176U 178U 175U 172U 165U 159U 159U 165U 173U 186U 181U 178U 178U 181U 181U 183U 185U 186U 187U 188U 188U 188U 187U 186U 187U 186U 186U 186U 186U 186U 185U 185U 184U 182U 181U 183U 183U 183U 182U 182U 183U 182U 182U 182U 183U 182U 182U 182U 182U 182U 181U 180U 181U 182U 176U 162U 150U 146U 158U 176U 187U 189U 191U 191U 187U 187U 188U 187U 187U 189U 193U 191U 188U 189U 192U 191U 189U 189U 189U 189U 191U 189U 192U 193U 193U 192U 193U 193U 193U 194U 195U 65535U 65535U 65535U 65535U 65535U 65535U
24 179U 180U 179U 175U 173U 167U 167U 168U 171U 173U 174U 178U 176U 179U 183U 183U 183U 185U 187U 187U 188U 188U 189U 189U 188U 188U 187U 187U 186U 186U 186U 186U 185U 185U 182U 182U 182U 182U 183U 183U 182U 183U 183U 182U 182U 182U 182U 182U 182U 182U 182U 181U 181U 181U 182U 178U 162U 151U 150U 160U 176U 187U 192U 193U 192U 190U 190U 190U 189U 189U 190U 192U 191U 189U 191U 192U 192U 192U 191U 191U 191U 191U 192U 192U 193U 193U 194U 194U 195U 195U 195U 195U 65535U 65535U 65535U 65535U 65535U 65535U
25 180U 181U 180U 179U 175U 173U 168U 159U 155U 157U 162U 172U 176U 180U 183U 183U 186U 186U 187U 187U 187U 188U 189U 189U 188U 188U 187U 187U 186U 186U 186U 186U 185U 185U 184U 184U 184U 182U 183U 183U 182U 182U 182U 181U 182U 182U 182U 182U 182U 182U 181U 181U 181U 180U 181U 178U 165U 155U 158U 165U 179U 188U 192U 194U 193U 192U 190U 190U 190U 190U 190U 190U 188U 188U 189U 191U 192U 192U 191U 191U 191U 191U 192U 192U 192U 193U 194U 194U 195U 195U 196U 196U 65535U 65535U 65535U 65535U 65535U 65535U
26 181U 181U 181U 181U 179U 175U 171U 154U 138U 137U 146U 165U 176U 181U 183U 183U 186U 188U 186U 186U 187U 188U 188U 188U 188U 188U 187U 187U 186U 186U 186U 186U 186U 185U 184U 184U 185U 184U 185U 183U 182U 182U 182U 181U 182U 182U 182U 182U 182U 182U 181U 181U 180U 180U 179U 175U 172U 164U 168U 173U 180U 186U 192U 193U 192U 192U 190U 190U 190U 189U 188U 189U 187U 188U 192U 191U 191U 192U 192U 192U 192U 192U 192U 192U 192U 193U 194U 194U 195U 196U 196U 196U 65535U 65535U 65535U 65535U 65535U 65535U
27 180U 181U 180U 180U 179U 178U 174U 164U 146U 139U 145U 161U 176U 182U 183U 183U 186U 187U 186U 186U 187U 187U 188U 188U 188U 188U 186U 186U 186U 185U 185U 185U 185U 184U 184U 184U 184U 182U 183U 183U 182U 182U 182U 182U 182U 182U 182U 182U 182U 182U 181U 180U 181U 181U 180U 178U 174U 172U 174U 178U 180U 186U 192U 193U 192U 192U 192U 190U 190U 188U 188U 188U 186U 188U 191U 191U 191U 192U 192U 192U 192U 192U 192U 192U 192U 193U 194U 194U 195U 196U 196U 196U 65535U 65535U 65535U 65535U 65535U 65535U
28 182U 180U 179U 179U 179U 179U 176U 176U 167U 158U 154U 165U 175U 182U 183U 185U 185U 186U 186U 186U 186U 187U 188U 188U 188U 188U 186U 186U 186U 185U 185U 185U 185U 184U 184U 184U 184U 182U 183U 182U 182U 182U 181U 181U 182U 182U 181U 181U 181U 181U 180U 180U 182U 182U 181U 178U 175U 174U 175U 178U 182U 187U 192U 192U 192U 192U 192U 190U 188U 187U 186U 186U 186U 187U 189U 189U 191U 191U 192U 192U 192U 192U 192U 192U 192U 193U 193U 194U 195U 195U 196U 194U 65535U 65535U 65535U 65535U 65535U 65535U
29 183U 182U 180U 179U 180U 181U 179U 179U 173U 166U 165U 168U 178U 185U 185U 185U 185U 185U 186U 186U 187U 187U 187U 187U 187U 187U 186U 186U 185U 185U 185U 185U 185U 184U 184U 184U 184U 182U 183U 182U 182U 182U 181U 181U 181U 181U 181U 181U 181U 181U 181U 182U 181U 181U 181U 180U 176U 176U 178U 179U 183U 189U 192U 192U 192U 190U 189U 188U 187U 186U 185U 186U 186U 187U 188U 189U 191U 191U 192U 192U 192U 192U 192U 192U 192U 192U 193U 193U 194U 194U 194U 193U 65535U 65535U 65535U 65535U 65535U 65535U
30 183U 182U 180U 180U 180U 179U 176U 174U 171U 167U 168U 175U 182U 185U 185U 185U 185U 185U 185U 185U 186U 187U 187U 187U 187U 187U 185U 185U 185U 184U 184U 184U 184U 184U 182U 182U 182U 182U 183U 182U 182U 182U 181U 181U 181U 181U 180U 180U 180U 180U 178U 178U 180U 179U 178U 178U 174U 176U 179U 181U 186U 190U 192U 192U 192U 189U 188U 188U 187U 186U 186U 186U 186U 187U 189U 189U 191U 191U 191U 192U 192U 192U 192U 192U 192U 192U 193U 193U 193U 192U 193U 193U 65535U 65535U 65535U 65535U 65535U 65535U
31 185U 185U 182U 180U 176U 174U 172U 172U 172U 171U 172U 179U 185U 185U 185U 185U 185U 185U 185U 185U 186U 187U 187U 187U 187U 187U 185U 185U 185U 184U 184U 184U 184U 182U 182U 182U 182U 181U 182U 182U 181U 181U 181U 181U 181U 181U 180U 180U 179U 179U 175U 173U 171U 171U 169U 169U 169U 175U 180U 183U 186U 190U 192U 190U 190U 189U 188U 188U 187U 187U 187U 188U 187U 188U 188U 189U 191U 191U 191U 191U 192U 192U 192U 192U 192U 192U 191U 192U 193U 192U 193U 193U 65535U 65535U 65535U 65535U 65535U 65535U
32 187U 185U 181U 178U 172U 169U 169U 172U 173U 174U 179U 181U 185U 185U 185U 185U 185U 185U 185U 186U 186U 186U 187U 187U 187U 187U 185U 185U 185U 184U 184U 184U 184U 182U 182U 182U 182U 181U 182U 182U 181U 181U 181U 181U 180U 180U 179U 179U 178U 175U 173U 171U 167U 161U 162U 164U 167U 175U 182U 186U 187U 188U 189U 189U 189U 189U 189U 189U 189U 189U 188U 188U 188U 188U 191U 191U 191U 191U 191U 191U 191U 192U 191U 191U 192U 191U 191U 191U 192U 192U 192U 193U 65535U 65535U 65535U 65535U 65535U 65535U
33 187U 183U 180U 174U 169U 168U 171U 174U 176U 182U 185U 183U 185U 185U 185U 185U 185U 185U 185U 186U 186U 186U 186U 186U 186U 186U 185U 185U 184U 184U 184U 184U 184U 182U 182U 182U 182U 181U 182U 182U 181U 181U 181U 181U 180U 180U 179U 178U 176U 175U 174U 172U 168U 165U 165U 166U 169U 179U 183U 187U 188U 188U 189U 189U 189U 189U 190U 192U 189U 189U 189U 189U 188U 189U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
34 188U 185U 179U 172U 166U 169U 174U 178U 180U 185U 186U 186U 185U 185U 185U 185U 185U 185U 185U 185U 185U 186U 186U 186U 186U 186U 184U 184U 184U 182U 182U 182U 182U 182U 181U 181U 181U 181U 182U 182U 181U 181U 181U 181U 180U 180U 179U 178U 176U 175U 175U 173U 172U 171U 171U 173U 178U 185U 187U 187U 188U 189U 189U 189U 189U 189U 189U 190U 190U 190U 192U 190U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
35 190U 185U 176U 166U 165U 169U 179U 183U 183U 186U 187U 187U 185U 185U 185U 185U 185U 185U 185U 185U 185U 186U 186U 186U 186U 186U 184U 184U 184U 182U 182U 182U 182U 181U 181U 181U 181U 180U 181U 181U 181U 181U 181U 181U 180U 180U 179U 178U 176U 176U 175U 174U 174U 175U 175U 179U 182U 186U 188U 188U 189U 189U 189U 189U 189U 189U 190U 190U 190U 192U 193U 192U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
36 190U 178U 162U 164U 164U 172U 180U 183U 186U 187U 187U 187U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 186U 186U 186U 186U 184U 184U 184U 182U 182U 182U 182U 181U 181U 181U 181U 180U 181U 181U 181U 181U 181U 181U 180U 180U 180U 179U 179U 179U 176U 176U 176U 176U 178U 180U 183U 186U 188U 188U 189U 189U 189U 189U 189U 190U 192U 192U 192U 193U 193U 193U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
37 185U 168U 154U 161U 172U 179U 182U 183U 187U 187U 187U 187U 186U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 184U 184U 182U 182U 182U 182U 182U 181U 181U 181U 181U 180U 181U 181U 181U 181U 181U 180U 181U 181U 180U 180U 180U 180U 179U 178U 178U 179U 179U 181U 183U 186U 188U 189U 189U 189U 190U 189U 189U 192U 192U 192U 193U 193U 193U 193U 192U 192U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 191U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
38 175U 161U 155U 166U 176U 180U 182U 183U 186U 185U 185U 186U 186U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 185U 183U 183U 183U 183U 183U 182U 182U 182U 182U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 180U 180U 180U 180U 180U 181U 182U 185U 187U 188U 189U 190U 190U 190U 192U 190U 190U 192U 192U 192U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
39 167U 157U 160U 173U 180U 181U 181U 182U 185U 183U 183U 185U 185U 185U 185U 185U 185U 185U 185U 185U 183U 183U 185U 185U 185U 185U 183U 183U 183U 183U 183U 182U 182U 182U 182U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 182U 182U 185U 187U 189U 190U 192U 192U 193U 193U 192U 190U 192U 192U 192U 193U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
40 163U 157U 164U 178U 181U 181U 182U 183U 183U 183U 183U 185U 183U 183U 183U 183U 183U 185U 183U 183U 183U 183U 185U 185U 185U 185U 185U 183U 183U 183U 183U 183U 182U 182U 182U 182U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 182U 182U 182U 182U 182U 183U 187U 187U 188U 190U 192U 193U 193U 193U 193U 192U 190U 192U 192U 193U 193U 193U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
41 161U 160U 172U 180U 182U 181U 182U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 185U 185U 183U 183U 183U 183U 183U 183U 183U 183U 182U 182U 182U 182U 181U 181U 181U 181U 181U 181U 181U 181U 180U 182U 182U 182U 182U 182U 182U 185U 187U 189U 192U 193U 193U 193U 193U 193U 193U 190U 190U 192U 192U 193U 193U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
42 161U 166U 175U 180U 181U 182U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 182U 182U 181U 182U 183U 185U 185U 183U 183U 183U 183U 183U 183U 183U 183U 183U 182U 182U 182U 182U 181U 181U 181U 181U 180U 181U 181U 178U 179U 179U 179U 178U 179U 180U 183U 187U 190U 193U 195U 195U 195U 194U 193U 192U 189U 189U 192U 193U 193U 193U 194U 194U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
43 154U 168U 181U 181U 180U 181U 183U 183U 182U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 183U 183U 183U 183U 183U 183U 183U 183U 183U 183U 182U 182U 182U 181U 182U 182U 181U 181U 181U 179U 180U 180U 179U 174U 172U 173U 173U 172U 171U 178U 185U 187U 190U 194U 196U 199U 199U 196U 194U 192U 188U 189U 190U 193U 195U 195U 194U 194U 194U 193U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
44 154U 167U 180U 181U 180U 180U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 181U 182U 183U 183U 183U 182U 183U 183U 183U 183U 182U 181U 181U 181U 180U 181U 181U 181U 181U 180U 179U 180U 178U 174U 172U 168U 166U 166U 166U 167U 175U 182U 186U 188U 193U 195U 199U 199U 196U 192U 190U 188U 189U 190U 190U 194U 195U 195U 194U 194U 193U 193U 193U 193U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
45 175U 175U 178U 179U 179U 180U 180U 181U 181U 181U 180U 181U 181U 180U 180U 180U 180U 180U 180U 180U 181U 181U 181U 181U 181U 182U 182U 182U 181U 182U 182U 181U 181U 181U 181U 181U 180U 180U 179U 179U 179U 176U 174U 174U 174U 171U 167U 164U 160U 159U 159U 164U 172U 179U 183U 187U 192U 194U 196U 199U 196U 193U 192U 189U 190U 190U 192U 194U 195U 195U 194U 192U 192U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
46 201U 189U 178U 176U 179U 179U 180U 180U 180U 181U 181U 181U 179U 179U 179U 179U 179U 179U 179U 180U 180U 181U 180U 181U 181U 181U 182U 182U 181U 182U 182U 182U 182U 181U 181U 181U 180U 180U 179U 179U 179U 176U 176U 172U 168U 166U 164U 159U 155U 153U 153U 158U 167U 176U 185U 189U 192U 194U 196U 196U 195U 195U 193U 193U 193U 193U 194U 194U 195U 195U 194U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 65535U 65535U 65535U 65535U 65535U 65535U
47 225U 203U 180U 175U 177U 177U 179U 179U 179U 180U 181U 180U 179U 179U 179U 179U 179U 179U 179U 180U 180U 180U 181U 181U 180U 181U 181U 181U 180U 182U 182U 181U 181U 181U 180U 179U 180U 180U 180U 180U 181U 186U 190U 193U 186U 175U 165U 158U 151U 145U 145U 151U 164U 175U 183U 188U 188U 190U 194U 194U 195U 195U 194U 194U 194U 195U 196U 196U 196U 196U 195U 193U 193U 193U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 190U 65535U 65535U 65535U 65535U 65535U 65535U
48 235U 207U 180U 176U 177U 177U 179U 180U 181U 181U 181U 181U 179U 179U 179U 179U 179U 179U 179U 179U 179U 180U 181U 180U 180U 181U 181U 181U 180U 180U 180U 180U 179U 181U 181U 179U 178U 180U 182U 181U 179U 188U 215U 229U 223U 197U 169U 159U 148U 143U 141U 147U 161U 174U 185U 188U 188U 188U 192U 192U 192U 192U 194U 193U 193U 194U 195U 196U 196U 196U 195U 193U 192U 192U 190U 190U 190U 190U 190U 190U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 192U 190U 65535U 65535U 65535U 65535U 65535U 65535U
49 227U 202U 179U 175U 176U 177U 179U 181U 182U 182U 181U 182U 180U 178U 179U 179U 179U 179U 179U 180U 179U 180U 182U 181U 180U 180U 181U 181U 179U 179U 179U 179U 178U 180U 181U 181U 179U 180U 181U 181U 176U 187U 208U 224U 220U 196U 178U 160U 147U 138U 137U 146U 161U 176U 185U 189U 190U 190U 190U 192U 192U 192U 192U 190U 189U 188U 189U 192U 195U 194U 192U 193U 192U 192U 188U 188U 189U 190U 189U 190U 192U 192U 190U 190U 190U 190U 190U 190U 190U 192U 192U 190U 65535U 65535U 65535U 65535U 65535U 65535U
50 225U 202U 177U 174U 175U 178U 180U 181U 181U 181U 181U 181U 179U 178U 179U 179U 178U 179U 180U 180U 180U 182U 187U 187U 187U 184U 182U 181U 180U 179U 179U 179U 180U 180U 180U 180U 180U 179U 181U 182U 181U 185U 187U 192U 192U 185U 176U 160U 146U 137U 133U 145U 164U 178U 187U 190U 190U 190U 189U 190U 190U 189U 190U 188U 182U 179U 178U 181U 189U 189U 187U 189U 188U 187U 186U 186U 187U 189U 189U 190U 192U 192U 190U 190U 190U 190U 190U 190U 190U 190U 190U 188U 65535U 65535U 65535U 65535U 65535U 65535U
51 223U 205U 182U 174U 179U 180U 181U 181U 182U 181U 181U 181U 179U 179U 179U 179U 179U 180U 180U 181U 181U 181U 189U 205U 210U 200U 189U 183U 181U 179U 179U 179U 180U 180U 179U 179U 179U 178U 180U 180U 182U 186U 186U 183U 182U 178U 168U 159U 147U 139U 141U 153U 166U 175U 187U 190U 190U 190U 188U 188U 188U 188U 187U 183U 175U 169U 166U 168U 179U 181U 182U 185U 183U 183U 182U 183U 185U 185U 186U 188U 190U 190U 187U 186U 188U 190U 190U 190U 189U 189U 188U 187U 65535U 65535U 65535U 65535U 65535U 65535U
52 221U 205U 184U 177U 180U 181U 181U 182U 182U 182U 181U 181U 180U 179U 179U 180U 180U 180U 181U 181U 182U 184U 191U 207U 212U 204U 193U 185U 181U 179U 178U 179U 179U 178U 178U 176U 176U 175U 176U 176U 180U 190U 196U 203U 201U 190U 186U 170U 152U 146U 151U 160U 166U 174U 177U 181U 182U 182U 182U 185U 187U 186U 182U 178U 173U 165U 160U 161U 168U 174U 178U 179U 181U 181U 182U 182U 181U 179U 180U 182U 182U 182U 179U 179U 182U 185U 185U 186U 186U 186U 186U 185U 65535U 65535U 65535U 65535U 65535U 65535U
53 204U 195U 184U 179U 181U 181U 181U 182U 182U 181U 181U 181U 180U 179U 179U 180U 179U 179U 180U 180U 181U 184U 187U 187U 188U 186U 182U 180U 176U 174U 176U 178U 178U 176U 176U 175U 175U 174U 173U 172U 175U 192U 209U 222U 221U 214U 210U 186U 158U 152U 155U 163U 163U 167U 167U 167U 167U 167U 169U 173U 176U 174U 171U 171U 169U 164U 159U 160U 165U 168U 171U 172U 172U 172U 173U 172U 171U 169U 171U 171U 172U 172U 172U 172U 174U 176U 178U 179U 181U 185U 183U 182U 65535U 65535U 65535U 65535U 65535U 65535U
54 181U 179U 179U 179U 181U 182U 181U 181U 180U 180U 180U 180U 179U 179U 179U 177U 176U 175U 176U 176U 176U 176U 175U 175U 174U 175U 176U 174U 172U 170U 170U 172U 174U 174U 174U 172U 169U 169U 167U 161U 166U 186U 204U 217U 219U 216U 214U 194U 162U 146U 152U 156U 160U 161U 159U 157U 156U 156U 155U 159U 163U 161U 158U 158U 161U 160U 156U 158U 162U 166U 166U 166U 166U 166U 166U 165U 165U 163U 163U 163U 163U 165U 166U 167U 169U 172U 172U 173U 174U 175U 174U 173U 65535U 65535U 65535U 65535U 65535U 65535U
55 176U 175U 174U 175U 177U 180U 178U 178U 175U 176U 175U 175U 175U 176U 175U 172U 170U 170U 170U 168U 166U 166U 165U 164U 165U 165U 166U 163U 161U 160U 158U 158U 161U 162U 160U 160U 162U 161U 155U 148U 153U 172U 189U 203U 204U 194U 191U 184U 160U 138U 145U 148U 151U 153U 151U 148U 148U 149U 149U 149U 151U 152U 149U 148U 153U 155U 152U 153U 156U 159U 160U 162U 162U 162U 161U 161U 161U 160U 160U 161U 159U 159U 158U 159U 160U 163U 163U 163U 163U 163U 161U 162U 65535U 65535U 65535U 65535U 65535U 65535U
56 175U 173U 172U 171U 173U 174U 175U 175U 174U 173U 173U 173U 171U 172U 170U 168U 167U 167U 167U 163U 161U 159U 157U 154U 152U 152U 151U 148U 148U 146U 144U 145U 147U 148U 148U 149U 151U 142U 135U 135U 151U 174U 188U 200U 193U 174U 155U 151U 139U 127U 129U 133U 137U 140U 141U 144U 146U 147U 147U 147U 147U 148U 148U 147U 148U 148U 149U 149U 152U 154U 154U 156U 157U 157U 158U 158U 159U 158U 159U 158U 156U 154U 153U 153U 155U 153U 154U 154U 155U 158U 158U 158U 65535U 65535U 65535U 65535U 65535U 65535U
57 175U 175U 168U 166U 168U 171U 173U 173U 171U 171U 171U 168U 169U 168U 167U 165U 162U 162U 162U 160U 156U 155U 151U 148U 146U 146U 146U 145U 143U 140U 138U 139U 140U 140U 141U 141U 140U 131U 126U 135U 156U 179U 186U 187U 178U 155U 129U 124U 123U 121U 121U 126U 131U 137U 140U 141U 142U 144U 145U 146U 146U 146U 146U 148U 147U 146U 147U 147U 148U 151U 149U 151U 151U 151U 154U 155U 155U 155U 156U 154U 152U 151U 151U 148U 148U 149U 152U 151U 151U 152U 153U 154U 65535U 65535U 65535U 65535U 65535U 65535U
58 190U 182U 168U 163U 162U 164U 165U 164U 166U 166U 165U 163U 163U 161U 159U 156U 155U 155U 153U 151U 150U 146U 144U 141U 139U 139U 139U 139U 138U 135U 134U 134U 133U 133U 133U 133U 130U 125U 124U 135U 156U 173U 170U 163U 154U 137U 119U 115U 119U 121U 121U 125U 131U 135U 138U 139U 139U 141U 143U 144U 144U 143U 144U 145U 144U 143U 144U 144U 146U 148U 146U 147U 147U 148U 151U 152U 151U 152U 152U 150U 148U 148U 148U 147U 147U 148U 148U 148U 150U 150U 151U 153U 65535U 65535U 65535U 65535U 65535U 65535U
59 200U 184U 168U 163U 159U 158U 158U 158U 159U 159U 159U 156U 153U 151U 149U 149U 148U 146U 144U 141U 140U 139U 138U 135U 133U 133U 133U 132U 132U 131U 128U 128U 128U 130U 128U 128U 126U 123U 123U 130U 142U 152U 147U 140U 133U 125U 121U 120U 120U 122U 123U 127U 133U 138U 138U 139U 139U 140U 140U 141U 143U 143U 144U 144U 143U 143U 144U 143U 145U 146U 145U 146U 147U 148U 148U 148U 150U 150U 150U 150U 148U 148U 148U 148U 148U 148U 147U 147U 148U 148U 148U 151U 65535U 65535U 65535U 65535U 65535U 65535U
60 215U 202U 170U 159U 156U 154U 154U 154U 153U 152U 152U 151U 147U 145U 144U 142U 142U 142U 139U 137U 135U 135U 133U 131U 131U 131U 128U 128U 127U 125U 125U 125U 125U 124U 126U 126U 124U 122U 122U 125U 127U 126U 124U 118U 113U 117U 119U 118U 119U 123U 126U 128U 132U 137U 138U 138U 139U 139U 139U 141U 142U 142U 143U 143U 144U 144U 143U 143U 145U 145U 145U 145U 147U 147U 146U 147U 147U 147U 147U 148U 148U 148U 148U 148U 149U 149U 148U 149U 149U 149U 149U 152U 65535U 65535U 65535U 65535U 65535U 65535U
61 204U 193U 172U 155U 151U 149U 148U 146U 145U 143U 145U 144U 139U 137U 138U 138U 137U 137U 135U 133U 131U 131U 131U 128U 128U 128U 126U 126U 125U 123U 122U 123U 123U 123U 125U 125U 123U 121U 120U 121U 122U 119U 112U 106U 103U 104U 105U 108U 117U 123U 124U 125U 130U 134U 134U 135U 137U 137U 137U 139U 140U 141U 140U 140U 141U 141U 141U 141U 142U 144U 143U 144U 145U 145U 145U 145U 146U 146U 146U 147U 147U 147U 147U 147U 148U 148U 148U 149U 149U 149U 151U 151U 65535U 65535U 65535U 65535U 65535U 65535U
62 182U 173U 165U 151U 146U 144U 141U 141U 141U 139U 139U 139U 138U 135U 135U 135U 134U 132U 131U 128U 127U 127U 127U 127U 127U 127U 125U 125U 125U 123U 122U 123U 122U 121U 123U 124U 122U 119U 117U 113U 110U 105U 99U 98U 93U 91U 96U 105U 114U 121U 122U 125U 128U 131U 132U 134U 135U 135U 137U 139U 139U 139U 138U 138U 138U 139U 139U 140U 141U 141U 140U 140U 141U 141U 141U 141U 143U 143U 143U 145U 145U 145U 146U 147U 147U 147U 148U 148U 148U 149U 151U 151U 65535U 65535U 65535U 65535U 65535U 65535U
63 174U 167U 159U 148U 144U 140U 137U 138U 137U 134U 134U 134U 134U 133U 133U 133U 133U 131U 127U 126U 126U 125U 125U 126U 126U 126U 124U 124U 124U 124U 123U 123U 122U 121U 121U 120U 120U 118U 112U 104U 97U 93U 92U 92U 87U 86U 92U 103U 112U 119U 121U 125U 127U 128U 131U 133U 133U 132U 134U 137U 137U 137U 136U 136U 134U 136U 136U 136U 137U 137U 136U 136U 138U 139U 137U 138U 138U 138U 139U 141U 143U 143U 144U 144U 145U 145U 146U 148U 148U 148U 149U 151U 65535U 65535U 65535U 65535U 65535U 65535U
64 179U 163U 153U 146U 141U 134U 132U 130U 130U 130U 128U 130U 130U 130U 130U 130U 130U 128U 125U 124U 124U 123U 123U 124U 124U 124U 124U 124U 124U 124U 124U 123U 121U 120U 120U 119U 115U 112U 107U 99U 93U 91U 90U 90U 89U 90U 92U 103U 111U 115U 118U 124U 127U 128U 128U 130U 131U 131U 130U 132U 135U 135U 133U 133U 134U 134U 134U 134U 133U 133U 133U 133U 134U 135U 134U 134U 137U 137U 137U 139U 139U 139U 139U 140U 140U 141U 144U 146U 146U 146U 147U 148U 65535U 65535U 65535U 65535U 65535U 65535U
65 161U 152U 147U 145U 138U 128U 125U 125U 124U 123U 125U 125U 125U 126U 126U 125U 123U 122U 122U 121U 122U 123U 123U 124U 124U 124U 124U 124U 125U 125U 123U 121U 121U 121U 120U 117U 111U 107U 106U 98U 92U 90U 89U 91U 93U 96U 98U 103U 108U 112U 113U 122U 126U 128U 130U 130U 131U 130U 130U 131U 132U 132U 131U 133U 133U 132U 132U 132U 131U 131U 131U 131U 133U 133U 133U 134U 134U 134U 135U 135U 137U 137U 137U 138U 138U 138U 140U 140U 141U 142U 142U 144U 65535U 65535U 65535U 65535U 65535U 65535U
66 135U 132U 134U 138U 130U 122U 120U 118U 115U 113U 115U 115U 117U 119U 119U 119U 120U 120U 120U 121U 121U 122U 123U 124U 124U 124U 123U 124U 124U 123U 123U 122U 121U 121U 117U 113U 110U 106U 104U 98U 93U 91U 91U 93U 98U 100U 100U 105U 108U 112U 112U 120U 126U 127U 128U 128U 130U 130U 130U 131U 131U 131U 131U 131U 131U 131U 131U 132U 131U 129U 130U 130U 131U 132U 131U 131U 132U 133U 133U 132U 134U 134U 134U 135U 135U 135U 135U 135U 138U 140U 140U 141U 65535U 65535U 65535U 65535U 65535U 65535U
67 119U 117U 117U 122U 119U 113U 111U 110U 106U 104U 105U 107U 112U 113U 114U 114U 115U 115U 118U 118U 118U 119U 120U 122U 122U 122U 122U 122U 121U 121U 121U 119U 119U 119U 114U 111U 107U 105U 103U 97U 93U 92U 96U 99U 101U 104U 106U 107U 110U 112U 114U 122U 126U 126U 127U 127U 128U 128U 128U 130U 130U 128U 128U 128U 128U 128U 130U 130U 129U 129U 127U 126U 126U 127U 127U 127U 130U 130U 128U 128U 130U 130U 131U 131U 131U 131U 131U 132U 134U 135U 135U 138U 65535U 65535U 65535U 65535U 65535U 65535U
68 108U 106U 107U 110U 110U 107U 105U 105U 105U 105U 106U 108U 108U 110U 112U 112U 113U 114U 114U 114U 114U 113U 113U 114U 115U 119U 120U 122U 121U 121U 119U 115U 114U 114U 113U 110U 106U 104U 100U 96U 93U 94U 97U 101U 105U 108U 108U 108U 110U 113U 115U 122U 125U 125U 126U 126U 126U 127U 128U 128U 127U 127U 127U 127U 126U 127U 127U 128U 127U 125U 124U 124U 123U 125U 125U 124U 125U 126U 125U 126U 127U 127U 127U 127U 127U 127U 127U 128U 131U 133U 133U 134U 65535U 65535U 65535U 65535U 65535U 65535U
69 106U 104U 105U 105U 105U 104U 104U 104U 104U 104U 105U 106U 106U 108U 108U 110U 110U 108U 110U 110U 107U 107U 107U 108U 110U 111U 113U 113U 113U 113U 112U 112U 112U 113U 111U 107U 104U 101U 100U 98U 97U 97U 99U 105U 111U 112U 111U 110U 110U 113U 115U 121U 124U 125U 126U 126U 125U 127U 128U 128U 126U 125U 125U 124U 126U 126U 125U 126U 124U 123U 124U 123U 123U 123U 123U 124U 124U 124U 125U 125U 125U 125U 125U 125U 125U 125U 126U 126U 127U 130U 130U 130U 65535U 65535U 65535U 65535U 65535U 65535U
70 105U 104U 103U 103U 103U 100U 101U 103U 104U 106U 106U 104U 105U 105U 106U 106U 106U 105U 105U 104U 103U 104U 105U 106U 106U 107U 107U 108U 110U 111U 111U 112U 112U 112U 110U 107U 105U 103U 101U 100U 100U 101U 104U 107U 113U 113U 112U 110U 110U 113U 115U 120U 122U 123U 125U 125U 125U 126U 126U 126U 124U 123U 123U 123U 125U 125U 124U 124U 123U 123U 124U 123U 123U 123U 123U 122U 123U 123U 124U 124U 124U 124U 123U 124U 124U 124U 123U 125U 125U 125U 125U 126U 65535U 65535U 65535U 65535U 65535U 65535U
71 105U 105U 104U 103U 103U 100U 101U 103U 106U 106U 106U 104U 105U 105U 105U 106U 105U 106U 106U 104U 104U 107U 108U 110U 108U 108U 110U 110U 112U 114U 113U 114U 114U 112U 111U 110U 107U 106U 105U 105U 105U 107U 108U 113U 113U 113U 111U 108U 110U 113U 117U 120U 121U 122U 124U 124U 124U 124U 124U 124U 124U 123U 123U 122U 123U 123U 123U 123U 123U 122U 122U 122U 122U 122U 121U 122U 122U 122U 123U 123U 123U 123U 123U 123U 123U 123U 122U 123U 123U 123U 124U 126U 65535U 65535U 65535U 65535U 65535U 65535U
72 109U 109U 107U 107U 106U 107U 109U 111U 112U 112U 107U 106U 105U 105U 105U 107U 106U 106U 107U 106U 106U 108U 112U 113U 113U 113U 112U 112U 113U 117U 117U 117U 115U 114U 112U 111U 110U 108U 108U 107U 110U 113U 114U 115U 115U 113U 110U 108U 111U 114U 117U 119U 121U 121U 123U 123U 124U 124U 123U 123U 123U 123U 123U 123U 122U 123U 123U 122U 123U 123U 122U 122U 121U 121U 121U 120U 122U 122U 122U 123U 123U 123U 123U 123U 123U 122U 122U 122U 122U 123U 124U 124U 65535U 65535U 65535U 65535U 65535U 65535U
73 112U 112U 113U 113U 113U 112U 114U 117U 115U 114U 112U 110U 108U 107U 107U 108U 108U 110U 110U 108U 110U 112U 114U 118U 118U 118U 115U 115U 117U 119U 119U 118U 118U 117U 114U 113U 111U 111U 111U 111U 113U 115U 118U 118U 118U 114U 113U 112U 113U 117U 119U 120U 121U 122U 122U 123U 124U 124U 123U 123U 123U 123U 123U 123U 122U 123U 123U 122U 123U 123U 121U 121U 121U 121U 120U 121U 122U 122U 122U 123U 123U 123U 123U 123U 123U 122U 122U 123U 123U 123U 124U 124U 65535U 65535U 65535U 65535U 65535U 65535U
74 115U 115U 117U 118U 118U 117U 118U 118U 119U 119U 115U 114U 112U 110U 111U 111U 112U 113U 112U 112U 112U 113U 115U 118U 118U 118U 118U 118U 118U 120U 120U 120U 119U 119U 118U 115U 114U 113U 113U 114U 115U 118U 118U 118U 117U 117U 115U 115U 118U 119U 121U 121U 122U 123U 122U 123U 124U 124U 123U 123U 123U 123U 123U 123U 122U 123U 123U 122U 122U 122U 121U 121U 121U 121U 120U 121U 123U 123U 123U 124U 124U 124U 124U 124U 124U 123U 123U 124U 124U 124U 124U 124U 65535U 65535U 65535U 65535U 65535U 65535U
75 118U 118U 118U 119U 119U 119U 119U 119U 118U 118U 118U 117U 115U 114U 115U 115U 115U 117U 115U 115U 114U 115U 118U 118U 118U 119U 118U 119U 119U 120U 120U 119U 119U 119U 118U 115U 115U 115U 115U 115U 117U 118U 118U 117U 117U 117U 115U 118U 120U 122U 123U 122U 123U 123U 123U 124U 125U 123U 123U 123U 123U 123U 123U 124U 124U 124U 123U 124U 124U 123U 123U 121U 121U 121U 121U 122U 124U 125U 125U 126U 126U 125U 125U 125U 125U 125U 125U 125U 125U 125U 126U 125U 65535U 65535U 65535U 65535U 65535U 65535U
76 122U 121U 119U 120U 120U 120U 120U 120U 119U 120U 119U 119U 118U 118U 118U 119U 118U 118U 117U 117U 117U 118U 118U 118U 118U 119U 119U 119U 120U 120U 120U 120U 119U 120U 119U 117U 117U 118U 118U 118U 118U 118U 118U 118U 118U 115U 117U 118U 121U 122U 123U 124U 124U 124U 125U 126U 126U 125U 125U 125U 125U 125U 125U 125U 125U 125U 125U 125U 125U 123U 123U 123U 122U 123U 123U 123U 125U 126U 126U 126U 126U 126U 126U 126U 126U 125U 125U 126U 126U 126U 127U 126U 65535U 65535U 65535U 65535U 65535U 65535U
77 121U 120U 120U 120U 121U 121U 121U 120U 121U 121U 121U 121U 120U 118U 118U 119U 120U 119U 119U 118U 118U 118U 118U 119U 119U 119U 119U 119U 120U 120U 121U 120U 119U 120U 120U 119U 119U 120U 119U 119U 119U 119U 120U 120U 120U 119U 118U 119U 122U 123U 124U 124U 125U 125U 126U 126U 126U 126U 126U 126U 126U 126U 126U 126U 126U 126U 126U 126U 125U 125U 125U 123U 124U 124U 124U 124U 125U 126U 126U 126U 126U 126U 126U 126U 127U 127U 127U 128U 128U 127U 127U 127U 65535U 65535U 65535U 65535U 65535U 65535U
78 120U 120U 121U 121U 121U 121U 120U 121U 121U 121U 121U 121U 120U 120U 120U 120U 119U 119U 120U 119U 119U 119U 119U 120U 120U 120U 120U 120U 121U 121U 121U 121U 121U 121U 120U 119U 120U 121U 121U 120U 120U 121U 121U 121U 121U 121U 120U 121U 123U 124U 125U 126U 126U 127U 127U 127U 126U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 126U 126U 126U 125U 125U 125U 127U 127U 126U 128U 128U 128U 128U 128U 130U 130U 128U 130U 130U 128U 128U 128U 65535U 65535U 65535U 65535U 65535U 65535U
79 119U 120U 121U 121U 121U 120U 121U 122U 122U 122U 122U 121U 121U 122U 122U 120U 119U 120U 121U 121U 121U 121U 121U 120U 120U 121U 121U 121U 121U 121U 121U 121U 121U 121U 120U 120U 120U 121U 121U 120U 120U 121U 121U 121U 122U 122U 122U 124U 126U 126U 126U 127U 128U 130U 130U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 127U 126U 126U 125U 126U 127U 127U 128U 128U 128U 128U 128U 128U 130U 130U 130U 128U 130U 130U 131U 131U 131U 131U 65535U 65535U 65535U 65535U 65535U 65535U
80 119U 120U 119U 120U 121U 121U 121U 122U 122U 122U 122U 122U 120U 120U 120U 119U 119U 120U 121U 121U 121U 121U 121U 121U 121U 122U 121U 122U 122U 121U 121U 121U 121U 121U 121U 121U 121U 121U 121U 122U 121U 121U 121U 122U 123U 123U 124U 126U 127U 127U 128U 128U 128U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 128U 128U 128U 127U 127U 128U 128U 128U 128U 128U 128U 128U 128U 128U 130U 130U 130U 130U 131U 131U 131U 132U 65535U 65535U 65535U 65535U 65535U 65535U
81 120U 120U 120U 121U 122U 123U 123U 123U 123U 122U 122U 122U 121U 119U 119U 120U 119U 119U 120U 121U 121U 121U 122U 122U 122U 123U 123U 122U 122U 122U 122U 121U 121U 122U 121U 121U 121U 121U 121U 122U 122U 121U 122U 123U 124U 124U 124U 126U 127U 126U 127U 128U 128U 128U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 130U 128U 128U 128U 127U 128U 128U 128U 127U 128U 131U 131U 131U 131U 131U 131U 131U 131U 131U 131U 132U 132U 65535U 65535U 65535U 65535U 65535U 65535U
82 123U 124U 124U 124U 124U 125U 125U 125U 124U 124U 123U 124U 124U 122U 121U 121U 120U 120U 121U 121U 121U 123U 123U 123U 123U 123U 123U 123U 123U 122U 122U 122U 122U 122U 122U 121U 121U 121U 121U 122U 122U 123U 123U 123U 124U 124U 125U 126U 126U 127U 127U 127U 130U 130U 130U 130U 128U 128U 128U 128U 128U 128U 128U 128U 128U 128U 127U 127U 127U 127U 130U 127U 127U 127U 128U 128U 128U 128U 130U 130U 131U 131U 131U 131U 131U 131U 131U 131U 131U 131U 132U 132U 65535U 65535U 65535U 65535U 65535U 65535U
83 131U 133U 130U 131U 132U 132U 131U 128U 126U 126U 126U 126U 125U 124U 124U 123U 122U 123U 121U 121U 123U 123U 123U 123U 123U 123U 123U 123U 123U 123U 122U 123U 122U 122U 122U 122U 122U 121U 121U 122U 122U 123U 123U 124U 125U 125U 126U 127U 127U 127U 127U 127U 130U 130U 130U 130U 131U 131U 131U 131U 131U 131U 131U 131U 131U 130U 129U 129U 130U 130U 130U 127U 127U 127U 128U 128U 128U 128U 130U 130U 130U 130U 131U 131U 131U 131U 131U 131U 132U 132U 133U 133U 65535U 65535U 65535U 65535U 65535U 65535U
84 141U 138U 138U 135U 137U 137U 134U 132U 128U 127U 127U 127U 127U 126U 126U 125U 123U 123U 122U 123U 124U 123U 123U 124U 124U 124U 123U 123U 123U 124U 124U 123U 123U 122U 122U 122U 122U 122U 121U 121U 122U 123U 123U 124U 126U 126U 125U 127U 127U 127U 127U 128U 130U 130U 130U 131U 131U 131U 131U 131U 131U 131U 131U 131U 131U 130U 129U 130U 129U 129U 128U 127U 127U 127U 127U 127U 128U 128U 130U 130U 131U 131U 133U 133U 133U 133U 133U 133U 133U 134U 135U 135U 65535U 65535U 65535U 65535U 65535U 65535U
85 145U 142U 141U 139U 139U 139U 138U 135U 132U 128U 128U 131U 128U 127U 128U 127U 125U 124U 124U 124U 123U 124U 125U 124U 124U 125U 125U 124U 124U 124U 124U 125U 124U 122U 123U 122U 122U 122U 121U 121U 122U 123U 124U 125U 126U 127U 126U 127U 127U 127U 128U 128U 130U 130U 130U 131U 132U 132U 132U 131U 132U 132U 131U 131U 131U 130U 129U 129U 127U 127U 128U 127U 127U 128U 128U 130U 131U 130U 132U 132U 133U 133U 133U 133U 134U 135U 135U 135U 135U 137U 138U 137U 65535U 65535U 65535U 65535U 65535U 65535U
86 146U 145U 142U 141U 141U 141U 139U 137U 135U 133U 131U 133U 131U 131U 131U 130U 128U 127U 126U 126U 125U 126U 126U 126U 126U 127U 126U 125U 124U 125U 125U 125U 125U 123U 125U 124U 122U 121U 121U 121U 122U 123U 124U 125U 126U 127U 127U 128U 128U 128U 128U 128U 130U 131U 131U 131U 132U 132U 132U 132U 132U 132U 131U 131U 130U 128U 127U 129U 127U 127U 130U 128U 130U 130U 131U 132U 133U 134U 134U 134U 135U 135U 135U 135U 137U 137U 137U 138U 138U 138U 139U 138U 65535U 65535U 65535U 65535U 65535U 65535U
87 146U 147U 146U 144U 144U 141U 139U 139U 139U 138U 133U 134U 133U 133U 133U 132U 131U 130U 128U 127U 127U 127U 127U 128U 128U 130U 128U 127U 126U 126U 127U 126U 125U 125U 125U 125U 124U 123U 122U 122U 123U 123U 125U 125U 126U 127U 127U 130U 130U 130U 130U 130U 131U 132U 132U 132U 132U 132U 132U 132U 132U 132U 131U 131U 131U 130U 129U 130U 129U 127U 130U 130U 131U 132U 132U 133U 135U 137U 137U 138U 138U 138U 139U 139U 139U 139U 139U 139U 139U 139U 139U 139U 65535U 65535U 65535U 65535U 65535U 65535U
88 146U 148U 148U 146U 144U 141U 140U 141U 140U 139U 135U 135U 135U 134U 135U 134U 132U 131U 130U 130U 130U 130U 130U 131U 131U 132U 132U 131U 130U 130U 129U 127U 127U 126U 126U 126U 124U 123U 122U 122U 123U 124U 124U 125U 126U 127U 128U 128U 128U 130U 130U 130U 131U 131U 132U 132U 132U 132U 132U 132U 132U 133U 133U 132U 132U 131U 130U 130U 130U 131U 131U 131U 132U 132U 135U 135U 137U 139U 140U 140U 140U 140U 140U 140U 140U 140U 140U 139U 139U 139U 139U 138U 65535U 65535U 65535U 65535U 65535U 65535U
89 146U 148U 149U 147U 145U 142U 144U 144U 142U 141U 139U 139U 138U 138U 138U 137U 134U 134U 132U 132U 131U 131U 132U 132U 131U 132U 133U 131U 131U 131U 130U 129U 129U 127U 127U 127U 125U 123U 121U 121U 122U 123U 124U 125U 126U 127U 128U 128U 128U 130U 130U 130U 131U 131U 131U 132U 132U 133U 132U 133U 133U 133U 132U 132U 132U 131U 130U 131U 131U 131U 131U 132U 132U 132U 135U 135U 137U 139U 140U 140U 140U 140U 140U 140U 140U 140U 139U 139U 138U 139U 138U 138U 65535U 65535U 65535U 65535U 65535U 65535U
90 147U 150U 151U 149U 147U 146U 146U 145U 142U 141U 141U 141U 140U 140U 140U 138U 138U 138U 135U 135U 134U 134U 134U 134U 133U 133U 133U 131U 130U 130U 130U 129U 129U 129U 129U 127U 125U 123U 122U 122U 123U 124U 124U 125U 127U 128U 128U 127U 128U 130U 130U 131U 131U 131U 131U 132U 132U 133U 133U 133U 133U 133U 132U 132U 132U 132U 132U 132U 132U 132U 132U 133U 133U 133U 132U 133U 134U 135U 135U 135U 138U 139U 139U 139U 139U 139U 138U 138U 138U 138U 138U 138U 65535U 65535U 65535U 65535U 65535U 65535U
91 146U 148U 151U 151U 149U 149U 148U 146U 144U 141U 140U 141U 140U 140U 140U 138U 139U 139U 137U 135U 137U 134U 134U 135U 134U 133U 132U 132U 132U 131U 130U 131U 130U 130U 131U 127U 125U 124U 124U 124U 125U 125U 126U 127U 128U 128U 127U 127U 127U 128U 130U 130U 131U 131U 132U 132U 132U 133U 133U 133U 133U 134U 134U 133U 133U 133U 133U 133U 133U 133U 133U 133U 133U 133U 132U 132U 133U 133U 132U 133U 135U 137U 138U 138U 138U 138U 138U 138U 137U 138U 137U 135U 65535U 65535U 65535U 65535U 65535U 65535U
92 141U 144U 146U 146U 146U 146U 147U 146U 141U 139U 138U 140U 141U 140U 140U 139U 139U 139U 137U 137U 138U 135U 135U 135U 135U 134U 133U 133U 132U 132U 133U 133U 131U 131U 131U 129U 128U 128U 125U 125U 126U 128U 128U 130U 131U 130U 127U 127U 126U 127U 127U 128U 131U 132U 133U 134U 133U 133U 133U 133U 133U 134U 134U 133U 133U 133U 133U 133U 133U 133U 133U 133U 133U 133U 132U 132U 132U 132U 130U 131U 133U 135U 137U 137U 138U 138U 138U 138U 137U 137U 137U 135U 65535U 65535U 65535U 65535U 65535U 65535U
93 139U 138U 139U 140U 139U 139U 141U 140U 139U 138U 137U 138U 139U 139U 139U 138U 138U 138U 137U 135U 135U 135U 135U 134U 135U 134U 134U 133U 132U 132U 133U 133U 132U 131U 131U 130U 131U 131U 128U 130U 131U 131U 132U 133U 134U 133U 130U 127U 126U 126U 127U 128U 132U 134U 135U 135U 135U 135U 135U 134U 134U 134U 133U 133U 133U 134U 134U 133U 133U 133U 134U 134U 135U 135U 134U 134U 134U 132U 130U 131U 133U 134U 135U 137U 137U 137U 137U 137U 137U 137U 135U 134U 65535U 65535U 65535U 65535U 65535U 65535U

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -6,14 +6,15 @@
#include "pva_kmd_regs.h" #include "pva_kmd_regs.h"
#include "pva_kmd_silicon_utils.h" #include "pva_kmd_silicon_utils.h"
void pva_kmd_abort_fw(struct pva_kmd_device *pva, uint32_t error_code) void pva_kmd_abort_fw(struct pva_kmd_device *pva, enum pva_error error_code)
{ {
// HW watchdog may fire repeatedly if PVA is hung. Therefore, disable all // HW watchdog may fire repeatedly if PVA is hung. Therefore, disable all
// interrupts to protect KMD from potential interrupt floods. // interrupts to protect KMD from potential interrupt floods.
pva_kmd_disable_all_interrupts_nosync(pva); pva_kmd_disable_all_interrupts_nosync(pva);
pva_kmd_report_error_fsi(pva, error_code); pva_kmd_report_error_fsi(pva, (uint32_t)error_code);
// We will handle firmware reboot after all contexts are closed and a new // We will handle firmware reboot after all contexts are closed and a new
// one is re-opened again // one is re-opened again
pva->recovery = true; pva->recovery = true;
pva->fw_aborted = true;
} }

View File

@@ -5,6 +5,28 @@
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
void pva_kmd_abort_fw(struct pva_kmd_device *pva, uint32_t error_code); /**
* @brief Abort firmware execution and initiate error recovery
*
* @details This function performs the following operations:
* - Immediately signals the firmware to abort current operations
* - Logs the provided error code using @ref pva_kmd_log_err_hex32()
* - Initiates emergency shutdown procedures for the PVA device
* - Marks the device as being in recovery mode for subsequent operations
* - Notifies platform-specific error handling mechanisms
* - Prepares the device for potential firmware restart or reset
* - Ensures all pending operations are cancelled safely
*
* This function is used in critical error scenarios where the firmware
* has encountered an unrecoverable error or the system has detected a
* condition that requires immediate firmware termination. The error code
* is preserved for debugging and diagnostic purposes.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] error_code Error code indicating the reason for abort
* Valid range: [0 .. UINT32_MAX]
*/
void pva_kmd_abort_fw(struct pva_kmd_device *pva, enum pva_error error_code);
#endif //PVA_KMD_ABORT_H #endif //PVA_KMD_ABORT_H

View File

@@ -4,31 +4,36 @@
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_api.h" #include "pva_api.h"
#define INVALID_ID 0xFFFFFFFF #define INVALID_ID 0xFFFFFFFFU
enum pva_error enum pva_error
pva_kmd_block_allocator_init(struct pva_kmd_block_allocator *allocator, pva_kmd_block_allocator_init(struct pva_kmd_block_allocator *allocator,
void *block_mem, uint32_t base_id, void *chunk_mem, uint32_t base_id,
uint32_t block_size, uint32_t max_num_blocks) uint32_t chunk_size, uint32_t max_num_chunks)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
allocator->free_slot_head = INVALID_ID; allocator->free_slot_head = INVALID_ID;
allocator->next_free_slot = 0; allocator->next_free_slot = 0;
allocator->max_num_blocks = max_num_blocks; allocator->max_num_blocks = max_num_chunks;
allocator->block_size = block_size; allocator->block_size = chunk_size;
allocator->base_id = base_id; allocator->base_id = base_id;
allocator->blocks = block_mem; allocator->blocks = chunk_mem;
allocator->slot_in_use = pva_kmd_zalloc( allocator->slot_in_use = pva_kmd_zalloc(
sizeof(*allocator->slot_in_use) * max_num_blocks); sizeof(*allocator->slot_in_use) * max_num_chunks);
if (!allocator->slot_in_use) { if (allocator->slot_in_use == NULL) {
err = PVA_NOMEM; err = PVA_NOMEM;
pva_kmd_log_err( pva_kmd_log_err(
"pva_kmd_block_allocator_init slot_in_use NULL"); "pva_kmd_block_allocator_init slot_in_use NULL");
goto err_out; goto err_out;
} }
pva_kmd_mutex_init(&allocator->allocator_lock); err = pva_kmd_mutex_init(&allocator->allocator_lock);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"pva_kmd_block_allocator_init mutex_init failed");
goto err_out;
}
return PVA_SUCCESS; return PVA_SUCCESS;
err_out: err_out:
return err; return err;
@@ -43,9 +48,11 @@ void pva_kmd_block_allocator_deinit(struct pva_kmd_block_allocator *allocator)
static inline void *get_block(struct pva_kmd_block_allocator *allocator, static inline void *get_block(struct pva_kmd_block_allocator *allocator,
uint32_t slot) uint32_t slot)
{ {
uintptr_t base = (uintptr_t)allocator->blocks; uintptr_t base = (uintptr_t)(void *)allocator->blocks;
uintptr_t addr = base + (slot * allocator->block_size); uint64_t offset =
return (void *)addr; safe_mulu64((uint64_t)slot, (uint64_t)allocator->block_size);
uint64_t addr = safe_addu64((uint64_t)base, offset);
return (void *)(uintptr_t)addr;
} }
static inline uint32_t next_slot(struct pva_kmd_block_allocator *allocator, static inline uint32_t next_slot(struct pva_kmd_block_allocator *allocator,

View File

@@ -6,53 +6,281 @@
#include "pva_api.h" #include "pva_api.h"
#include "pva_kmd_mutex.h" #include "pva_kmd_mutex.h"
/**
* @brief Block allocator for managing fixed-size memory blocks
*
* @details This structure provides efficient allocation and deallocation of
* fixed-size memory blocks from a pre-allocated memory region. It maintains
* a free list of available blocks and provides thread-safe access through
* mutex protection. The allocator is particularly useful for managing pools
* of objects such as command buffers, resource records, or other frequently
* allocated data structures.
*/
struct pva_kmd_block_allocator { struct pva_kmd_block_allocator {
/**
* @brief Head of the free slot linked list
* Valid range: [0 .. max_num_blocks-1] or special sentinel values
*/
uint32_t free_slot_head; uint32_t free_slot_head;
/**
* @brief Base ID for allocated blocks
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t base_id; uint32_t base_id;
/**
* @brief Maximum number of blocks that can be allocated
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t max_num_blocks; uint32_t max_num_blocks;
/**
* @brief Next free slot to be allocated
* Valid range: [0 .. max_num_blocks-1]
*/
uint32_t next_free_slot; uint32_t next_free_slot;
/**
* @brief Size of each block in bytes
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t block_size; uint32_t block_size;
/**
* @brief Pointer to the base of the block memory region
*/
void *blocks; void *blocks;
/**
* @brief Array tracking which slots are currently in use
*/
bool *slot_in_use; bool *slot_in_use;
/**
* @brief Mutex protecting allocator operations for thread safety
*/
pva_kmd_mutex_t allocator_lock; pva_kmd_mutex_t allocator_lock;
}; };
/**
* @brief Initialize a block allocator with specified memory and parameters
*
* @details This function performs the following operations:
* - Initializes the allocator structure with provided memory region
* - Sets up the free list linking all available blocks
* - Configures block size and maximum block count parameters
* - Initializes the usage tracking array for allocated blocks
* - Sets up mutex for thread-safe allocation operations
* - Establishes base ID for block identification
* - Prepares the allocator for block allocation and deallocation
*
* The provided memory region must be large enough to hold max_num_chunks
* blocks of chunk_size bytes each. After successful initialization, blocks
* can be allocated using @ref pva_kmd_alloc_block() and freed using
* @ref pva_kmd_free_block().
*
* @param[out] allocator Pointer to @ref pva_kmd_block_allocator structure to initialize
* Valid value: non-null
* @param[in] chunk_mem Pointer to pre-allocated memory for block storage
* Valid value: non-null, must be at least
* (chunk_size * max_num_chunks) bytes
* @param[in] base_id Base identifier for allocated blocks
* Valid range: [0 .. UINT32_MAX]
* @param[in] chunk_size Size of each block in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[in] max_num_chunks Maximum number of blocks that can be allocated
* Valid range: [1 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Allocator initialized successfully
* @retval PVA_NOMEM Failed to allocate memory for slot tracking array
*/
enum pva_error enum pva_error
pva_kmd_block_allocator_init(struct pva_kmd_block_allocator *allocator, pva_kmd_block_allocator_init(struct pva_kmd_block_allocator *allocator,
void *chunk_mem, uint32_t base_id, void *chunk_mem, uint32_t base_id,
uint32_t chunk_size, uint32_t max_num_chunks); uint32_t chunk_size, uint32_t max_num_chunks);
/**
* @brief Allocate a block from the allocator (thread-safe version)
*
* @details This function performs the following operations:
* - Acquires the allocator mutex for thread-safe operation
* - Checks if any blocks are available for allocation
* - Removes a block from the free list if available
* - Marks the block as in use in the usage tracking array
* - Assigns a unique block ID based on the base ID and slot index
* - Returns pointer to the allocated block and its ID
* - Releases the allocator mutex after completion
*
* The allocated block remains valid until it is freed using
* @ref pva_kmd_free_block(). The block ID can be used to reference
* the block in other operations or to free it later.
*
* @param[in, out] allocator Pointer to @ref pva_kmd_block_allocator structure
* Valid value: non-null, must be initialized
* @param[out] out_id Pointer to store the allocated block ID
* Valid value: non-null
*
* @retval non-null Pointer to allocated block if successful
* @retval NULL No blocks available for allocation
*/
void *pva_kmd_alloc_block(struct pva_kmd_block_allocator *allocator, void *pva_kmd_alloc_block(struct pva_kmd_block_allocator *allocator,
uint32_t *out_id); uint32_t *out_id);
/**
* @brief Allocate a block from the allocator (unsafe version)
*
* @details This function performs the following operations:
* - Checks if any blocks are available for allocation
* - Removes a block from the free list if available
* - Marks the block as in use in the usage tracking array
* - Assigns a unique block ID based on the base ID and slot index
* - Returns pointer to the allocated block and its ID
*
* This function is not thread-safe and requires external synchronization.
* The caller must ensure proper locking around calls to this function and
* the corresponding @ref pva_kmd_free_block_unsafe().
*
* @param[in, out] allocator Pointer to @ref pva_kmd_block_allocator structure
* Valid value: non-null, must be initialized
* @param[out] out_id Pointer to store the allocated block ID
* Valid value: non-null
*
* @retval non-null Pointer to allocated block if successful
* @retval NULL No blocks available for allocation
*/
void *pva_kmd_alloc_block_unsafe(struct pva_kmd_block_allocator *allocator, void *pva_kmd_alloc_block_unsafe(struct pva_kmd_block_allocator *allocator,
uint32_t *out_id); uint32_t *out_id);
/**
* @brief Allocate and zero-initialize a block from the allocator
*
* @details This function performs the following operations:
* - Calls @ref pva_kmd_alloc_block() to allocate a block
* - Zero-initializes the entire block using @ref memset()
* - Returns pointer to the zero-initialized block
* - Provides the allocated block ID through the output parameter
*
* This inline function provides a convenient way to allocate blocks that
* need to be initialized to zero. The zero initialization covers the entire
* block size as specified during allocator initialization.
*
* @param[in, out] allocator Pointer to @ref pva_kmd_block_allocator structure
* Valid value: non-null, must be initialized
* @param[out] out_id Pointer to store the allocated block ID
* Valid value: non-null
*
* @retval non-null Pointer to zero-initialized allocated block if successful
* @retval NULL No blocks available for allocation
*/
static inline void * static inline void *
pva_kmd_zalloc_block(struct pva_kmd_block_allocator *allocator, pva_kmd_zalloc_block(struct pva_kmd_block_allocator *allocator,
uint32_t *out_id) uint32_t *out_id)
{ {
void *ptr = pva_kmd_alloc_block(allocator, out_id); void *ptr = pva_kmd_alloc_block(allocator, out_id);
if (ptr != NULL) { if (ptr != NULL) {
memset(ptr, 0, allocator->block_size); (void)memset(ptr, 0, allocator->block_size);
} }
return ptr; return ptr;
} }
/** This API is not thread safe and has to be explicitly locked during use of the obtained block. /**
* @brief Get pointer to a block by ID without allocation (unsafe version)
*
* @details This function performs the following operations:
* - Validates the provided block ID against the allocator's range
* - Calculates the memory address of the block from the ID
* - Returns pointer to the block without changing its allocation state
* - Does not perform any allocation or reference counting
*
* This API is not thread safe and has to be explicitly locked during use of the obtained block.
* This is to ensure that a parallel free operation does not result in dangling pointer to obtained block. * This is to ensure that a parallel free operation does not result in dangling pointer to obtained block.
* Correct usage: * Correct usage:
* lock(allocator) * lock(allocator)
* block - pva_kmd_get_block_unsafe(); * block - @ref pva_kmd_get_block_unsafe();
* use block * use block
* unlock(allocator) * unlock(allocator)
*
* @param[in] allocator Pointer to @ref pva_kmd_block_allocator structure
* Valid value: non-null, must be initialized
* @param[in] id Block ID to retrieve
* Valid range: [base_id .. base_id+max_num_blocks-1]
*
* @retval non-null Pointer to the block if ID is valid
* @retval NULL Invalid block ID or allocator not properly initialized
*/ */
void *pva_kmd_get_block_unsafe(struct pva_kmd_block_allocator *allocator, void *pva_kmd_get_block_unsafe(struct pva_kmd_block_allocator *allocator,
uint32_t id); uint32_t id);
/**
* @brief Free a previously allocated block (thread-safe version)
*
* @details This function performs the following operations:
* - Acquires the allocator mutex for thread-safe operation
* - Validates the provided block ID against allocated blocks
* - Marks the block as no longer in use in the usage tracking array
* - Adds the block back to the free list for future allocation
* - Updates allocator state to reflect the freed block
* - Releases the allocator mutex after completion
*
* The block ID must correspond to a previously allocated block. After
* freeing, the block becomes available for future allocation and the
* ID should not be used to access the block.
*
* @param[in, out] allocator Pointer to @ref pva_kmd_block_allocator structure
* Valid value: non-null, must be initialized
* @param[in] id Block ID to free
* Valid range: [base_id .. base_id+max_num_blocks-1]
*
* @retval PVA_SUCCESS Block freed successfully
* @retval PVA_INVAL Invalid block ID or block not allocated
*/
enum pva_error pva_kmd_free_block(struct pva_kmd_block_allocator *allocator, enum pva_error pva_kmd_free_block(struct pva_kmd_block_allocator *allocator,
uint32_t id); uint32_t id);
/**
* @brief Free a previously allocated block (unsafe version)
*
* @details This function performs the following operations:
* - Validates the provided block ID against allocated blocks
* - Marks the block as no longer in use in the usage tracking array
* - Adds the block back to the free list for future allocation
* - Updates allocator state to reflect the freed block
*
* This function is not thread-safe and requires external synchronization.
* The caller must ensure proper locking around calls to this function and
* the corresponding @ref pva_kmd_alloc_block_unsafe().
*
* @param[in, out] allocator Pointer to @ref pva_kmd_block_allocator structure
* Valid value: non-null, must be initialized
* @param[in] id Block ID to free
* Valid range: [base_id .. base_id+max_num_blocks-1]
*
* @retval PVA_SUCCESS Block freed successfully
* @retval PVA_INVAL Invalid block ID or block not allocated
*/
enum pva_error enum pva_error
pva_kmd_free_block_unsafe(struct pva_kmd_block_allocator *allocator, pva_kmd_free_block_unsafe(struct pva_kmd_block_allocator *allocator,
uint32_t id); uint32_t id);
/**
* @brief Deinitialize a block allocator and clean up resources
*
* @details This function performs the following operations:
* - Ensures no blocks are currently allocated (debugging builds)
* - Deinitializes the allocator mutex using @ref pva_kmd_mutex_deinit()
* - Cleans up internal allocator state and data structures
* - Invalidates the allocator for future use
* - Does not free the underlying memory region (caller's responsibility)
*
* All allocated blocks should be freed before calling this function.
* After deinitialization, the allocator cannot be used for block allocation
* until it is reinitialized. The underlying memory region provided during
* initialization is not freed and remains the caller's responsibility.
*
* @param[in, out] allocator Pointer to @ref pva_kmd_block_allocator structure to deinitialize
* Valid value: non-null, must be initialized
*/
void pva_kmd_block_allocator_deinit(struct pva_kmd_block_allocator *allocator); void pva_kmd_block_allocator_deinit(struct pva_kmd_block_allocator *allocator);
#endif // PVA_KMD_BLOCK_ALLOCATOR_H #endif // PVA_KMD_BLOCK_ALLOCATOR_H

View File

@@ -5,8 +5,8 @@
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_math_utils.h" #include "pva_math_utils.h"
#define CHUNK_STATE_INVALID 0 #define CHUNK_STATE_INVALID 0U
#define CHUNK_STATE_FENCE_TRIGGERED 1 #define CHUNK_STATE_FENCE_TRIGGERED 1U
static uint32_t * static uint32_t *
get_chunk_states(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool) get_chunk_states(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool)
@@ -20,15 +20,21 @@ static void *get_chunk(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool,
uint32_t chunk_id) uint32_t chunk_id)
{ {
return pva_offset_pointer(cmdbuf_chunk_pool->mem_base_va, return pva_offset_pointer(cmdbuf_chunk_pool->mem_base_va,
cmdbuf_chunk_pool->chunk_size * chunk_id); (uint64_t)cmdbuf_chunk_pool->chunk_size *
chunk_id);
} }
static uint32_t get_chunk_id_from_res_offset( static uint32_t get_chunk_id_from_res_offset(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint64_t offset) struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint64_t offset)
{ {
uint64_t chunk_id_u64;
ASSERT(offset >= cmdbuf_chunk_pool->mem_offset); ASSERT(offset >= cmdbuf_chunk_pool->mem_offset);
offset -= cmdbuf_chunk_pool->mem_offset; offset -= cmdbuf_chunk_pool->mem_offset;
return offset / cmdbuf_chunk_pool->chunk_size; chunk_id_u64 = offset / cmdbuf_chunk_pool->chunk_size;
/* chunk_id bounded by pool size and chunk size */
ASSERT(chunk_id_u64 <= U32_MAX);
return (uint32_t)chunk_id_u64;
} }
enum pva_error pva_kmd_cmdbuf_chunk_pool_init( enum pva_error pva_kmd_cmdbuf_chunk_pool_init(
@@ -49,41 +55,55 @@ enum pva_error pva_kmd_cmdbuf_chunk_pool_init(
cmdbuf_chunk_pool->chunk_size = chunk_size; cmdbuf_chunk_pool->chunk_size = chunk_size;
cmdbuf_chunk_pool->num_chunks = num_chunks; cmdbuf_chunk_pool->num_chunks = num_chunks;
cmdbuf_chunk_pool->mem_base_va = mem_base_va; cmdbuf_chunk_pool->mem_base_va = mem_base_va;
cmdbuf_chunk_pool->chunk_states_offset = chunk_size * num_chunks; cmdbuf_chunk_pool->chunk_states_offset =
(uint64_t)chunk_size * num_chunks;
chunk_states = get_chunk_states(cmdbuf_chunk_pool); chunk_states = get_chunk_states(cmdbuf_chunk_pool);
for (i = 0; i < num_chunks; i++) { for (i = 0U; i < num_chunks; i++) {
chunk_states[i] = CHUNK_STATE_INVALID; chunk_states[i] = CHUNK_STATE_INVALID;
} }
err = pva_kmd_block_allocator_init(&cmdbuf_chunk_pool->block_allocator, err = pva_kmd_block_allocator_init(&cmdbuf_chunk_pool->block_allocator,
mem_base_va, 0, chunk_size, mem_base_va, 0, chunk_size,
num_chunks); num_chunks);
pva_kmd_mutex_init(&cmdbuf_chunk_pool->chunk_state_lock); if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Failed to initialize block allocator for cmdbuf chunk pool");
return err;
}
err = pva_kmd_mutex_init(&cmdbuf_chunk_pool->chunk_state_lock);
return err; return err;
} }
void pva_kmd_cmdbuf_chunk_pool_deinit(struct pva_kmd_cmdbuf_chunk_pool *pool) void pva_kmd_cmdbuf_chunk_pool_deinit(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool)
{ {
pva_kmd_mutex_deinit(&pool->chunk_state_lock); pva_kmd_mutex_deinit(&cmdbuf_chunk_pool->chunk_state_lock);
pva_kmd_block_allocator_deinit(&pool->block_allocator); pva_kmd_block_allocator_deinit(&cmdbuf_chunk_pool->block_allocator);
} }
void pva_kmd_free_linked_cmdbuf_chunks(struct pva_kmd_cmdbuf_chunk_pool *pool, /* This function assumes locks are already held by caller */
uint32_t chunk_id) static void
pva_kmd_free_linked_cmdbuf_chunks_unsafe(struct pva_kmd_cmdbuf_chunk_pool *pool,
uint32_t chunk_id)
{ {
struct pva_cmd_link_chunk *begin; struct pva_cmd_link_chunk *begin;
uint32_t *chunk_states; uint32_t *chunk_states;
uint64_t offset; uint64_t offset;
uint32_t resource_id; uint32_t resource_id;
enum pva_error tmp_err;
chunk_states = get_chunk_states(pool); chunk_states = get_chunk_states(pool);
/* Caller must hold both allocator_lock and chunk_state_lock */
while (true) { while (true) {
begin = get_chunk(pool, chunk_id); begin = get_chunk(pool, chunk_id);
chunk_states[chunk_id] = CHUNK_STATE_INVALID; chunk_states[chunk_id] = CHUNK_STATE_INVALID;
offset = assemble_addr(begin->next_chunk_offset_hi, offset = assemble_addr(begin->next_chunk_offset_hi,
begin->next_chunk_offset_lo); begin->next_chunk_offset_lo);
resource_id = begin->next_chunk_resource_id; resource_id = begin->next_chunk_resource_id;
pva_kmd_free_block(&pool->block_allocator, chunk_id); /* Use unsafe version since caller already holds allocator_lock */
tmp_err = pva_kmd_free_block_unsafe(&pool->block_allocator,
chunk_id);
ASSERT(tmp_err == PVA_SUCCESS);
if (resource_id == PVA_RESOURCE_ID_INVALID) { if (resource_id == PVA_RESOURCE_ID_INVALID) {
break; break;
} }
@@ -93,6 +113,18 @@ void pva_kmd_free_linked_cmdbuf_chunks(struct pva_kmd_cmdbuf_chunk_pool *pool,
} }
} }
void pva_kmd_free_linked_cmdbuf_chunks(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id)
{
/* CERT CON35-C: Acquire locks in consistent order to prevent deadlock */
pva_kmd_mutex_lock(&cmdbuf_chunk_pool->block_allocator.allocator_lock);
pva_kmd_mutex_lock(&cmdbuf_chunk_pool->chunk_state_lock);
pva_kmd_free_linked_cmdbuf_chunks_unsafe(cmdbuf_chunk_pool, chunk_id);
pva_kmd_mutex_unlock(&cmdbuf_chunk_pool->chunk_state_lock);
pva_kmd_mutex_unlock(
&cmdbuf_chunk_pool->block_allocator.allocator_lock);
}
static bool recycle_chunks(struct pva_kmd_cmdbuf_chunk_pool *pool) static bool recycle_chunks(struct pva_kmd_cmdbuf_chunk_pool *pool)
{ {
uint32_t *chunk_states; uint32_t *chunk_states;
@@ -100,9 +132,10 @@ static bool recycle_chunks(struct pva_kmd_cmdbuf_chunk_pool *pool)
bool freed = false; bool freed = false;
chunk_states = get_chunk_states(pool); chunk_states = get_chunk_states(pool);
for (i = 0; i < pool->num_chunks; i++) { for (i = 0U; i < pool->num_chunks; i++) {
if (chunk_states[i] == CHUNK_STATE_FENCE_TRIGGERED) { if (chunk_states[i] == CHUNK_STATE_FENCE_TRIGGERED) {
pva_kmd_free_linked_cmdbuf_chunks(pool, i); /* Use unsafe version since caller already holds locks */
pva_kmd_free_linked_cmdbuf_chunks_unsafe(pool, i);
freed = true; freed = true;
break; break;
} }
@@ -112,38 +145,47 @@ static bool recycle_chunks(struct pva_kmd_cmdbuf_chunk_pool *pool)
} }
enum pva_error enum pva_error
pva_kmd_alloc_cmdbuf_chunk(struct pva_kmd_cmdbuf_chunk_pool *pool, pva_kmd_alloc_cmdbuf_chunk(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool,
uint32_t *out_chunk_id) uint32_t *out_chunk_id)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
void *chunk; void *chunk;
pva_kmd_mutex_lock(&pool->chunk_state_lock); /* CERT CON35-C: Acquire locks in consistent order to prevent deadlock.
chunk = pva_kmd_alloc_block(&pool->block_allocator, out_chunk_id); * Lock ordering: allocator_lock before chunk_state_lock
*/
pva_kmd_mutex_lock(&cmdbuf_chunk_pool->block_allocator.allocator_lock);
pva_kmd_mutex_lock(&cmdbuf_chunk_pool->chunk_state_lock);
chunk = pva_kmd_alloc_block_unsafe(&cmdbuf_chunk_pool->block_allocator,
out_chunk_id);
if (chunk == NULL) { if (chunk == NULL) {
if (recycle_chunks(pool)) { if (recycle_chunks(cmdbuf_chunk_pool)) {
chunk = pva_kmd_alloc_block(&pool->block_allocator, chunk = pva_kmd_alloc_block_unsafe(
out_chunk_id); &cmdbuf_chunk_pool->block_allocator,
out_chunk_id);
ASSERT(chunk != NULL); ASSERT(chunk != NULL);
} else { } else {
err = PVA_NOMEM; err = PVA_NOMEM;
} }
} }
pva_kmd_mutex_unlock(&pool->chunk_state_lock); pva_kmd_mutex_unlock(&cmdbuf_chunk_pool->chunk_state_lock);
pva_kmd_mutex_unlock(
&cmdbuf_chunk_pool->block_allocator.allocator_lock);
return err; return err;
} }
void pva_kmd_get_free_notifier_fence(struct pva_kmd_cmdbuf_chunk_pool *pool, void pva_kmd_get_free_notifier_fence(
uint32_t chunk_id, struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id,
struct pva_fw_postfence *fence) struct pva_fw_postfence *fence)
{ {
uint64_t offset_sum = uint64_t offset_sum =
safe_addu64(pool->mem_offset, pool->chunk_states_offset); safe_addu64(cmdbuf_chunk_pool->mem_offset,
cmdbuf_chunk_pool->chunk_states_offset);
uint64_t chunk_size = uint64_t chunk_size =
(uint64_t)safe_mulu32((uint32_t)sizeof(uint32_t), chunk_id); (uint64_t)safe_mulu32((uint32_t)sizeof(uint32_t), chunk_id);
uint64_t state_offset = safe_addu64(offset_sum, chunk_size); uint64_t state_offset = safe_addu64(offset_sum, chunk_size);
memset(fence, 0, sizeof(*fence)); (void)memset(fence, 0, sizeof(*fence));
fence->resource_id = pool->mem_resource_id; fence->resource_id = cmdbuf_chunk_pool->mem_resource_id;
fence->offset_lo = iova_lo(state_offset); fence->offset_lo = iova_lo(state_offset);
fence->offset_hi = iova_hi(state_offset); fence->offset_hi = iova_hi(state_offset);
fence->value = CHUNK_STATE_FENCE_TRIGGERED; fence->value = CHUNK_STATE_FENCE_TRIGGERED;
@@ -162,11 +204,12 @@ static void begin_chunk(struct pva_kmd_cmdbuf_builder *builder)
{ {
struct pva_cmd_link_chunk *cmd = pva_kmd_get_cmdbuf_chunk_va( struct pva_cmd_link_chunk *cmd = pva_kmd_get_cmdbuf_chunk_va(
builder->pool, builder->current_chunk_id); builder->pool, builder->current_chunk_id);
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_LINK_CHUNK; cmd->header.opcode = PVA_CMD_OPCODE_LINK_CHUNK;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->next_chunk_resource_id = PVA_RESOURCE_ID_INVALID; cmd->next_chunk_resource_id = PVA_RESOURCE_ID_INVALID;
builder->current_chunk_offset = sizeof(*cmd); /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
builder->current_chunk_offset = (uint16_t)sizeof(*cmd);
} }
static void end_chunk(struct pva_kmd_cmdbuf_builder *builder) static void end_chunk(struct pva_kmd_cmdbuf_builder *builder)
@@ -237,7 +280,8 @@ pva_kmd_cmdbuf_builder_init(struct pva_kmd_cmdbuf_builder *builder,
struct pva_kmd_cmdbuf_chunk_pool *chunk_pool) struct pva_kmd_cmdbuf_chunk_pool *chunk_pool)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
uint32_t const min_chunk_size = sizeof(struct pva_cmd_link_chunk); uint32_t const min_chunk_size =
(uint32_t)sizeof(struct pva_cmd_link_chunk);
ASSERT(chunk_pool->chunk_size >= min_chunk_size); ASSERT(chunk_pool->chunk_size >= min_chunk_size);

View File

@@ -9,29 +9,94 @@
#include "pva_api_cmdbuf.h" #include "pva_api_cmdbuf.h"
#include "pva_utils.h" #include "pva_utils.h"
#include "pva_math_utils.h" #include "pva_math_utils.h"
#include "pva_kmd_limits.h"
struct pva_kmd_queue; struct pva_kmd_queue;
/** /**
* A fixed-size pool of command buffer chunks. * @brief Fixed-size pool of command buffer chunks for efficient allocation
* *
* We can allocate chunks from this pool. When submitting the chunks, we should * @details A fixed-size pool of command buffer chunks designed for efficient
* request a post fence from the pool for the first chunk. When the post fence * command buffer allocation and management. The pool allocates chunks from
* is triggered, the chain of chunks will be considered free by the pool. * a pre-allocated memory region and provides automatic cleanup through post
* fence notifications. When submitting chunks, a post fence should be requested
* for the first chunk, and when the fence is triggered, the entire chain of
* chunks is automatically freed by the pool.
*/ */
struct pva_kmd_cmdbuf_chunk_pool { struct pva_kmd_cmdbuf_chunk_pool {
/**
* @brief Size of each chunk in bytes
* Valid range: [1 .. UINT16_MAX]
*/
uint16_t chunk_size; uint16_t chunk_size;
/**
* @brief Total number of chunks in the pool
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t num_chunks; uint32_t num_chunks;
/**
* @brief Resource ID of the memory used for this pool
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t mem_resource_id; uint32_t mem_resource_id;
/**
* @brief Total size of memory allocated for the pool
* Valid range: [chunk_size .. UINT64_MAX]
*/
uint64_t mem_size; uint64_t mem_size;
uint64_t mem_offset; /**< Starting offset in the resource that can be
* used by this pool */ /**
* @brief Starting offset within the resource for this pool
*
* @details Starting offset in the resource that can be used by this pool
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t mem_offset;
/**
* @brief Offset to chunk state tracking information
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t chunk_states_offset; uint64_t chunk_states_offset;
/**
* @brief Virtual address base pointer for pool memory access
*/
void *mem_base_va; void *mem_base_va;
/**
* @brief Block allocator for managing chunk allocation within the pool
*/
struct pva_kmd_block_allocator block_allocator; struct pva_kmd_block_allocator block_allocator;
/**
* @brief Mutex protecting chunk state modifications
*/
pva_kmd_mutex_t chunk_state_lock; pva_kmd_mutex_t chunk_state_lock;
}; };
/**
* @brief Calculate required memory size for a command buffer chunk pool
*
* @details This function performs the following operations:
* - Calculates the memory needed for all chunks of the specified size
* - Adds storage space required for free notifier fences (uint32_t per chunk)
* - Returns the total memory requirement for pool initialization
* - Accounts for chunk state tracking and fence notification overhead
*
* The returned size should be used when allocating memory for pool
* initialization with @ref pva_kmd_cmdbuf_chunk_pool_init().
*
* @param[in] chunk_size Size of each chunk in bytes
* Valid range: [1 .. UINT16_MAX]
* @param[in] num_chunks Number of chunks in the pool
* Valid range: [1 .. UINT32_MAX]
*
* @retval memory_size Total memory size required for the pool in bytes
*/
static inline uint64_t static inline uint64_t
pva_kmd_cmdbuf_pool_get_required_mem_size(uint16_t chunk_size, pva_kmd_cmdbuf_pool_get_required_mem_size(uint16_t chunk_size,
uint32_t num_chunks) uint32_t num_chunks)
@@ -41,69 +106,201 @@ pva_kmd_cmdbuf_pool_get_required_mem_size(uint16_t chunk_size,
} }
/** /**
* Initialize the chunk pool. * @brief Initialize a command buffer chunk pool
* *
* @param[out] Pointer to the pool. * @details This function performs the following operations:
* - Initializes the chunk pool structure with provided memory and parameters
* - Sets up the block allocator for managing individual chunk allocation
* - Configures chunk size, count, and memory layout parameters
* - Establishes virtual address mapping for pool memory access
* - Initializes synchronization primitives for thread-safe operations
* - Prepares free notifier fence storage for automatic chunk cleanup
* - Associates the pool with the specified memory resource
* *
* @param[in] mem_resource_id Resource ID of the memory to be used for the pool. * The chunk pool enables efficient allocation and automatic cleanup of
* command buffer chunks. After initialization, chunks can be allocated using
* @ref pva_kmd_alloc_cmdbuf_chunk() and will be automatically freed when
* their associated fence is triggered.
* *
* @param[in] mem_offset Offset of the memory to be used for the pool. * @param[out] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure to initialize
* Valid value: non-null
* @param[in] mem_size Size of the memory to be used for the pool. * @param[in] mem_resource_id Resource ID of the memory for the pool
* Valid range: [0 .. UINT32_MAX]
* @param[in] mem_offset Offset within the resource for pool memory
* Valid range: [0 .. UINT64_MAX]
* @param[in] mem_size Size of memory allocated for the pool
* Valid range: [required_size .. UINT32_MAX]
* @param[in] chunk_size Size of each chunk in bytes
* Valid range: [1 .. UINT16_MAX]
* @param[in] num_chunks Number of chunks in the pool
* Valid range: [1 .. UINT32_MAX]
* @param[in] mem_base_va Virtual address base of the memory resource
* Valid value: non-null
* *
* @param[in] chunk_size Size of each chunk in the pool. * @retval PVA_SUCCESS Pool initialized successfully
* * @retval PVA_NOMEM Failed to initialize block allocator
* @param[in] num_chunks Number of chunks in the pool.
*
* @param[in] mem_base_va Virtual address of the memory to be used for the pool.
* The virtual address is the base address of the resource.
*/ */
enum pva_error pva_kmd_cmdbuf_chunk_pool_init( enum pva_error pva_kmd_cmdbuf_chunk_pool_init(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool,
uint32_t mem_resource_id, uint64_t mem_offset, uint32_t mem_size, uint32_t mem_resource_id, uint64_t mem_offset, uint32_t mem_size,
uint16_t chunk_size, uint32_t num_chunks, void *mem_base_va); uint16_t chunk_size, uint32_t num_chunks, void *mem_base_va);
/**
* @brief Deinitialize a command buffer chunk pool and clean up resources
*
* @details This function performs the following operations:
* - Ensures all chunks have been properly freed and returned to the pool
* - Deinitializes the block allocator used for chunk management
* - Destroys synchronization primitives including mutexes
* - Cleans up internal pool state and data structures
* - Invalidates the pool for future use
* - Does not free the underlying memory resource (caller's responsibility)
*
* All chunks should be freed before calling this function. After
* deinitialization, the pool cannot be used for chunk allocation until
* it is reinitialized.
*
* @param[in, out] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure
* to deinitialize
* Valid value: non-null, must be initialized
*/
void pva_kmd_cmdbuf_chunk_pool_deinit( void pva_kmd_cmdbuf_chunk_pool_deinit(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool); struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool);
/** /**
* Allocate a chunk from the pool. * @brief Allocate a command buffer chunk from the pool
* *
* If the chunk is submitted, then free will be done automatically when * @details This function performs the following operations:
* free-notifier fence is triggered. * - Allocates a chunk from the pool using the internal block allocator
* - Returns a unique chunk ID for referencing the allocated chunk
* - Marks the chunk as in use within the pool's tracking system
* - Provides chunk memory for command buffer construction
* - Enables automatic cleanup when the chunk is submitted with a fence
*
* If the chunk is submitted with a free-notifier fence, the chunk will be
* automatically freed when the fence is triggered. If the chunk is not
* submitted, it should be manually freed using @ref pva_kmd_free_linked_cmdbuf_chunks()
* to avoid memory leaks.
*
* @param[in, out] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure
* Valid value: non-null, must be initialized
* @param[out] out_chunk_id Pointer to store the allocated chunk ID
* Valid value: non-null
*
* @retval PVA_SUCCESS Chunk allocated successfully
* @retval PVA_NOMEM No chunks available in the pool
*/ */
enum pva_error enum pva_error
pva_kmd_alloc_cmdbuf_chunk(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, pva_kmd_alloc_cmdbuf_chunk(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool,
uint32_t *out_chunk_id); uint32_t *out_chunk_id);
/** /**
* Free a linked list of chunks. * @brief Free a linked list of command buffer chunks
* *
* We only need to call this function if we decide not to submit the chunks, * @details This function performs the following operations:
* usually in error path. * - Traverses the linked list of chunks starting from the specified chunk ID
* - Frees each chunk in the chain back to the pool for reuse
* - Updates pool state to reflect the freed chunks
* - Handles chunk linking and ensures proper cleanup of the entire chain
* - Resets chunk state tracking for the freed chunks
*
* This function should only be called if the chunks are not submitted,
* typically in error paths where command buffer construction fails.
* For submitted chunks, automatic cleanup occurs when the free-notifier
* fence is triggered, making manual cleanup unnecessary.
*
* @param[in, out] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure
* Valid value: non-null, must be initialized
* @param[in] chunk_id ID of the first chunk in the linked list to free
* Valid range: Valid chunk ID from previous allocation
*/ */
void pva_kmd_free_linked_cmdbuf_chunks( void pva_kmd_free_linked_cmdbuf_chunks(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id); struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id);
/** /**
* Get the free-notifier fence. * @brief Get the free-notifier fence for automatic chunk cleanup
* *
* @param[in] The first chunk of the command buffer to be submitted. * @details This function performs the following operations:
* - Configures a post fence for automatic chunk cleanup upon completion
* - Associates the fence with the specified chunk for cleanup tracking
* - Sets up the fence to trigger when the command buffer completes execution
* - Enables automatic return of chunks to the pool when work is finished
* - Configures fence parameters for proper cleanup timing
* *
* @param[out] The free-notifier fence that should be submitted with the command buffer. * The returned fence should be submitted along with the command buffer
* to enable automatic cleanup. When the fence is triggered by firmware
* upon command completion, all linked chunks starting from the specified
* chunk will be automatically freed and returned to the pool.
*
* @param[in] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure
* Valid value: non-null, must be initialized
* @param[in] chunk_id ID of the first chunk in the command buffer to be submitted
* Valid range: Valid chunk ID from previous allocation
* @param[out] fence Pointer to @ref pva_fw_postfence structure to configure
* Valid value: non-null
*/ */
void pva_kmd_get_free_notifier_fence( void pva_kmd_get_free_notifier_fence(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id, struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id,
struct pva_fw_postfence *fence); struct pva_fw_postfence *fence);
/**
* @brief Get virtual address pointer for a command buffer chunk
*
* @details This function performs the following operations:
* - Calculates the virtual memory address for the specified chunk
* - Uses the chunk ID and pool's base address for address calculation
* - Returns a pointer suitable for writing command data
* - Provides direct memory access to the chunk's storage area
* - Enables efficient command buffer construction in allocated chunks
*
* The returned pointer can be used to write command data directly into
* the chunk memory. The pointer remains valid until the chunk is freed
* or the pool is deinitialized.
*
* @param[in] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure
* Valid value: non-null, must be initialized
* @param[in] chunk_id Chunk ID to get virtual address for
* Valid range: Valid chunk ID from previous allocation
*
* @retval pointer Virtual address pointer to the chunk memory
*/
static inline void * static inline void *
pva_kmd_get_cmdbuf_chunk_va(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, pva_kmd_get_cmdbuf_chunk_va(struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool,
uint32_t chunk_id) uint32_t chunk_id)
{ {
return (void *)((uintptr_t)cmdbuf_chunk_pool->mem_base_va + /* Use byte pointer arithmetic to avoid INT36-C violation */
chunk_id * cmdbuf_chunk_pool->chunk_size); char *base;
size_t offset;
/* Verify alignment for proper access */
ASSERT(cmdbuf_chunk_pool->chunk_size % sizeof(uint32_t) == 0U);
base = (char *)cmdbuf_chunk_pool->mem_base_va;
offset = (size_t)chunk_id * cmdbuf_chunk_pool->chunk_size;
return (void *)(base + offset);
} }
/**
* @brief Get resource offset for a command buffer chunk
*
* @details This function performs the following operations:
* - Calculates the offset of the chunk within the memory resource
* - Uses safe arithmetic to prevent overflow during calculation
* - Adds the pool's memory offset to the chunk-specific offset
* - Returns the absolute offset for firmware addressing
* - Enables proper IOVA calculations for hardware access
*
* The returned offset can be used by firmware to calculate IOVA addresses
* for accessing the chunk memory during command execution. The offset is
* relative to the base of the memory resource.
*
* @param[in] cmdbuf_chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool structure
* Valid value: non-null, must be initialized
* @param[in] chunk_id Chunk ID to get resource offset for
* Valid range: Valid chunk ID from previous allocation
*
* @retval offset Resource offset of the chunk in bytes
*/
static inline uint64_t pva_kmd_get_cmdbuf_chunk_res_offset( static inline uint64_t pva_kmd_get_cmdbuf_chunk_res_offset(
struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id) struct pva_kmd_cmdbuf_chunk_pool *cmdbuf_chunk_pool, uint32_t chunk_id)
{ {
@@ -113,52 +310,198 @@ static inline uint64_t pva_kmd_get_cmdbuf_chunk_res_offset(
} }
/** /**
* Utility for building a command buffer with multiple chunks. * @brief Utility for building command buffers with automatic chunk management
* *
* The builder will automatically allocate chunks from the pool when the current * @details This structure provides a convenient interface for building command
* chunk is full. * buffers that may span multiple chunks. The builder automatically allocates
* new chunks from the pool when the current chunk becomes full, links chunks
* together with appropriate commands, and manages the overall command buffer
* structure. It simplifies command buffer construction by handling chunk
* boundaries and linking transparently.
*/ */
struct pva_kmd_cmdbuf_builder { struct pva_kmd_cmdbuf_builder {
/**
* @brief Size of the first chunk in the command buffer
* Valid range: [1 .. UINT16_MAX]
*/
uint16_t first_chunk_size; uint16_t first_chunk_size;
/**
* @brief Current write offset within the active chunk
* Valid range: [0 .. chunk_size-1]
*/
uint16_t current_chunk_offset; uint16_t current_chunk_offset;
/**
* @brief Chunk ID of the first chunk in the command buffer
* Valid range: Valid chunk ID from pool allocation
*/
uint32_t first_chunk_id; uint32_t first_chunk_id;
/**
* @brief Chunk ID of the currently active chunk being written
* Valid range: Valid chunk ID from pool allocation
*/
uint32_t current_chunk_id; uint32_t current_chunk_id;
/**
* @brief Pointer to the chunk pool for automatic allocation
*/
struct pva_kmd_cmdbuf_chunk_pool *pool; struct pva_kmd_cmdbuf_chunk_pool *pool;
uint16_t *chunk_size_ptr; /**< Pointer to the chunk size field of the previous link_chunk command */
/**
* @brief Pointer to chunk size field of the previous link_chunk command
*
* @details Pointer to the chunk size field of the previous link_chunk command
*/
uint16_t *chunk_size_ptr;
}; };
/**
* @brief Initialize a command buffer builder with the specified chunk pool
*
* @details This function performs the following operations:
* - Initializes the builder structure with the provided chunk pool
* - Allocates the first chunk from the pool for command buffer construction
* - Sets up internal state for tracking chunk usage and linking
* - Prepares the builder for command addition through @ref pva_kmd_reserve_cmd_space()
* - Configures chunk linking and boundary management
* - Establishes the foundation for multi-chunk command buffer construction
*
* The initialized builder can be used to construct command buffers by
* reserving space for commands and writing command data. The builder
* automatically handles chunk allocation and linking as needed.
*
* @param[out] builder Pointer to @ref pva_kmd_cmdbuf_builder structure to initialize
* Valid value: non-null
* @param[in] chunk_pool Pointer to @ref pva_kmd_cmdbuf_chunk_pool for chunk allocation
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS Builder initialized successfully
* @retval PVA_NOMEM Failed to allocate initial chunk from pool
*/
enum pva_error enum pva_error
pva_kmd_cmdbuf_builder_init(struct pva_kmd_cmdbuf_builder *builder, pva_kmd_cmdbuf_builder_init(struct pva_kmd_cmdbuf_builder *builder,
struct pva_kmd_cmdbuf_chunk_pool *chunk_pool); struct pva_kmd_cmdbuf_chunk_pool *chunk_pool);
/**
* @brief Reserve space in the command buffer for writing command data
*
* @details This function performs the following operations:
* - Checks if the current chunk has sufficient space for the requested size
* - Allocates a new chunk and links it if the current chunk is insufficient
* - Updates chunk linking commands to maintain proper command buffer structure
* - Returns a pointer to the reserved memory space for command writing
* - Advances internal tracking to account for the reserved space
* - Handles chunk boundaries transparently for the caller
*
* The returned pointer can be used to write command data directly. The
* space remains reserved until the next call to this function or until
* the builder is finalized or cancelled.
*
* @param[in, out] builder Pointer to @ref pva_kmd_cmdbuf_builder structure
* Valid value: non-null, must be initialized
* @param[in] size Number of bytes to reserve for command data
* Valid range: [1 .. chunk_size]
*
* @retval non-null Pointer to reserved memory space for command writing
* @retval NULL Failed to allocate new chunk or insufficient space
*/
void *pva_kmd_reserve_cmd_space(struct pva_kmd_cmdbuf_builder *builder, void *pva_kmd_reserve_cmd_space(struct pva_kmd_cmdbuf_builder *builder,
uint16_t size); uint16_t size);
/**
* @brief Finalize command buffer construction and get submission parameters
*
* @details This function performs the following operations:
* - Completes the command buffer construction process
* - Updates the final chunk size for the last chunk used
* - Prepares the command buffer for submission to the firmware
* - Returns the first chunk ID and size for submission setup
* - Ensures proper command buffer termination and linking
* - Transfers ownership of chunks from builder to submission system
*
* After finalization, the builder should not be used for further command
* construction. The returned chunk ID and size should be used for command
* buffer submission through the queue system.
*
* @param[in, out] builder Pointer to @ref pva_kmd_cmdbuf_builder structure
* Valid value: non-null, must be initialized with commands
* @param[out] out_first_chunk_id Pointer to store the first chunk ID
* Valid value: non-null
* @param[out] out_first_chunk_size Pointer to store the first chunk size
* Valid value: non-null
*/
void pva_kmd_cmdbuf_builder_finalize(struct pva_kmd_cmdbuf_builder *builder, void pva_kmd_cmdbuf_builder_finalize(struct pva_kmd_cmdbuf_builder *builder,
uint32_t *out_first_chunk_id, uint32_t *out_first_chunk_id,
uint16_t *out_first_chunk_size); uint16_t *out_first_chunk_size);
/**
* @brief Cancel command buffer construction and free allocated chunks
*
* @details This function performs the following operations:
* - Cancels the command buffer construction process
* - Frees all chunks allocated by the builder back to the pool
* - Cleans up internal builder state and chunk linking
* - Ensures no memory leaks from partially constructed command buffers
* - Invalidates the builder for future use without reinitialization
*
* This function should be called when command buffer construction fails
* or is cancelled before completion. It ensures proper cleanup of all
* resources allocated during the construction process.
*
* @param[in, out] builder Pointer to @ref pva_kmd_cmdbuf_builder structure to cancel
* Valid value: non-null, must be initialized
*/
void pva_kmd_cmdbuf_builder_cancel(struct pva_kmd_cmdbuf_builder *builder); void pva_kmd_cmdbuf_builder_cancel(struct pva_kmd_cmdbuf_builder *builder);
/**
* @brief Initialize a resource table initialization command
*
* @details This function performs the following operations:
* - Initializes all fields of the command structure to appropriate values
* - Sets the command opcode to @ref PVA_CMD_OPCODE_INIT_RESOURCE_TABLE
* - Configures the resource table address using IOVA low and high parts
* - Sets the maximum number of entries supported by the resource table
* - Calculates and sets the command length based on structure size
* - Prepares the command for submission to firmware
*
* This inline function provides a convenient way to construct resource table
* initialization commands with proper field setup and validation. The
* command instructs firmware to initialize its resource table handling
* for the specified resource table.
*
* @param[out] cmd Pointer to @ref pva_cmd_init_resource_table command structure
* Valid value: non-null
* @param[in] resource_table_id Resource table identifier
* Valid range: [0 .. PVA_KMD_MAX_NUM_KMD_RESOURCES-1]
* @param[in] iova_addr IOVA address of the resource table
* Valid range: [0 .. UINT64_MAX]
* @param[in] max_num_entries Maximum number of entries in the resource table
* Valid range: [1 .. UINT32_MAX]
*/
static inline void pva_kmd_set_cmd_init_resource_table( static inline void pva_kmd_set_cmd_init_resource_table(
struct pva_cmd_init_resource_table *cmd, uint8_t resource_table_id, struct pva_cmd_init_resource_table *cmd, uint8_t resource_table_id,
uint64_t iova_addr, uint32_t max_num_entries) uint64_t iova_addr, uint32_t max_num_entries, uint64_t ctx_status_addr)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_INIT_RESOURCE_TABLE; cmd->header.opcode = PVA_CMD_OPCODE_INIT_RESOURCE_TABLE;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->resource_table_id = resource_table_id; cmd->resource_table_id = resource_table_id;
cmd->resource_table_addr_lo = iova_lo(iova_addr); cmd->resource_table_addr_lo = iova_lo(iova_addr);
cmd->resource_table_addr_hi = iova_hi(iova_addr); cmd->resource_table_addr_hi = iova_hi(iova_addr);
cmd->max_n_entries = max_num_entries; cmd->max_n_entries = max_num_entries;
cmd->ctx_status_addr_lo = iova_lo(ctx_status_addr);
cmd->ctx_status_addr_hi = iova_hi(ctx_status_addr);
} }
static inline void static inline void
pva_kmd_set_cmd_deinit_resource_table(struct pva_cmd_deinit_resource_table *cmd, pva_kmd_set_cmd_deinit_resource_table(struct pva_cmd_deinit_resource_table *cmd,
uint8_t resource_table_id) uint8_t resource_table_id)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_DEINIT_RESOURCE_TABLE; cmd->header.opcode = PVA_CMD_OPCODE_DEINIT_RESOURCE_TABLE;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->resource_table_id = resource_table_id; cmd->resource_table_id = resource_table_id;
} }
@@ -169,9 +512,9 @@ static inline void pva_kmd_set_cmd_init_queue(struct pva_cmd_init_queue *cmd,
uint32_t syncpt_id, uint32_t syncpt_id,
uint64_t syncpt_addr) uint64_t syncpt_addr)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_INIT_QUEUE; cmd->header.opcode = PVA_CMD_OPCODE_INIT_QUEUE;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->ccq_id = ccq_id; cmd->ccq_id = ccq_id;
cmd->queue_id = queue_id; cmd->queue_id = queue_id;
cmd->queue_addr_lo = iova_lo(queue_addr); cmd->queue_addr_lo = iova_lo(queue_addr);
@@ -186,9 +529,9 @@ static inline void
pva_kmd_set_cmd_deinit_queue(struct pva_cmd_deinit_queue *cmd, uint8_t ccq_id, pva_kmd_set_cmd_deinit_queue(struct pva_cmd_deinit_queue *cmd, uint8_t ccq_id,
uint8_t queue_id) uint8_t queue_id)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_DEINIT_QUEUE; cmd->header.opcode = PVA_CMD_OPCODE_DEINIT_QUEUE;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->ccq_id = ccq_id; cmd->ccq_id = ccq_id;
cmd->queue_id = queue_id; cmd->queue_id = queue_id;
} }
@@ -198,13 +541,15 @@ static inline void pva_kmd_set_cmd_update_resource_table(
uint32_t resource_id, struct pva_resource_entry const *entry, uint32_t resource_id, struct pva_resource_entry const *entry,
struct pva_resource_aux_info const *aux_info) struct pva_resource_aux_info const *aux_info)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_UPDATE_RESOURCE_TABLE; cmd->header.opcode = PVA_CMD_OPCODE_UPDATE_RESOURCE_TABLE;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->resource_table_id = resource_table_id; /* resource_table_id field is uint8_t - bounded by CCQ ID (max 7) */
ASSERT(resource_table_id <= (uint32_t)U8_MAX);
cmd->resource_table_id = (uint8_t)resource_table_id;
cmd->resource_id = resource_id; cmd->resource_id = resource_id;
cmd->entry = *entry; cmd->entry = *entry;
if (aux_info) { if (aux_info != NULL) {
cmd->aux_info = *aux_info; cmd->aux_info = *aux_info;
} }
} }
@@ -213,9 +558,9 @@ static inline void
pva_kmd_set_cmd_unregister_resource(struct pva_cmd_unregister_resource *cmd, pva_kmd_set_cmd_unregister_resource(struct pva_cmd_unregister_resource *cmd,
uint32_t resource_id) uint32_t resource_id)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_UNREGISTER_RESOURCE; cmd->header.opcode = PVA_CMD_OPCODE_UNREGISTER_RESOURCE;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->resource_id = resource_id; cmd->resource_id = resource_id;
} }
@@ -223,9 +568,9 @@ static inline void
pva_kmd_set_cmd_enable_fw_profiling(struct pva_cmd_enable_fw_profiling *cmd, pva_kmd_set_cmd_enable_fw_profiling(struct pva_cmd_enable_fw_profiling *cmd,
uint32_t filter, uint8_t timestamp_type) uint32_t filter, uint8_t timestamp_type)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_ENABLE_FW_PROFILING; cmd->header.opcode = PVA_CMD_OPCODE_ENABLE_FW_PROFILING;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->filter = filter; cmd->filter = filter;
cmd->timestamp_type = timestamp_type; cmd->timestamp_type = timestamp_type;
} }
@@ -233,18 +578,18 @@ pva_kmd_set_cmd_enable_fw_profiling(struct pva_cmd_enable_fw_profiling *cmd,
static inline void static inline void
pva_kmd_set_cmd_disable_fw_profiling(struct pva_cmd_disable_fw_profiling *cmd) pva_kmd_set_cmd_disable_fw_profiling(struct pva_cmd_disable_fw_profiling *cmd)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_DISABLE_FW_PROFILING; cmd->header.opcode = PVA_CMD_OPCODE_DISABLE_FW_PROFILING;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
} }
static inline void pva_kmd_set_cmd_get_tegra_stats( static inline void pva_kmd_set_cmd_get_tegra_stats(
struct pva_cmd_get_tegra_stats *cmd, uint32_t buffer_resource_id, struct pva_cmd_get_tegra_stats *cmd, uint32_t buffer_resource_id,
uint32_t buffer_size, uint64_t offset, bool enabled) uint32_t buffer_size, uint64_t offset, bool enabled)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_GET_TEGRA_STATS; cmd->header.opcode = PVA_CMD_OPCODE_GET_TEGRA_STATS;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->buffer_resource_id = buffer_resource_id; cmd->buffer_resource_id = buffer_resource_id;
cmd->buffer_offset_hi = iova_hi(offset); cmd->buffer_offset_hi = iova_hi(offset);
cmd->buffer_offset_lo = iova_lo(offset); cmd->buffer_offset_lo = iova_lo(offset);
@@ -256,45 +601,47 @@ static inline void
pva_kmd_set_cmd_set_trace_level(struct pva_cmd_set_trace_level *cmd, pva_kmd_set_cmd_set_trace_level(struct pva_cmd_set_trace_level *cmd,
uint32_t trace_level) uint32_t trace_level)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_SET_TRACE_LEVEL; cmd->header.opcode = PVA_CMD_OPCODE_SET_TRACE_LEVEL;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->trace_level = trace_level; cmd->trace_level = trace_level;
} }
static inline void pva_kmd_set_cmd_suspend_fw(struct pva_cmd_suspend_fw *cmd) static inline void pva_kmd_set_cmd_suspend_fw(struct pva_cmd_suspend_fw *cmd)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_SUSPEND_FW; cmd->header.opcode = PVA_CMD_OPCODE_SUSPEND_FW;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
} }
static inline void pva_kmd_set_cmd_resume_fw(struct pva_cmd_resume_fw *cmd) static inline void pva_kmd_set_cmd_resume_fw(struct pva_cmd_resume_fw *cmd)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_RESUME_FW; cmd->header.opcode = PVA_CMD_OPCODE_RESUME_FW;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
} }
static inline void pva_kmd_set_cmd_init_shared_dram_buffer( static inline void pva_kmd_set_cmd_init_shared_dram_buffer(
struct pva_cmd_init_shared_dram_buffer *cmd, uint8_t interface, struct pva_cmd_init_shared_dram_buffer *cmd, uint8_t interface,
uint32_t buffer_iova, uint32_t buffer_size) uint64_t buffer_iova, uint64_t buffer_size)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_INIT_SHARED_DRAM_BUFFER; cmd->header.opcode = PVA_CMD_OPCODE_INIT_SHARED_DRAM_BUFFER;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->buffer_iova_hi = iova_hi(buffer_iova); cmd->buffer_iova_hi = iova_hi(buffer_iova);
cmd->buffer_iova_lo = iova_lo(buffer_iova); cmd->buffer_iova_lo = iova_lo(buffer_iova);
cmd->buffer_size = buffer_size; /* CERT INT31-C: Hardware constrains buffer sizes to 32-bit address space */
ASSERT(buffer_size <= U32_MAX);
cmd->buffer_size = (uint32_t)buffer_size;
cmd->interface = interface; cmd->interface = interface;
} }
static inline void pva_kmd_set_cmd_deinit_shared_dram_buffer( static inline void pva_kmd_set_cmd_deinit_shared_dram_buffer(
struct pva_cmd_deinit_shared_dram_buffer *cmd, uint8_t interface) struct pva_cmd_deinit_shared_dram_buffer *cmd, uint8_t interface)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_DEINIT_SHARED_DRAM_BUFFER; cmd->header.opcode = PVA_CMD_OPCODE_DEINIT_SHARED_DRAM_BUFFER;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->interface = interface; cmd->interface = interface;
} }
@@ -302,22 +649,31 @@ static inline void
pva_kmd_set_cmd_set_profiling_level(struct pva_cmd_set_profiling_level *cmd, pva_kmd_set_cmd_set_profiling_level(struct pva_cmd_set_profiling_level *cmd,
uint32_t level) uint32_t level)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_SET_PROFILING_LEVEL; cmd->header.opcode = PVA_CMD_OPCODE_SET_PROFILING_LEVEL;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->level = level; cmd->level = level;
} }
static inline void pva_kmd_set_cmd_get_version(struct pva_cmd_get_version *cmd, static inline void pva_kmd_set_cmd_get_version(struct pva_cmd_get_version *cmd,
uint64_t buffer_iova) uint64_t buffer_iova)
{ {
memset(cmd, 0, sizeof(*cmd)); (void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_GET_VERSION; cmd->header.opcode = PVA_CMD_OPCODE_GET_VERSION;
cmd->header.len = sizeof(*cmd) / sizeof(uint32_t); cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->buffer_iova_hi = iova_hi(buffer_iova); cmd->buffer_iova_hi = iova_hi(buffer_iova);
cmd->buffer_iova_lo = iova_lo(buffer_iova); cmd->buffer_iova_lo = iova_lo(buffer_iova);
} }
static inline void pva_kmd_set_cmd_set_pfsd_cmd_buffer_size(
struct pva_cmd_set_pfsd_cmd_buffer_size *cmd, uint32_t cmd_buffer_size)
{
(void)memset(cmd, 0, sizeof(*cmd));
cmd->header.opcode = PVA_CMD_OPCODE_SET_PFSD_CMD_BUFFER_SIZE;
cmd->header.len = (uint8_t)(sizeof(*cmd) / sizeof(uint32_t));
cmd->cmd_buffer_size = cmd_buffer_size;
}
#define CMD_LEN(cmd_type) (sizeof(cmd_type) / sizeof(uint32_t)) #define CMD_LEN(cmd_type) (sizeof(cmd_type) / sizeof(uint32_t))
#endif // PVA_KMD_CMDBUF_H #endif // PVA_KMD_CMDBUF_H

View File

@@ -4,9 +4,32 @@
#ifndef PVA_KMD_CO_H #ifndef PVA_KMD_CO_H
#define PVA_KMD_CO_H #define PVA_KMD_CO_H
/**
* @brief Compute Object information structure
*
* @details This structure contains memory mapping information for a compute object,
* including both virtual and physical address mappings along with size information.
* Compute objects represent memory regions or buffers that are used for computation
* tasks on the PVA hardware, providing the necessary address translation information
* for both software and hardware access.
*/
struct pva_co_info { struct pva_co_info {
/**
* @brief Virtual address base of the compute object
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t base_va; uint64_t base_va;
/**
* @brief Physical address base of the compute object
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t base_pa; uint64_t base_pa;
/**
* @brief Size of the compute object in bytes
* Valid range: [1 .. UINT64_MAX]
*/
uint64_t size; uint64_t size;
}; };

View File

@@ -3,56 +3,253 @@
#ifndef PVA_KMD_CONSTANTS_H #ifndef PVA_KMD_CONSTANTS_H
#define PVA_KMD_CONSTANTS_H #define PVA_KMD_CONSTANTS_H
#include "pva_kmd_limits.h"
#include "pva_constants.h" #include "pva_constants.h"
/* Limits related to KMD's own submission*/
/**
* @brief Maximum number of resources that can be managed by KMD internally
*
* @details This constant defines the upper limit for the number of resources
* that the KMD can manage for its own internal operations. These resources
* include memory buffers, DMA configurations, and other hardware resources
* needed for KMD's privileged operations and communication with firmware.
*/
#define PVA_KMD_MAX_NUM_KMD_RESOURCES 32 #define PVA_KMD_MAX_NUM_KMD_RESOURCES 32
/**
* @brief Maximum number of DMA configurations for KMD internal use
*
* @details This constant defines the maximum number of DMA configuration
* objects that the KMD can allocate and manage for its own internal DMA
* operations. These configurations are used for transferring data between
* system memory and PVA internal memory during KMD operations.
*/
#define PVA_KMD_MAX_NUM_KMD_DMA_CONFIGS 1 #define PVA_KMD_MAX_NUM_KMD_DMA_CONFIGS 1
/**
* @brief Maximum number of command buffer chunks for KMD internal submissions
*
* @details This constant defines the upper limit for the number of command
* buffer chunks that the KMD can use for its own internal command submissions.
* These chunks are used to build command buffers for privileged operations
* such as resource management and device configuration.
*/
#define PVA_KMD_MAX_NUM_KMD_CHUNKS 32 #define PVA_KMD_MAX_NUM_KMD_CHUNKS 32
/**
* @brief Maximum number of submissions that KMD can queue internally
*
* @details This constant defines the maximum number of command buffer
* submissions that the KMD can have queued for its own internal operations.
* This limits the depth of the internal submission queue to prevent
* unbounded resource usage during high-throughput scenarios.
*/
#define PVA_KMD_MAX_NUM_KMD_SUBMITS 32 #define PVA_KMD_MAX_NUM_KMD_SUBMITS 32
/* Limits related to User's privileged submission */ /**
* @brief Maximum number of command buffer chunks for user privileged submissions
*
* @details This constant defines the upper limit for the number of command
* buffer chunks that can be used for user-initiated privileged submissions.
* Privileged submissions are those that require elevated permissions and
* are processed through the KMD's privileged command path.
*/
#define PVA_KMD_MAX_NUM_PRIV_CHUNKS 256 #define PVA_KMD_MAX_NUM_PRIV_CHUNKS 256
/**
* @brief Maximum number of privileged submissions that can be queued
*
* @details This constant defines the maximum number of privileged command
* buffer submissions that can be queued at any given time. This limit
* helps manage memory usage and ensures system stability under heavy
* privileged operation loads.
*/
#define PVA_KMD_MAX_NUM_PRIV_SUBMITS 256 #define PVA_KMD_MAX_NUM_PRIV_SUBMITS 256
/**
* @brief Base context ID for user contexts
*
* @details This constant defines the starting context ID value for user
* contexts. Context ID 0 is typically reserved for privileged/system
* operations, so user contexts start from this base value. This ensures
* proper separation between system and user context namespaces.
*/
#define PVA_KMD_USER_CONTEXT_ID_BASE 1u #define PVA_KMD_USER_CONTEXT_ID_BASE 1u
/**
* @brief Physical register base address for PVA0 on T23x silicon
*
* @details This constant defines the physical memory address where the
* PVA0 device registers are mapped on T23x (Tegra23x) silicon platforms.
* This address is used for register access and memory mapping operations
* specific to the first PVA instance on T23x hardware.
*/
#define PVA_KMD_PVA0_T23x_REG_BASE 0x16000000 #define PVA_KMD_PVA0_T23x_REG_BASE 0x16000000
/**
* @brief Size of PVA0 register space on T23x silicon
*
* @details This constant defines the total size in bytes of the PVA0
* register address space on T23x (Tegra23x) silicon platforms. This
* size covers all register apertures and memory-mapped regions needed
* for complete PVA0 device control and operation.
*/
#define PVA_KMD_PVA0_T23x_REG_SIZE 0x800000 #define PVA_KMD_PVA0_T23x_REG_SIZE 0x800000
#define PVA_KMD_TIMEOUT_INF UINT64_MAX /**
* @brief Infinite timeout value for operations that should never timeout
*
* @details This constant represents an infinite timeout value, typically
* used for operations that must complete regardless of how long they take.
* Set to the maximum value of a 64-bit unsigned integer to effectively
* disable timeout checking for critical operations.
*/
#define PVA_KMD_TIMEOUT_INF U64_MAX
// clang-format off // clang-format off
#if PVA_BUILD_MODE == PVA_BUILD_MODE_SIM #if PVA_BUILD_MODE == PVA_BUILD_MODE_SIM
/**
* @brief Timeout scaling factor for simulation builds
*
* @details This constant provides a scaling factor applied to timeout
* values when running in simulation mode. Simulation environments
* typically run slower than real hardware, so timeouts are scaled up
* by this factor to prevent spurious timeout failures during testing.
*/
#define PVA_KMD_TIMEOUT_FACTOR 100 #define PVA_KMD_TIMEOUT_FACTOR 100
#elif (PVA_BUILD_MODE == PVA_BUILD_MODE_NATIVE) #elif (PVA_BUILD_MODE == PVA_BUILD_MODE_NATIVE)
// On native builds, the FW calls the KMD's shared buffer handler in its /**
// own thread. In debug builds, if there are a large number of messages * @brief Timeout scaling factor for native builds
// (prints, unregister, etc.), this handler might take a while to execute, *
// making the FW and delay the processing of command buffers. This could * @details This constant provides a scaling factor applied to timeout
// lead to submission timeouts in KMD. * values when running in native build mode. On native builds, the FW calls
* the KMD's shared buffer handler in its own thread. In debug builds, if
* there are a large number of messages (prints, unregister, etc.), this
* handler might take a while to execute, making the FW delay the processing
* of command buffers. This could lead to submission timeouts in KMD.
*/
#define PVA_KMD_TIMEOUT_FACTOR 10 #define PVA_KMD_TIMEOUT_FACTOR 10
#else #else
/**
* @brief Default timeout scaling factor for silicon builds
*
* @details This constant provides the default scaling factor applied to
* timeout values when running on actual silicon hardware. No scaling
* is applied (factor of 1) as silicon hardware runs at expected speeds
* and timeout values are calibrated for real hardware performance.
*/
#define PVA_KMD_TIMEOUT_FACTOR 1 #define PVA_KMD_TIMEOUT_FACTOR 1
#endif #endif
// clang-format on // clang-format on
#define PVA_KMD_TIMEOUT(val) (val * PVA_KMD_TIMEOUT_FACTOR) /**
* @brief Macro to apply platform-specific timeout scaling
*
* @details This macro applies the appropriate timeout scaling factor based
* on the build mode. It multiplies the provided timeout value by the
* platform-specific timeout factor to account for different execution
* speeds in simulation, native, and silicon environments.
*
* @param val Base timeout value before scaling
*/
#define PVA_KMD_TIMEOUT(val) ((val)*PVA_KMD_TIMEOUT_FACTOR)
#define PVA_KMD_TIMEOUT_RESOURCE_SEMA_MS PVA_KMD_TIMEOUT(400) /*< 100 ms */ /**
#define PVA_KMD_WAIT_FW_TIMEOUT_US PVA_KMD_TIMEOUT(100000) /*< 100 ms */ * @brief Timeout for resource semaphore operations in milliseconds
*
* @details This constant defines the timeout value for acquiring resource
* semaphores in the KMD. Resource semaphores are used to coordinate access
* to shared resources between different contexts and operations. The timeout
* is scaled based on the build mode to account for platform differences.
*/
#define PVA_KMD_TIMEOUT_RESOURCE_SEMA_MS PVA_KMD_TIMEOUT(400)
/**
* @brief Timeout for waiting on firmware responses in microseconds
*
* @details This constant defines the timeout value for operations that
* wait for firmware responses or completion signals. This timeout ensures
* that the KMD doesn't wait indefinitely for firmware operations that
* may have failed or stalled. The timeout is scaled for platform differences.
*/
#define PVA_KMD_WAIT_FW_TIMEOUT_US PVA_KMD_TIMEOUT(100000)
/**
* @brief Additional scaling factor for firmware timeouts in simulation
*
* @details This constant provides an additional scaling factor specifically
* for firmware timeout operations when running in simulation mode. This
* extra scaling accounts for the significantly slower execution speed
* of firmware operations in simulation environments.
*/
#define PVA_KMD_WAIT_FW_TIMEOUT_SCALER_SIM 100 #define PVA_KMD_WAIT_FW_TIMEOUT_SCALER_SIM 100
#define PVA_KMD_WAIT_FW_POLL_INTERVAL_US PVA_KMD_TIMEOUT(100) /*< 100 us*/
#define PVA_KMD_FW_BOOT_TIMEOUT_MS PVA_KMD_TIMEOUT(1000) /*< 1 seconds */
/**
* @brief Polling interval for firmware status checks in microseconds
*
* @details This constant defines the interval between polling operations
* when waiting for firmware status changes or responses. The polling
* interval balances responsiveness with CPU usage - too frequent polling
* wastes CPU cycles, while too infrequent polling increases response latency.
*/
#define PVA_KMD_WAIT_FW_POLL_INTERVAL_US PVA_KMD_TIMEOUT(100)
/**
* @brief Timeout for firmware boot completion in milliseconds
*
* @details This constant defines the maximum time to wait for firmware
* boot completion during device initialization. If the firmware doesn't
* complete its boot sequence within this timeout, the initialization
* is considered failed. The timeout is scaled for platform differences.
*/
#define PVA_KMD_FW_BOOT_TIMEOUT_MS PVA_KMD_TIMEOUT(1000)
/**
* @brief Total number of read-write syncpoints available across all contexts
*
* @details This constant calculates the total number of read-write syncpoints
* available in the system by multiplying the maximum number of CCQs by the
* number of read-write syncpoints per context. This provides the total pool
* of syncpoints that can be allocated for user operations requiring both
* read and write access to syncpoint values.
*/
#define PVA_NUM_RW_SYNCPTS (PVA_MAX_NUM_CCQ * PVA_NUM_RW_SYNCPTS_PER_CONTEXT) #define PVA_NUM_RW_SYNCPTS (PVA_MAX_NUM_CCQ * PVA_NUM_RW_SYNCPTS_PER_CONTEXT)
// clang-format off // clang-format off
#if PVA_DEV_MAIN_COMPATIBLE == 1 #if PVA_DEV_MAIN_COMPATIBLE == 1
/**
* @brief Default setting for loading firmware from GSC in main-compatible builds
*
* @details This constant defines the default behavior for firmware loading
* from GSC (Generic Security Controller) in builds that are compatible with
* the main development branch. When true, firmware will be loaded through
* the GSC secure path by default, providing enhanced security for production
* environments.
*/
#define PVA_KMD_LOAD_FROM_GSC_DEFAULT true #define PVA_KMD_LOAD_FROM_GSC_DEFAULT true
#else #else
/**
* @brief Default setting for loading firmware from GSC in non-main-compatible builds
*
* @details This constant defines the default behavior for firmware loading
* from GSC (Generic Security Controller) in development or testing builds
* that are not main-compatible. When false, firmware will be loaded through
* conventional paths, which may be more suitable for development and debugging.
*/
#define PVA_KMD_LOAD_FROM_GSC_DEFAULT false #define PVA_KMD_LOAD_FROM_GSC_DEFAULT false
#endif #endif
// clang-format on // clang-format on
/**
* @brief Increment size for DMA configuration pool expansion
*
* @details This constant defines the number of DMA configuration entries
* to allocate when expanding the DMA configuration pool. When the pool
* becomes full and needs to grow, it will be expanded by this many entries
* to provide room for additional DMA configurations while minimizing
* the frequency of pool expansion operations.
*/
#define PVA_KMD_DMA_CONFIG_POOL_INCR 256 #define PVA_KMD_DMA_CONFIG_POOL_INCR 256
#endif // PVA_KMD_CONSTANTS_H #endif // PVA_KMD_CONSTANTS_H

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_device_memory.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_constants.h" #include "pva_constants.h"
#include "pva_api_cmdbuf.h" #include "pva_api_cmdbuf.h"
@@ -10,6 +11,7 @@
#include "pva_kmd_context.h" #include "pva_kmd_context.h"
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_kmd_msg.h" #include "pva_kmd_msg.h"
#include "pva_kmd_limits.h"
struct pva_kmd_context *pva_kmd_context_create(struct pva_kmd_device *pva) struct pva_kmd_context *pva_kmd_context_create(struct pva_kmd_device *pva)
{ {
@@ -21,28 +23,33 @@ struct pva_kmd_context *pva_kmd_context_create(struct pva_kmd_device *pva)
if (ctx == NULL) { if (ctx == NULL) {
pva_kmd_log_err( pva_kmd_log_err(
"pva_kmd_context_create pva_kmd_context block alloc failed"); "pva_kmd_context_create pva_kmd_context block alloc failed");
err = PVA_NOMEM;
goto err_out; goto err_out;
} }
ctx->ccq_id = alloc_id; /* alloc_id bounded by PVA_MAX_NUM_USER_CONTEXTS (7) from allocator */
/* MISRA 10.4: alloc_id is unsigned, only check upper bound */
ASSERT(alloc_id <= (uint32_t)U8_MAX);
ctx->ccq_id = (uint8_t)alloc_id;
ctx->resource_table_id = ctx->ccq_id; ctx->resource_table_id = ctx->ccq_id;
ctx->smmu_ctx_id = ctx->ccq_id; ctx->smmu_ctx_id = ctx->ccq_id;
ctx->pva = pva; ctx->pva = pva;
ctx->max_n_queues = PVA_MAX_NUM_QUEUES_PER_CONTEXT; ctx->max_n_queues = PVA_MAX_NUM_QUEUES_PER_CONTEXT;
pva_kmd_mutex_init(&ctx->ocb_lock); err = pva_kmd_mutex_init(&ctx->ocb_lock);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("pva_kmd_context_create mutex_init failed");
goto free_ctx;
}
ctx->queue_allocator_mem = pva_kmd_zalloc(sizeof(struct pva_kmd_queue) * ctx->queue_allocator_mem = pva_kmd_zalloc(sizeof(struct pva_kmd_queue) *
ctx->max_n_queues); ctx->max_n_queues);
if (ctx->queue_allocator_mem == NULL) { if (ctx->queue_allocator_mem == NULL) {
err = PVA_NOMEM;
pva_kmd_log_err( pva_kmd_log_err(
"pva_kmd_context_create queue_allocator_mem NULL"); "pva_kmd_context_create queue_allocator_mem NULL");
goto free_ctx; goto free_ctx;
} }
err = pva_kmd_block_allocator_init(&ctx->queue_allocator, /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
ctx->queue_allocator_mem, 0, err = pva_kmd_block_allocator_init(
sizeof(struct pva_kmd_queue), &ctx->queue_allocator, ctx->queue_allocator_mem, 0,
ctx->max_n_queues); (uint32_t)sizeof(struct pva_kmd_queue), ctx->max_n_queues);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err( pva_kmd_log_err(
"pva_kmd_context_create block allocator init failed"); "pva_kmd_context_create block allocator init failed");
@@ -63,12 +70,93 @@ free_queue_mem:
pva_kmd_free(ctx->queue_allocator_mem); pva_kmd_free(ctx->queue_allocator_mem);
free_ctx: free_ctx:
pva_kmd_mutex_deinit(&ctx->ocb_lock); pva_kmd_mutex_deinit(&ctx->ocb_lock);
pva_kmd_free_block(&pva->context_allocator, alloc_id); err = pva_kmd_free_block(&pva->context_allocator, alloc_id);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to free context block");
}
err_out: err_out:
pva_kmd_log_err("Failed to create PVA context"); pva_kmd_log_err("Failed to create PVA context");
return NULL; return NULL;
} }
static enum pva_error setup_status_memory(struct pva_kmd_context *ctx,
uint64_t status_shm_hdl)
{
enum pva_error err = PVA_SUCCESS;
ctx->status_mem = pva_kmd_device_memory_acquire(
status_shm_hdl, 0, sizeof(struct pva_fw_async_error), ctx);
if (ctx->status_mem == NULL) {
pva_kmd_log_err("Failed to acquire context status memory");
err = PVA_INTERNAL;
goto out;
}
err = pva_kmd_device_memory_iova_map(ctx->status_mem, ctx->pva,
PVA_ACCESS_RW,
PVA_R5_SMMU_CONTEXT_ID);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to map context status memory");
pva_kmd_device_memory_free(ctx->status_mem);
ctx->status_mem = NULL;
}
out:
return err;
}
static enum pva_error
setup_submit_memory_and_chunk_pool(struct pva_kmd_context *ctx)
{
enum pva_error err = PVA_SUCCESS;
uint64_t chunk_mem_size;
uint64_t size;
/* Allocate memory for submission */
chunk_mem_size = pva_kmd_cmdbuf_pool_get_required_mem_size(
pva_kmd_get_max_cmdbuf_chunk_size(ctx->pva),
PVA_KMD_MAX_NUM_PRIV_CHUNKS);
/* Allocate one post fence at the end. This memory will be added to
* KMD's own resource table. We don't need to explicitly free it. It
* will be freed after we drop the resource. */
size = safe_addu64(chunk_mem_size, (uint64_t)sizeof(uint32_t));
ctx->submit_memory = pva_kmd_device_memory_alloc_map(
size, ctx->pva, PVA_ACCESS_RW, PVA_R5_SMMU_CONTEXT_ID);
if (ctx->submit_memory == NULL) {
err = PVA_NOMEM;
goto out;
}
/* Add submit memory to resource table */
err = pva_kmd_add_dram_buffer_resource(&ctx->pva->dev_resource_table,
ctx->submit_memory,
&ctx->submit_memory_resource_id,
false);
if (err != PVA_SUCCESS) {
// Ownership of submit memory is transferred to KMD's resource table so
// if adding to resource table fails, we need to free it here.
pva_kmd_device_memory_free(ctx->submit_memory);
goto out;
}
/* Init chunk pool */
err = pva_kmd_cmdbuf_chunk_pool_init(
&ctx->chunk_pool, ctx->submit_memory_resource_id,
0 /* offset */, (uint32_t)chunk_mem_size,
pva_kmd_get_max_cmdbuf_chunk_size(ctx->pva),
PVA_KMD_MAX_NUM_PRIV_CHUNKS, ctx->submit_memory->va);
if (err != PVA_SUCCESS) {
pva_kmd_drop_resource(&ctx->pva->dev_resource_table,
ctx->submit_memory_resource_id);
goto out;
}
/* Init fence */
ctx->fence_offset = chunk_mem_size;
out:
return err;
}
static enum pva_error notify_fw_context_init(struct pva_kmd_context *ctx) static enum pva_error notify_fw_context_init(struct pva_kmd_context *ctx)
{ {
struct pva_kmd_submitter *dev_submitter = &ctx->pva->submitter; struct pva_kmd_submitter *dev_submitter = &ctx->pva->submitter;
@@ -81,24 +169,26 @@ static enum pva_error notify_fw_context_init(struct pva_kmd_context *ctx)
uint32_t current_offset = 0; uint32_t current_offset = 0;
uint32_t cmd_scratch[CMD_LEN(struct pva_cmd_init_resource_table) + uint32_t cmd_scratch[CMD_LEN(struct pva_cmd_init_resource_table) +
CMD_LEN(struct pva_cmd_init_queue) + CMD_LEN(struct pva_cmd_init_queue) +
CMD_LEN(struct pva_cmd_update_resource_table)]; CMD_LEN(struct pva_cmd_update_resource_table)] = {
0
};
res_cmd = (struct pva_cmd_init_resource_table *)pva_offset_pointer( res_cmd = (struct pva_cmd_init_resource_table *)pva_offset_pointer(
&cmd_scratch[0], current_offset); &cmd_scratch[0], current_offset);
current_offset += sizeof(*res_cmd); current_offset += (uint32_t)sizeof(*res_cmd);
queue_cmd = (struct pva_cmd_init_queue *)pva_offset_pointer( queue_cmd = (struct pva_cmd_init_queue *)pva_offset_pointer(
&cmd_scratch[0], current_offset); &cmd_scratch[0], current_offset);
current_offset += sizeof(*queue_cmd); current_offset += (uint32_t)sizeof(*queue_cmd);
update_cmd = (struct pva_cmd_update_resource_table *)pva_offset_pointer( update_cmd = (struct pva_cmd_update_resource_table *)pva_offset_pointer(
&cmd_scratch[0], current_offset); &cmd_scratch[0], current_offset);
current_offset += sizeof(*update_cmd); current_offset += (uint32_t)sizeof(*update_cmd);
pva_kmd_set_cmd_init_resource_table( pva_kmd_set_cmd_init_resource_table(
res_cmd, ctx->resource_table_id, res_cmd, ctx->resource_table_id,
ctx->ctx_resource_table.table_mem->iova, ctx->ctx_resource_table.table_mem->iova,
ctx->ctx_resource_table.n_entries); ctx->ctx_resource_table.n_entries, ctx->status_mem->iova);
syncpt_info = pva_kmd_queue_get_rw_syncpt_info( syncpt_info = pva_kmd_queue_get_rw_syncpt_info(
ctx->pva, PVA_PRIV_CCQ_ID, ctx->ccq_id); ctx->pva, PVA_PRIV_CCQ_ID, ctx->ccq_id);
@@ -119,9 +209,13 @@ static enum pva_error notify_fw_context_init(struct pva_kmd_context *ctx)
&entry, NULL); &entry, NULL);
err = pva_kmd_submit_cmd_sync(dev_submitter, cmd_scratch, err = pva_kmd_submit_cmd_sync(dev_submitter, cmd_scratch,
sizeof(cmd_scratch), (uint32_t)sizeof(cmd_scratch),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Failed to submit command for context init notify");
}
return err; return err;
} }
@@ -131,7 +225,9 @@ static enum pva_error notify_fw_context_deinit(struct pva_kmd_context *ctx)
struct pva_cmd_deinit_resource_table *deinit_table_cmd; struct pva_cmd_deinit_resource_table *deinit_table_cmd;
struct pva_cmd_deinit_queue *deinit_queue_cmd; struct pva_cmd_deinit_queue *deinit_queue_cmd;
uint32_t cmd_scratch[CMD_LEN(struct pva_cmd_deinit_queue) + uint32_t cmd_scratch[CMD_LEN(struct pva_cmd_deinit_queue) +
CMD_LEN(struct pva_cmd_deinit_resource_table)]; CMD_LEN(struct pva_cmd_deinit_resource_table)] = {
0
};
enum pva_error err; enum pva_error err;
deinit_queue_cmd = (struct pva_cmd_deinit_queue *)pva_offset_pointer( deinit_queue_cmd = (struct pva_cmd_deinit_queue *)pva_offset_pointer(
@@ -149,20 +245,23 @@ static enum pva_error notify_fw_context_deinit(struct pva_kmd_context *ctx)
ctx->resource_table_id); ctx->resource_table_id);
err = pva_kmd_submit_cmd_sync(dev_submitter, cmd_scratch, err = pva_kmd_submit_cmd_sync(dev_submitter, cmd_scratch,
sizeof(cmd_scratch), (uint32_t)sizeof(cmd_scratch),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Failed to submit command for context deinit notify");
}
return err; return err;
} }
enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx, enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
uint32_t res_table_capacity) uint32_t res_table_capacity,
uint64_t status_shm_hdl)
{ {
enum pva_error err; enum pva_error err;
uint32_t queue_mem_size; uint32_t queue_mem_size;
uint64_t chunk_mem_size;
struct pva_fw_postfence post_fence = { 0 }; struct pva_fw_postfence post_fence = { 0 };
uint64_t size;
if (ctx->inited) { if (ctx->inited) {
err = PVA_INVAL; err = PVA_INVAL;
@@ -175,11 +274,16 @@ enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
goto err_out; goto err_out;
} }
err = setup_status_memory(ctx, status_shm_hdl);
if (err != PVA_SUCCESS) {
goto err_out;
}
/* Init resource table for this context */ /* Init resource table for this context */
err = pva_kmd_resource_table_init(&ctx->ctx_resource_table, ctx->pva, err = pva_kmd_resource_table_init(&ctx->ctx_resource_table, ctx->pva,
ctx->smmu_ctx_id, res_table_capacity); ctx->smmu_ctx_id, res_table_capacity);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto err_out; goto unmap_status_mem;
} }
/* Init privileged queue for this context */ /* Init privileged queue for this context */
@@ -199,48 +303,23 @@ enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
ctx->ccq_id, /* Context's PRIV queue ID is identical to CCQ ID */ ctx->ccq_id, /* Context's PRIV queue ID is identical to CCQ ID */
ctx->ctx_queue_mem, PVA_KMD_MAX_NUM_PRIV_SUBMITS); ctx->ctx_queue_mem, PVA_KMD_MAX_NUM_PRIV_SUBMITS);
/* Allocate memory for submission */ err = setup_submit_memory_and_chunk_pool(ctx);
chunk_mem_size = pva_kmd_cmdbuf_pool_get_required_mem_size( if (err != PVA_SUCCESS) {
pva_kmd_get_max_cmdbuf_chunk_size(ctx->pva),
PVA_KMD_MAX_NUM_PRIV_CHUNKS);
/* Allocate one post fence at the end. This memory will be added to
* KMD's own resource table. We don't need to explicitly free it. It
* will be freed after we drop the resource. */
size = safe_addu64(chunk_mem_size, (uint64_t)sizeof(uint32_t));
ctx->submit_memory = pva_kmd_device_memory_alloc_map(
size, ctx->pva, PVA_ACCESS_RW, PVA_R5_SMMU_CONTEXT_ID);
if (ctx->submit_memory == NULL) {
err = PVA_NOMEM;
goto queue_deinit; goto queue_deinit;
} }
/* Add submit memory to resource table */
err = pva_kmd_add_dram_buffer_resource(&ctx->pva->dev_resource_table,
ctx->submit_memory,
&ctx->submit_memory_resource_id);
if (err != PVA_SUCCESS) {
// Ownership of submit memory is transferred to KMD's resource table so
// if adding to resource table fails, we need to free it here.
pva_kmd_device_memory_free(ctx->submit_memory);
goto queue_deinit;
}
/* Init chunk pool */
err = pva_kmd_cmdbuf_chunk_pool_init(
&ctx->chunk_pool, ctx->submit_memory_resource_id,
0 /* offset */, chunk_mem_size,
pva_kmd_get_max_cmdbuf_chunk_size(ctx->pva),
PVA_KMD_MAX_NUM_PRIV_CHUNKS, ctx->submit_memory->va);
if (err != PVA_SUCCESS) {
goto free_dram_buffer_resource;
}
/* Init fence */
ctx->fence_offset = chunk_mem_size;
/* Init submitter */ /* Init submitter */
pva_kmd_mutex_init(&ctx->submit_lock); err = pva_kmd_mutex_init(&ctx->submit_lock);
pva_kmd_mutex_init(&ctx->chunk_pool_lock); if (err != PVA_SUCCESS) {
pva_kmd_log_err("pva_kmd_context_init submit_lock init failed");
goto deinit_chunk_pool;
}
err = pva_kmd_mutex_init(&ctx->chunk_pool_lock);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"pva_kmd_context_init chunk_pool_lock init failed");
goto deinit_submit_lock;
}
post_fence.resource_id = ctx->submit_memory_resource_id; post_fence.resource_id = ctx->submit_memory_resource_id;
post_fence.offset_lo = iova_lo(ctx->fence_offset); post_fence.offset_lo = iova_lo(ctx->fence_offset);
post_fence.offset_hi = iova_hi(ctx->fence_offset); post_fence.offset_hi = iova_hi(ctx->fence_offset);
@@ -248,7 +327,8 @@ enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
pva_kmd_submitter_init( pva_kmd_submitter_init(
&ctx->submitter, &ctx->ctx_queue, &ctx->submit_lock, &ctx->submitter, &ctx->ctx_queue, &ctx->submit_lock,
&ctx->chunk_pool, &ctx->chunk_pool_lock, &ctx->chunk_pool, &ctx->chunk_pool_lock,
pva_offset_pointer(ctx->submit_memory->va, ctx->fence_offset), (uint32_t *)pva_offset_pointer(ctx->submit_memory->va,
ctx->fence_offset),
&post_fence); &post_fence);
/* Use KMD's queue to inform FW */ /* Use KMD's queue to inform FW */
@@ -258,7 +338,7 @@ enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
} }
err = pva_kmd_shared_buffer_init(ctx->pva, ctx->ccq_id, err = pva_kmd_shared_buffer_init(ctx->pva, ctx->ccq_id,
PVA_KMD_FW_BUF_ELEMENT_SIZE, (uint32_t)PVA_KMD_FW_BUF_ELEMENT_SIZE,
res_table_capacity, res_table_capacity,
pva_kmd_resource_table_lock, pva_kmd_resource_table_lock,
pva_kmd_resource_table_unlock); pva_kmd_resource_table_unlock);
@@ -271,18 +351,25 @@ enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
return PVA_SUCCESS; return PVA_SUCCESS;
deinit_fw_context: deinit_fw_context:
notify_fw_context_deinit(ctx); if (PVA_SUCCESS != notify_fw_context_deinit(ctx)) {
pva_kmd_log_err(
"Failed to deinitialize FW context during cleanup");
}
deinit_submitter: deinit_submitter:
pva_kmd_mutex_deinit(&ctx->chunk_pool_lock); pva_kmd_mutex_deinit(&ctx->chunk_pool_lock);
deinit_submit_lock:
pva_kmd_mutex_deinit(&ctx->submit_lock); pva_kmd_mutex_deinit(&ctx->submit_lock);
deinit_chunk_pool:
pva_kmd_cmdbuf_chunk_pool_deinit(&ctx->chunk_pool); pva_kmd_cmdbuf_chunk_pool_deinit(&ctx->chunk_pool);
free_dram_buffer_resource:
pva_kmd_drop_resource(&ctx->pva->dev_resource_table, pva_kmd_drop_resource(&ctx->pva->dev_resource_table,
ctx->submit_memory_resource_id); ctx->submit_memory_resource_id);
queue_deinit: queue_deinit:
pva_kmd_device_memory_free(ctx->ctx_queue_mem); pva_kmd_device_memory_free(ctx->ctx_queue_mem);
deinit_table: deinit_table:
pva_kmd_resource_table_deinit(&ctx->ctx_resource_table); pva_kmd_resource_table_deinit(&ctx->ctx_resource_table);
unmap_status_mem:
pva_kmd_device_memory_iova_unmap(ctx->status_mem);
pva_kmd_device_memory_free(ctx->status_mem);
err_out: err_out:
return err; return err;
} }
@@ -300,6 +387,8 @@ void pva_kmd_free_context(struct pva_kmd_context *ctx)
ctx->submit_memory_resource_id); ctx->submit_memory_resource_id);
pva_kmd_device_memory_free(ctx->ctx_queue_mem); pva_kmd_device_memory_free(ctx->ctx_queue_mem);
pva_kmd_resource_table_deinit(&ctx->ctx_resource_table); pva_kmd_resource_table_deinit(&ctx->ctx_resource_table);
pva_kmd_device_memory_iova_unmap(ctx->status_mem);
pva_kmd_device_memory_free(ctx->status_mem);
ctx->inited = false; ctx->inited = false;
} }
@@ -348,24 +437,24 @@ static enum pva_error notify_fw_context_destroy(struct pva_kmd_context *ctx)
return ret; return ret;
} }
void pva_kmd_context_destroy(struct pva_kmd_context *ctx) void pva_kmd_context_destroy(struct pva_kmd_context *client)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
struct pva_kmd_device *pva = ctx->pva; struct pva_kmd_device *pva = client->pva;
bool deferred_free = false; bool deferred_free = false;
if (ctx->inited) { if (client->inited) {
err = notify_fw_context_destroy(ctx); err = notify_fw_context_destroy(client);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
deferred_free = true; deferred_free = true;
pva_kmd_add_deferred_context_free(pva, ctx->ccq_id); pva_kmd_add_deferred_context_free(pva, client->ccq_id);
pva_kmd_log_err( pva_kmd_log_err(
"Failed to notify FW of context destroy; Deferring resource free until PVA is powered off."); "Failed to notify FW of context destroy; Deferring resource free until PVA is powered off.");
} }
} }
if (!deferred_free) { if (!deferred_free) {
pva_kmd_free_context(ctx); pva_kmd_free_context(client);
} }
pva_kmd_device_idle(pva); pva_kmd_device_idle(pva);
} }

View File

@@ -10,87 +10,287 @@
#include "pva_kmd_queue.h" #include "pva_kmd_queue.h"
#include "pva_kmd_mutex.h" #include "pva_kmd_mutex.h"
#include "pva_kmd_submitter.h" #include "pva_kmd_submitter.h"
#include "pva_kmd_pfsd.h"
struct pva_kmd_device; struct pva_kmd_device;
/** /**
* @brief This struct manages a user context in KMD. * @brief This struct manages a user context in KMD.
* *
* One KMD user context is uniquely mapped to a UMD user context. Each context * @details One KMD user context is uniquely mapped to a UMD user context. Each context
* is assigned a unique CCQ block and, on QNX and Linux, a unique file * is assigned a unique CCQ block and, on QNX and Linux, a unique file
* descriptor. * descriptor. This structure contains all the resources and state information
* needed to manage operations for a specific user context, including resource
* tables, command queues, memory allocations, and synchronization primitives.
*/ */
struct pva_kmd_context { struct pva_kmd_context {
/**
* @brief Pointer to the parent PVA device
* Valid value: non-null
*/
struct pva_kmd_device *pva; struct pva_kmd_device *pva;
/**
* @brief Resource table ID assigned to this context
* Valid range: [0 .. PVA_KMD_MAX_NUM_KMD_RESOURCES-1]
*/
uint8_t resource_table_id; uint8_t resource_table_id;
/**
* @brief CCQ (Command and Control Queue) ID assigned to this context
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
*/
uint8_t ccq_id; uint8_t ccq_id;
/**
* @brief SMMU context ID for memory protection
* Valid range: [0 .. PVA_MAX_NUM_SMMU_CONTEXTS-1]
*/
uint8_t smmu_ctx_id; uint8_t smmu_ctx_id;
/**
* @brief Flag indicating if context has been initialized
* Valid values: true, false
*/
bool inited; bool inited;
/**
* @brief Context-specific resource table for managing user resources
*/
struct pva_kmd_resource_table ctx_resource_table; struct pva_kmd_resource_table ctx_resource_table;
/**
* @brief Command submission handler for context operations
*/
struct pva_kmd_submitter submitter; struct pva_kmd_submitter submitter;
/** The lock protects the submission to the queue, including
* incrementing the post fence */ /**
* @brief Lock protecting submission operations and post fence increment
*
* @details The lock protects the submission to the queue, including
* incrementing the post fence
*/
pva_kmd_mutex_t submit_lock; pva_kmd_mutex_t submit_lock;
/** Privileged queue owned by this context. It uses the privileged
* resource table (ID 0). */ /**
* @brief Device memory allocation for context queue operations
*
* @details Privileged queue owned by this context. It uses the privileged
* resource table (ID 0).
*/
struct pva_kmd_device_memory *ctx_queue_mem; struct pva_kmd_device_memory *ctx_queue_mem;
/** Privileged queue owned by the context */ /**
* @brief Context-owned privileged command queue
*
* @details Privileged queue owned by the context
*/
struct pva_kmd_queue ctx_queue; struct pva_kmd_queue ctx_queue;
/** memory needed for submission: including command buffer chunks and fences */ /**
* @brief Memory allocation for context submission operations
*
* @details Memory needed for submission: including command buffer chunks and fences
*/
struct pva_kmd_device_memory *submit_memory; struct pva_kmd_device_memory *submit_memory;
/** Resource ID of the submission memory, registered with the privileged resource table (ID 0) */
uint32_t submit_memory_resource_id;
uint64_t fence_offset; /**< fence offset within submit_memory*/
/**
* @brief Resource ID of submission memory in privileged resource table
*
* @details Resource ID of the submission memory, registered with the
* privileged resource table (ID 0)
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t submit_memory_resource_id;
/**
* @brief Offset of fence within submission memory
* Valid range: [0 .. submit_memory_size-1]
*/
uint64_t fence_offset;
/**
* @brief Lock protecting command buffer chunk pool operations
*/
pva_kmd_mutex_t chunk_pool_lock; pva_kmd_mutex_t chunk_pool_lock;
/**
* @brief Pool of command buffer chunks for efficient allocation
*/
struct pva_kmd_cmdbuf_chunk_pool chunk_pool; struct pva_kmd_cmdbuf_chunk_pool chunk_pool;
/**
* @brief Maximum number of queues supported by this context
* Valid range: [0 .. PVA_MAX_QUEUES_PER_CONTEXT]
*/
uint32_t max_n_queues; uint32_t max_n_queues;
/**
* @brief Memory allocation for queue allocator bookkeeping
*/
void *queue_allocator_mem; void *queue_allocator_mem;
/**
* @brief Block allocator for managing queue allocation within context
*/
struct pva_kmd_block_allocator queue_allocator; struct pva_kmd_block_allocator queue_allocator;
/**
* @brief Platform-specific private data pointer
*/
void *plat_data; void *plat_data;
/**
* @brief Shared memory handle for CCQ communication
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t ccq_shm_handle; uint64_t ccq_shm_handle;
/**
* @brief Lock protecting OCB (On-Chip Buffer) operations
*/
pva_kmd_mutex_t ocb_lock; pva_kmd_mutex_t ocb_lock;
/** Status memory for this context. KMD shares ownership of this memory
* with the UMD so that FW can write safely. */
struct pva_kmd_device_memory *status_mem;
/**
* @brief PFSD (Power Functional Safety Diagnostic) resource IDs
*
* @details Stores resource IDs for PFSD buffers, executables, and configurations
* that are registered with the resource table for this context
*/
struct pva_pfsd_resource_ids pfsd_resource_ids;
}; };
/** /**
* @brief Allocate a KMD context. * @brief Allocate a KMD context.
*
* @details This function performs the following operations:
* - Allocates memory for a new @ref pva_kmd_context structure
* - Initializes basic context fields including device pointer
* - Allocates a unique CCQ ID from the device's available CCQ pool
* - Sets up initial resource table and queue allocator configurations
* - Initializes synchronization primitives including mutexes
* - Configures platform-specific context data if required
* - Prepares the context for initialization via @ref pva_kmd_context_init()
*
* The allocated context must be initialized using @ref pva_kmd_context_init()
* before it can be used for operations. The context should be destroyed using
* @ref pva_kmd_context_destroy() when no longer needed.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
*
* @retval non-null Pointer to successfully allocated @ref pva_kmd_context
* @retval NULL Context allocation failed due to memory shortage,
* CCQ unavailability, or initialization failure
*/ */
struct pva_kmd_context *pva_kmd_context_create(struct pva_kmd_device *pva); struct pva_kmd_context *pva_kmd_context_create(struct pva_kmd_device *pva);
/** /**
* @brief Destroy a KMD context. * @brief Destroy a KMD context.
* *
* @details This function performs the following operations:
* - Notifies firmware of context destruction using appropriate messaging
* - Waits for firmware acknowledgment of context cleanup
* - If firmware notification succeeds, calls @ref pva_kmd_free_context()
* to immediately free context resources
* - If firmware notification fails, adds context to deferred free list
* using @ref pva_kmd_add_deferred_context_free()
* - Ensures proper cleanup of context resources and CCQ assignment
*
* This function first notify FW of context destruction. If successful, it * This function first notify FW of context destruction. If successful, it
* calls pva_kmd_free_context() to free the context. Otherwise, the * calls @ref pva_kmd_free_context() to free the context. Otherwise, the
* free is deferred until PVA is powered off. * free is deferred until PVA is powered off. Deferred cleanup ensures
* that contexts are properly cleaned up even when firmware communication
* is not possible.
*
* @param[in] client Pointer to @ref pva_kmd_context structure to destroy
* Valid value: non-null, must be a valid context created by
* @ref pva_kmd_context_create()
*/ */
void pva_kmd_context_destroy(struct pva_kmd_context *client); void pva_kmd_context_destroy(struct pva_kmd_context *client);
/** /**
* @brief Free a KMD context. * @brief Free a KMD context.
* *
* @details This function performs the following operations:
* - Frees all context-allocated memory including queues and resource tables
* - Releases the assigned CCQ ID back to the device's available pool
* - Destroys synchronization primitives including mutexes and semaphores
* - Cleans up platform-specific context resources
* - Deallocates command buffer chunks and submission memory
* - Frees the context structure itself
*
* This function frees the context without notifying FW. We need to make sure FW * This function frees the context without notifying FW. We need to make sure FW
* will not access any context resources before calling this function. * will not access any context resources before calling this function. This
* function is typically called either after successful firmware notification
* or during device shutdown when firmware communication is not required.
*
* @param[in] ctx Pointer to @ref pva_kmd_context structure to free
* Valid value: non-null, firmware must not be accessing
* context resources
*/ */
void pva_kmd_free_context(struct pva_kmd_context *ctx); void pva_kmd_free_context(struct pva_kmd_context *ctx);
/** /**
* @brief Initialize a KMD context. * @brief Initialize a KMD context.
* *
* @details This function performs the following operations:
* - Allocates and configures the context's resource table with specified capacity
* - Sets up context-specific command queues and submission infrastructure
* - Initializes memory allocations for command buffers and synchronization
* - Configures SMMU context for memory protection and isolation
* - Establishes communication channels with firmware for this context
* - Sets up queue allocator for managing multiple queues within the context
* - Marks the context as initialized and ready for operation
*
* The user provides a CCQ range (inclusive on both ends) and the KMD will pick * The user provides a CCQ range (inclusive on both ends) and the KMD will pick
* one CCQ from this range. * one CCQ from this range. The context must be created using
* @ref pva_kmd_context_create() before calling this function. After successful
* initialization, the context is ready to accept command submissions and
* resource registrations.
*
* @param[in, out] ctx Pointer to @ref pva_kmd_context structure
* Valid value: non-null, created but not yet initialized
* @param[in] res_table_capacity Maximum number of resources the context can manage
* Valid range: [1 .. PVA_MAX_RESOURCE_TABLE_ENTRIES]
*
* @retval PVA_SUCCESS Context initialized successfully
* @retval PVA_INVAL Context is already initialized
* @retval PVA_BAD_PARAMETER_ERROR Invalid resource table capacity (zero)
* @retval PVA_NOMEM Memory allocation failed for context resources
* @retval PVA_NO_RESOURCE_ID No available resource IDs for memory registration
*/ */
enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx, enum pva_error pva_kmd_context_init(struct pva_kmd_context *ctx,
uint32_t res_table_capacity); uint32_t res_table_capacity,
uint64_t status_shm_hdl);
/**
* @brief Retrieve a context by its allocation ID from the device
*
* @details This function performs the following operations:
* - Validates the provided allocation ID against the device's context pool
* - Uses the device's context allocator to locate the corresponding context
* - Performs bounds checking to ensure the allocation ID is valid
* - Returns the context pointer if found, or NULL if invalid
* - Provides safe access to contexts using their allocation identifiers
*
* This function provides a safe way to retrieve context pointers using
* allocation IDs, which are used internally by the KMD to track and
* manage contexts. The allocation ID is typically assigned during context
* creation and remains valid until context destruction.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] alloc_id Allocation ID of the context to retrieve
* Valid range: [0 .. max_n_contexts-1]
*
* @retval non-null Pointer to @ref pva_kmd_context if allocation ID is valid
* @retval NULL Invalid allocation ID or context not found
*/
struct pva_kmd_context *pva_kmd_get_context(struct pva_kmd_device *pva, struct pva_kmd_context *pva_kmd_get_context(struct pva_kmd_device *pva,
uint8_t alloc_id); uint8_t alloc_id);

View File

@@ -10,24 +10,33 @@
#include "pva_kmd_vpu_app_auth.h" #include "pva_kmd_vpu_app_auth.h"
#include "pva_kmd_shared_buffer.h" #include "pva_kmd_shared_buffer.h"
#include "pva_kmd_r5_ocd.h" #include "pva_kmd_r5_ocd.h"
#include "pva_kmd_fw_tracepoints.h"
#include "pva_kmd_limits.h"
uint64_t pva_kmd_read_from_buffer_to_user(void *to, uint64_t count, int64_t pva_kmd_read_from_buffer_to_user(void *to, uint64_t count,
uint64_t offset, const void *from, uint64_t offset, const void *from,
uint64_t available) uint64_t available)
{ {
if (offset >= available || !count) { uint64_t bytes_copied;
if ((offset >= available) || (count == 0U)) {
return 0; return 0;
} }
if (count > available - offset) { if (count > available - offset) {
count = available - offset; count = available - offset;
} }
if (pva_kmd_copy_data_to_user(to, (uint8_t *)from + offset, count)) { if (pva_kmd_copy_data_to_user(to, (const uint8_t *)from + offset,
count) != 0UL) {
pva_kmd_log_err("failed to copy read buffer to user"); pva_kmd_log_err("failed to copy read buffer to user");
return 0; return 0;
} }
return count; bytes_copied = count;
/* Ensure result fits in int64_t for debugfs interface */
ASSERT(bytes_copied <= (uint64_t)S64_MAX);
return (int64_t)bytes_copied;
} }
#if PVA_ENABLE_NSYS_PROFILING == 1
static int64_t profiling_level_read(struct pva_kmd_device *dev, void *file_data, static int64_t profiling_level_read(struct pva_kmd_device *dev, void *file_data,
uint8_t *out_buffer, uint64_t offset, uint8_t *out_buffer, uint64_t offset,
uint64_t size) uint64_t size)
@@ -46,7 +55,8 @@ static int64_t profiling_level_read(struct pva_kmd_device *dev, void *file_data,
formatted_len++; // Account for null terminator formatted_len++; // Account for null terminator
return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset, return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset,
kernel_buffer, formatted_len); kernel_buffer,
(uint64_t)formatted_len);
} }
static int64_t profiling_level_write(struct pva_kmd_device *dev, static int64_t profiling_level_write(struct pva_kmd_device *dev,
@@ -91,120 +101,84 @@ static int64_t profiling_level_write(struct pva_kmd_device *dev,
} }
} }
return size; return (int64_t)size;
}
static int64_t print_vpu_stats(struct pva_kmd_tegrastats *kmd_tegra_stats,
uint8_t *out_buffer, uint64_t offset,
uint64_t len)
{
char kernel_buffer[256];
int64_t formatted_len;
formatted_len = snprintf(
kernel_buffer, sizeof(kernel_buffer),
"%llu\n%llu\n%llu\n%llu\n",
(long long unsigned int)(kmd_tegra_stats->window_start_time),
(long long unsigned int)(kmd_tegra_stats->window_end_time),
(long long unsigned int)
kmd_tegra_stats->average_vpu_utilization[0],
(long long unsigned int)
kmd_tegra_stats->average_vpu_utilization[1]);
if (formatted_len <= 0) {
return 0;
}
formatted_len++; //accounting for null terminating character
if (len < (uint64_t)formatted_len) {
return 0;
}
// Copy the formatted string from kernel buffer to user buffer
return pva_kmd_read_from_buffer_to_user(out_buffer, len, offset,
kernel_buffer, formatted_len);
}
static int64_t get_vpu_stats(struct pva_kmd_device *dev, void *file_data,
uint8_t *out_buffer, uint64_t offset,
uint64_t size)
{
struct pva_kmd_tegrastats kmd_tegra_stats;
// We don't support partial reads for vpu stats because we cannot mix two
// reads at different times together.
if (offset != 0) {
return 0;
}
kmd_tegra_stats.window_start_time = 0;
kmd_tegra_stats.window_end_time = 0;
kmd_tegra_stats.average_vpu_utilization[0] = 0;
kmd_tegra_stats.average_vpu_utilization[1] = 0;
if (pva_kmd_device_maybe_on(dev))
pva_kmd_notify_fw_get_tegra_stats(dev, &kmd_tegra_stats);
return print_vpu_stats(&kmd_tegra_stats, out_buffer, offset, size);
} }
#endif
static int64_t get_vpu_allowlist_enabled(struct pva_kmd_device *pva, static int64_t get_vpu_allowlist_enabled(struct pva_kmd_device *pva,
void *file_data, uint8_t *out_buffer, void *file_data, uint8_t *out_buffer,
uint64_t offset, uint64_t size) uint64_t offset, uint64_t size)
{ {
// 1 byte for '0' or '1' and another 1 byte for the Null character char out_str[2]; // 1 byte for '0' or '1' and another 1 byte for the Null character
char out_str[2]; int ret;
pva_kmd_mutex_lock(&(pva->pva_auth->allow_list_lock)); pva_kmd_mutex_lock(&(pva->pva_auth->allow_list_lock));
snprintf(out_str, sizeof(out_str), "%d", ret = snprintf(out_str, sizeof(out_str), "%d",
(int)pva->pva_auth->pva_auth_enable); (int)pva->pva_auth->pva_auth_enable);
pva_kmd_mutex_unlock(&(pva->pva_auth->allow_list_lock)); pva_kmd_mutex_unlock(&(pva->pva_auth->allow_list_lock));
if ((ret < 0) || ((size_t)ret >= sizeof(out_str))) {
pva_kmd_log_err("snprintf failed or truncated");
return (int64_t)PVA_INVAL;
}
// Copy the formatted string from kernel buffer to user buffer // Copy the formatted string from kernel buffer to user buffer
return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset, return pva_kmd_read_from_buffer_to_user(
out_str, sizeof(out_str)); out_buffer, size, offset, out_str, (uint64_t)sizeof(out_str));
} }
static int64_t update_vpu_allowlist(struct pva_kmd_device *pva, void *file_data, static int64_t update_vpu_allowlist(struct pva_kmd_device *pva, void *file_data,
const uint8_t *in_buffer, uint64_t offset, const uint8_t *in_buffer, uint64_t offset,
uint64_t size) uint64_t size)
{ {
char strbuf[2]; // 1 byte for '0' or '1' and another 1 byte for the Null character char input_buf
[2]; // 1 byte for '0' or '1' and another 1 byte for the Null character
uint32_t base = 10; uint32_t base = 10;
uint32_t pva_auth_enable; uint32_t pva_auth_enable;
unsigned long retval; unsigned long retval;
unsigned long strtol_result;
if (size == 0) { if (size == 0U) {
pva_kmd_log_err("Write failed, no data provided"); pva_kmd_log_err("Write failed, no data provided");
return -1; return -1;
} }
// Copy a single character, ignore the rest // Copy a single character, ignore the rest
retval = pva_kmd_copy_data_from_user(strbuf, in_buffer + offset, 1); retval = pva_kmd_copy_data_from_user(input_buf, in_buffer + offset, 1);
if (retval != 0u) { if (retval != 0UL) {
pva_kmd_log_err("Failed to copy write buffer from user"); pva_kmd_log_err("Failed to copy write buffer from user");
return -1; return -1;
} }
// Explicitly null terminate the string for conversion // Explicitly null terminate the string for conversion
strbuf[1] = '\0'; input_buf[1] = '\0';
pva_auth_enable = pva_kmd_strtol(strbuf, base); /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
strtol_result = pva_kmd_strtol(input_buf, (int32_t)base);
/* Validate result fits in uint32_t */
if (strtol_result > U32_MAX) {
pva_kmd_log_err("pva_kmd_debugfs: Value exceeds U32_MAX");
return -1;
}
/* CERT INT31-C: strtol_result validated to fit in uint32_t, safe to cast */
pva_auth_enable = (uint32_t)strtol_result;
pva_kmd_mutex_lock(&(pva->pva_auth->allow_list_lock)); pva_kmd_mutex_lock(&(pva->pva_auth->allow_list_lock));
pva->pva_auth->pva_auth_enable = (pva_auth_enable == 1) ? true : false; pva->pva_auth->pva_auth_enable = (pva_auth_enable == 1U) ? true : false;
if (pva->pva_auth->pva_auth_enable) if (pva->pva_auth->pva_auth_enable) {
pva->pva_auth->pva_auth_allow_list_parsed = false; pva->pva_auth->pva_auth_allow_list_parsed = false;
}
pva_kmd_mutex_unlock(&(pva->pva_auth->allow_list_lock)); pva_kmd_mutex_unlock(&(pva->pva_auth->allow_list_lock));
return size; return (int64_t)size;
} }
static int64_t get_vpu_allowlist_path(struct pva_kmd_device *pva, static int64_t get_vpu_allowlist_path(struct pva_kmd_device *pva,
void *file_data, uint8_t *out_buffer, void *file_data, uint8_t *out_buffer,
uint64_t offset, uint64_t size) uint64_t offset, uint64_t size)
{ {
uint64_t len; int64_t len;
pva_kmd_mutex_lock(&(pva->pva_auth->allow_list_lock)); pva_kmd_mutex_lock(&(pva->pva_auth->allow_list_lock));
len = pva_kmd_read_from_buffer_to_user( len = pva_kmd_read_from_buffer_to_user(
out_buffer, size, offset, out_buffer, size, offset,
@@ -223,7 +197,7 @@ static int64_t update_vpu_allowlist_path(struct pva_kmd_device *pva,
char buffer[ALLOWLIST_FILE_LEN]; char buffer[ALLOWLIST_FILE_LEN];
unsigned long retval; unsigned long retval;
if (size == 0) { if (size == 0U) {
return 0; return 0;
} }
@@ -235,7 +209,7 @@ static int64_t update_vpu_allowlist_path(struct pva_kmd_device *pva,
} }
retval = pva_kmd_copy_data_from_user(buffer, in_buffer, size); retval = pva_kmd_copy_data_from_user(buffer, in_buffer, size);
if (retval != 0u) { if (retval != 0UL) {
pva_kmd_log_err("Failed to copy write buffer from user"); pva_kmd_log_err("Failed to copy write buffer from user");
return -1; return -1;
} }
@@ -247,79 +221,7 @@ static int64_t update_vpu_allowlist_path(struct pva_kmd_device *pva,
pva_kmd_update_allowlist_path(pva, buffer); pva_kmd_update_allowlist_path(pva, buffer);
pva_kmd_mutex_unlock(&(pva->pva_auth->allow_list_lock)); pva_kmd_mutex_unlock(&(pva->pva_auth->allow_list_lock));
return size; return (int64_t)size;
}
static int64_t update_fw_trace_level(struct pva_kmd_device *pva,
void *file_data, const uint8_t *in_buffer,
uint64_t offset, uint64_t size)
{
uint32_t trace_level;
unsigned long retval;
size_t copy_size;
uint32_t base = 10;
char strbuf[11]; // 10 bytes for the highest 32bit value and another 1 byte for the Null character
strbuf[10] = '\0';
if (size == 0) {
pva_kmd_log_err("Write failed, no data provided");
return -1;
}
/* Copy minimum of buffer size and input size */
copy_size = (size < (sizeof(strbuf) - 1)) ? size : (sizeof(strbuf) - 1);
retval = pva_kmd_copy_data_from_user(strbuf, in_buffer + offset,
copy_size);
if (retval != 0u) {
pva_kmd_log_err("Failed to copy write buffer from user");
return -1;
}
trace_level = pva_kmd_strtol(strbuf, base);
pva->fw_trace_level = trace_level;
/* If device is on, busy the device and set the debug log level */
if (pva_kmd_device_maybe_on(pva) == true) {
enum pva_error err;
err = pva_kmd_device_busy(pva);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"pva_kmd_device_busy failed when submitting set debug log level cmd");
goto err_end;
}
err = pva_kmd_notify_fw_set_trace_level(pva, trace_level);
pva_kmd_device_idle(pva);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Failed to notify FW about debug log level change");
}
}
err_end:
return copy_size;
}
static int64_t get_fw_trace_level(struct pva_kmd_device *dev, void *file_data,
uint8_t *out_buffer, uint64_t offset,
uint64_t size)
{
char print_buffer[64];
int formatted_len;
formatted_len = snprintf(print_buffer, sizeof(print_buffer), "%u\n",
dev->fw_trace_level);
if (formatted_len <= 0) {
return -1;
}
return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset,
print_buffer,
(uint64_t)formatted_len);
} }
static int64_t write_simulate_sc7(struct pva_kmd_device *pva, void *file_data, static int64_t write_simulate_sc7(struct pva_kmd_device *pva, void *file_data,
@@ -330,32 +232,32 @@ static int64_t write_simulate_sc7(struct pva_kmd_device *pva, void *file_data,
enum pva_error err; enum pva_error err;
unsigned long ret; unsigned long ret;
if ((offset != 0) || (size < 1)) { if ((offset != 0U) || (size < 1U)) {
return -EINVAL; return -EINVAL;
} }
ret = pva_kmd_copy_data_from_user(&buf, in_buffer, 1); ret = pva_kmd_copy_data_from_user(&buf, in_buffer, 1);
if (ret != 0) { if (ret != 0U) {
pva_kmd_log_err( pva_kmd_log_err(
"SC7 simulation: failed to copy data from user"); "SC7 simulation: failed to copy data from user");
return -EFAULT; return -EFAULT;
} }
if (buf == '1') { if (buf == (uint8_t)'1') {
if (pva->debugfs_context.entered_sc7 == 0) { if (pva->debugfs_context.entered_sc7 == false) {
err = pva_kmd_simulate_enter_sc7(pva); err = pva_kmd_simulate_enter_sc7(pva);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
return -EFAULT; return -EFAULT;
} }
pva->debugfs_context.entered_sc7 = 1; pva->debugfs_context.entered_sc7 = true;
} }
} else if (buf == '0') { } else if (buf == (uint8_t)'0') {
if (pva->debugfs_context.entered_sc7 == 1) { if (pva->debugfs_context.entered_sc7 == true) {
err = pva_kmd_simulate_exit_sc7(pva); err = pva_kmd_simulate_exit_sc7(pva);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
return -EFAULT; return -EFAULT;
} }
pva->debugfs_context.entered_sc7 = 0; pva->debugfs_context.entered_sc7 = false;
} }
} else { } else {
pva_kmd_log_err( pva_kmd_log_err(
@@ -363,7 +265,7 @@ static int64_t write_simulate_sc7(struct pva_kmd_device *pva, void *file_data,
return -EINVAL; return -EINVAL;
} }
return size; return (int64_t)size;
} }
static int64_t read_simulate_sc7(struct pva_kmd_device *pva, void *file_data, static int64_t read_simulate_sc7(struct pva_kmd_device *pva, void *file_data,
@@ -374,20 +276,15 @@ static int64_t read_simulate_sc7(struct pva_kmd_device *pva, void *file_data,
buf = pva->debugfs_context.entered_sc7 ? '1' : '0'; buf = pva->debugfs_context.entered_sc7 ? '1' : '0';
return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset, &buf, return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset, &buf,
1); (uint64_t)1);
} }
enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *pva) enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *pva)
{ {
static const char *vpu_ocd_names[NUM_VPU_BLOCKS] = { "ocd_vpu0_v3",
"ocd_vpu1_v3" };
struct pva_kmd_file_ops *profiling_fops;
enum pva_error err; enum pva_error err;
pva_kmd_debugfs_create_bool(pva, "stats_enabled", #if PVA_ENABLE_NSYS_PROFILING == 1
&pva->debugfs_context.stats_enable); struct pva_kmd_file_ops *profiling_fops;
pva_kmd_debugfs_create_bool(pva, "vpu_debug",
&pva->debugfs_context.vpu_debug);
// Create profiling_level file operations // Create profiling_level file operations
profiling_fops = &pva->debugfs_context.profiling_level_fops; profiling_fops = &pva->debugfs_context.profiling_level_fops;
@@ -396,6 +293,7 @@ enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *pva)
profiling_fops->open = NULL; profiling_fops->open = NULL;
profiling_fops->release = NULL; profiling_fops->release = NULL;
profiling_fops->pdev = pva; profiling_fops->pdev = pva;
err = pva_kmd_debugfs_create_file(pva, "profiling_level", err = pva_kmd_debugfs_create_file(pva, "profiling_level",
profiling_fops); profiling_fops);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -403,37 +301,17 @@ enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *pva)
"Failed to create profiling_level debugfs file"); "Failed to create profiling_level debugfs file");
return err; return err;
} }
#endif
pva->debugfs_context.vpu_fops.read = &get_vpu_stats; err = pva_kmd_tegrastats_init_debugfs(pva);
pva->debugfs_context.vpu_fops.write = NULL;
pva->debugfs_context.vpu_fops.pdev = pva;
err = pva_kmd_debugfs_create_file(pva, "vpu_stats",
&pva->debugfs_context.vpu_fops);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to create vpu_stats debugfs file"); pva_kmd_log_err("Failed to create tegrastats debugfs file");
return err; return err;
} }
for (uint32_t i = 0; i < NUM_VPU_BLOCKS; i++) { err = pva_kmd_vpu_ocd_init_debugfs(pva);
pva->debugfs_context.vpu_ocd_fops[i].open = if (err != PVA_SUCCESS) {
&pva_kmd_vpu_ocd_open; return err;
pva->debugfs_context.vpu_ocd_fops[i].release =
&pva_kmd_vpu_ocd_release;
pva->debugfs_context.vpu_ocd_fops[i].read =
&pva_kmd_vpu_ocd_read;
pva->debugfs_context.vpu_ocd_fops[i].write =
&pva_kmd_vpu_ocd_write;
pva->debugfs_context.vpu_ocd_fops[i].pdev = pva;
pva->debugfs_context.vpu_ocd_fops[i].file_data =
(void *)&pva->regspec.vpu_dbg_instr_reg_offset[i];
err = pva_kmd_debugfs_create_file(
pva, vpu_ocd_names[i],
&pva->debugfs_context.vpu_ocd_fops[i]);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Failed to create vpu_ocd debugfs file");
return err;
}
} }
pva->debugfs_context.allowlist_ena_fops.read = pva->debugfs_context.allowlist_ena_fops.read =
@@ -461,12 +339,7 @@ enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *pva)
return err; return err;
} }
pva->debugfs_context.fw_trace_level_fops.write = &update_fw_trace_level; err = pva_kmd_fw_tracepoints_init_debugfs(pva);
pva->debugfs_context.fw_trace_level_fops.read = &get_fw_trace_level;
pva->debugfs_context.fw_trace_level_fops.pdev = pva;
err = pva_kmd_debugfs_create_file(
pva, "fw_trace_level",
&pva->debugfs_context.fw_trace_level_fops);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to create fw_trace_level debugfs file"); pva_kmd_log_err("Failed to create fw_trace_level debugfs file");
return err; return err;

View File

@@ -7,45 +7,247 @@
#include "pva_kmd_shim_debugfs.h" #include "pva_kmd_shim_debugfs.h"
#include "pva_kmd_fw_profiler.h" #include "pva_kmd_fw_profiler.h"
/**
* @brief Number of VPU blocks supported for debugging
*
* @details Number of VPU blocks supported for debugging operations.
* This constant defines the maximum number of VPU debugging interfaces
* that can be created in the debug system.
*/
#define NUM_VPU_BLOCKS 2U #define NUM_VPU_BLOCKS 2U
/**
* @brief File operations structure for debug interfaces
*
* @details This structure defines the callback functions for debug file
* operations including open, close, read, and write operations. It provides
* a platform-agnostic interface for accessing debug information through
* file-like operations, supporting both reading and writing of debug data.
*/
struct pva_kmd_file_ops { struct pva_kmd_file_ops {
/**
* @brief Open callback for debug file
* Valid value: non-null function pointer or NULL if not supported
*/
int (*open)(struct pva_kmd_device *dev); int (*open)(struct pva_kmd_device *dev);
/**
* @brief Release/close callback for debug file
* Valid value: non-null function pointer or NULL if not supported
*/
int (*release)(struct pva_kmd_device *dev); int (*release)(struct pva_kmd_device *dev);
/**
* @brief Read callback for debug file
* Valid value: non-null function pointer or NULL if not supported
*/
int64_t (*read)(struct pva_kmd_device *dev, void *file_data, int64_t (*read)(struct pva_kmd_device *dev, void *file_data,
uint8_t *data, uint64_t offset, uint64_t size); uint8_t *data, uint64_t offset, uint64_t size);
/**
* @brief Write callback for debug file
* Valid value: non-null function pointer or NULL if not supported
*/
int64_t (*write)(struct pva_kmd_device *dev, void *file_data, int64_t (*write)(struct pva_kmd_device *dev, void *file_data,
const uint8_t *data, uint64_t offset, uint64_t size); const uint8_t *data, uint64_t offset, uint64_t size);
/**
* @brief Platform-specific device pointer
*/
void *pdev; void *pdev;
/**
* @brief File-specific data pointer
*/
void *file_data; void *file_data;
}; };
/**
* @brief Debug context for PVA device debugging
*
* @details This structure maintains the complete debug context
* for a PVA device, including various debug interfaces, configuration
* settings, and file operation handlers. It provides comprehensive debugging
* capabilities including VPU debugging, profiling, allowlist management,
* hardware performance monitoring, and firmware tracing.
*/
struct pva_kmd_debugfs_context { struct pva_kmd_debugfs_context {
/**
* @brief Enable flag for statistics collection
* Valid values: true (enabled), false (disabled)
*/
bool stats_enable; bool stats_enable;
/**
* @brief Enable flag for VPU debugging
* Valid values: true (enabled), false (disabled)
*/
bool vpu_debug; bool vpu_debug;
/**
* @brief Enable flag for VPU print output
* Valid values: true (enabled), false (disabled)
*/
bool vpu_print_enable; bool vpu_print_enable;
/**
* @brief Flag indicating if system entered SC7 state
* Valid values: true (entered), false (not entered)
*/
bool entered_sc7; bool entered_sc7;
/**
* @brief Path to allowlist configuration file
* Valid value: null-terminated string or NULL
*/
char *allowlist_path; char *allowlist_path;
/**
* @brief Current profiling level setting
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t profiling_level; uint32_t profiling_level;
/**
* @brief File operations for VPU debugging interface
*/
struct pva_kmd_file_ops vpu_fops; struct pva_kmd_file_ops vpu_fops;
/**
* @brief File operations for allowlist enable interface
*/
struct pva_kmd_file_ops allowlist_ena_fops; struct pva_kmd_file_ops allowlist_ena_fops;
/**
* @brief File operations for allowlist path interface
*/
struct pva_kmd_file_ops allowlist_path_fops; struct pva_kmd_file_ops allowlist_path_fops;
/**
* @brief File operations for hardware performance monitoring interface
*/
struct pva_kmd_file_ops hwpm_fops; struct pva_kmd_file_ops hwpm_fops;
/**
* @brief File operations for profiling level interface
*/
struct pva_kmd_file_ops profiling_level_fops; struct pva_kmd_file_ops profiling_level_fops;
/**
* @brief Data pointer for hardware performance monitoring
*/
void *data_hwpm; void *data_hwpm;
/**
* @brief Array of file operations for VPU on-chip debugging interfaces
*/
struct pva_kmd_file_ops vpu_ocd_fops[NUM_VPU_BLOCKS]; struct pva_kmd_file_ops vpu_ocd_fops[NUM_VPU_BLOCKS];
/**
* @brief Global firmware profiling configuration
*/
struct pva_kmd_fw_profiling_config g_fw_profiling_config; struct pva_kmd_fw_profiling_config g_fw_profiling_config;
/**
* @brief File operations for firmware trace level interface
*/
struct pva_kmd_file_ops fw_trace_level_fops; struct pva_kmd_file_ops fw_trace_level_fops;
/**
* @brief File operations for SC7 simulation interface
*/
struct pva_kmd_file_ops simulate_sc7_fops; struct pva_kmd_file_ops simulate_sc7_fops;
/**
* @brief File operations for R5 on-chip debugging interface
*/
struct pva_kmd_file_ops r5_ocd_fops; struct pva_kmd_file_ops r5_ocd_fops;
/**
* @brief Buffer for R5 OCD staging operations
*/
void *r5_ocd_stage_buffer; void *r5_ocd_stage_buffer;
}; };
/**
* @brief Create debug nodes for PVA device debugging
*
* @details This function performs the following operations:
* - Creates debug nodes for various PVA debugging interfaces
* - Sets up file operation callbacks for each debug interface
* - Initializes VPU debugging interfaces for all VPU blocks
* - Creates hardware performance monitoring debug nodes
* - Sets up firmware profiling and tracing interfaces
* - Configures allowlist management debug interfaces
* - Establishes R5 and VPU on-chip debugging capabilities
* - Provides comprehensive debugging infrastructure for the PVA device
*
* The created debug nodes enable access to various PVA debugging features
* through the debug interface, supporting development, debugging,
* and performance analysis workflows.
*
* @param[in] dev Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS Debug nodes created successfully
* @retval PVA_NOMEM Failed to allocate memory for debug infrastructure
* @retval PVA_INVAL Invalid parameters for debug node creation
* @retval PVA_INTERNAL Platform-specific debug creation failed
*/
enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *dev); enum pva_error pva_kmd_debugfs_create_nodes(struct pva_kmd_device *dev);
/**
* @brief Destroy debug nodes and clean up resources
*
* @details This function performs the following operations:
* - Removes all debug nodes created for the PVA device
* - Cleans up file operation callbacks and associated data structures
* - Frees memory allocated for debug interfaces and buffers
* - Destroys VPU and R5 on-chip debugging interfaces
* - Cleans up hardware performance monitoring debug nodes
* - Removes firmware profiling and tracing interfaces
* - Ensures proper cleanup of all debugging infrastructure
*
* This function should be called during device cleanup to ensure
* proper removal of all debug interfaces and prevent resource leaks.
*
* @param[in] dev Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must have been initialized with debug nodes
*/
void pva_kmd_debugfs_destroy_nodes(struct pva_kmd_device *dev); void pva_kmd_debugfs_destroy_nodes(struct pva_kmd_device *dev);
uint64_t pva_kmd_read_from_buffer_to_user(void *to, uint64_t count, /**
uint64_t offset, const void *from, * @brief Copy data from buffer to user space with bounds checking
uint64_t available); *
* @details This function performs the following operations:
* - Validates the requested read parameters against buffer bounds
* - Calculates the actual amount of data available for reading
* - Handles offset positioning within the source buffer
* - Copies data from the source buffer to the destination
* - Ensures no buffer overruns or invalid memory access
* - Returns the actual number of bytes copied to user space
* - Validates result fits in int64_t for debugfs interface compatibility
*
* This utility function provides safe buffer-to-user copying for debug
* file read operations, preventing buffer overruns and ensuring proper
* bounds checking for all debug interface data transfers.
*
* @param[out] to Destination buffer for copied data
* Valid value: non-null, min size count bytes
* @param[in] count Maximum number of bytes to copy
* Valid range: [0 .. UINT64_MAX]
* @param[in] offset Offset within source buffer to start reading
* Valid range: [0 .. UINT64_MAX]
* @param[in] from Source buffer containing data to copy
* Valid value: non-null
* @param[in] available Total size of available data in source buffer
* Valid range: [0 .. UINT64_MAX]
*
* @retval bytes_copied Number of bytes actually copied to destination
* Range: [0 .. min(count, available-offset, INT64_MAX)]
*/
int64_t pva_kmd_read_from_buffer_to_user(void *to, uint64_t count,
uint64_t offset, const void *from,
uint64_t available);
#endif //PVA_KMD_DEBUGFS_H #endif //PVA_KMD_DEBUGFS_H

View File

@@ -18,13 +18,13 @@
#include "pva_kmd_regs.h" #include "pva_kmd_regs.h"
#include "pva_kmd_device_memory.h" #include "pva_kmd_device_memory.h"
#include "pva_kmd_fw_profiler.h" #include "pva_kmd_fw_profiler.h"
#include "pva_kmd_fw_debug.h"
#include "pva_kmd_vpu_app_auth.h" #include "pva_kmd_vpu_app_auth.h"
#include "pva_utils.h" #include "pva_utils.h"
#include "pva_kmd_debugfs.h" #include "pva_kmd_debugfs.h"
#include "pva_kmd_tegra_stats.h" #include "pva_kmd_tegra_stats.h"
#include "pva_kmd_shim_silicon.h" #include "pva_kmd_shim_silicon.h"
#include "pva_kmd_shared_buffer.h" #include "pva_kmd_shared_buffer.h"
#include "pva_kmd_fw_tracepoints.h"
#include "pva_kmd_abort.h" #include "pva_kmd_abort.h"
#include "pva_version.h" #include "pva_version.h"
@@ -130,22 +130,27 @@ static void pva_kmd_device_init_submission(struct pva_kmd_device *pva)
/* Add submit memory to resource table */ /* Add submit memory to resource table */
err = pva_kmd_add_dram_buffer_resource(&pva->dev_resource_table, err = pva_kmd_add_dram_buffer_resource(&pva->dev_resource_table,
pva->submit_memory, pva->submit_memory,
&pva->submit_memory_resource_id); &pva->submit_memory_resource_id,
false);
ASSERT(err == PVA_SUCCESS); ASSERT(err == PVA_SUCCESS);
pva_kmd_update_fw_resource_table(&pva->dev_resource_table); pva_kmd_update_fw_resource_table(&pva->dev_resource_table);
/* Init chunk pool */ /* Init chunk pool */
pva_kmd_cmdbuf_chunk_pool_init( err = pva_kmd_cmdbuf_chunk_pool_init(
&pva->chunk_pool, pva->submit_memory_resource_id, 0, &pva->chunk_pool, pva->submit_memory_resource_id, 0,
chunk_mem_size, pva_kmd_get_max_cmdbuf_chunk_size(pva), (uint32_t)chunk_mem_size,
pva_kmd_get_max_cmdbuf_chunk_size(pva),
PVA_KMD_MAX_NUM_KMD_CHUNKS, pva->submit_memory->va); PVA_KMD_MAX_NUM_KMD_CHUNKS, pva->submit_memory->va);
ASSERT(err == PVA_SUCCESS);
/* Init fence */ /* Init fence */
pva->fence_offset = chunk_mem_size; pva->fence_offset = chunk_mem_size;
/* Init submitter */ /* Init submitter */
pva_kmd_mutex_init(&pva->submit_lock); err = pva_kmd_mutex_init(&pva->submit_lock);
pva_kmd_mutex_init(&pva->chunk_pool_lock); ASSERT(err == PVA_SUCCESS);
err = pva_kmd_mutex_init(&pva->chunk_pool_lock);
ASSERT(err == PVA_SUCCESS);
post_fence.resource_id = pva->submit_memory_resource_id; post_fence.resource_id = pva->submit_memory_resource_id;
post_fence.offset_lo = iova_lo(pva->fence_offset); post_fence.offset_lo = iova_lo(pva->fence_offset);
post_fence.offset_hi = iova_hi(pva->fence_offset); post_fence.offset_hi = iova_hi(pva->fence_offset);
@@ -153,7 +158,8 @@ static void pva_kmd_device_init_submission(struct pva_kmd_device *pva)
pva_kmd_submitter_init( pva_kmd_submitter_init(
&pva->submitter, &pva->dev_queue, &pva->submit_lock, &pva->submitter, &pva->dev_queue, &pva->submit_lock,
&pva->chunk_pool, &pva->chunk_pool_lock, &pva->chunk_pool, &pva->chunk_pool_lock,
pva_offset_pointer(pva->submit_memory->va, pva->fence_offset), (uint32_t *)pva_offset_pointer(pva->submit_memory->va,
pva->fence_offset),
&post_fence); &post_fence);
} }
@@ -172,14 +178,14 @@ static void pva_kmd_device_deinit_submission(struct pva_kmd_device *pva)
struct pva_kmd_device *pva_kmd_device_create(enum pva_chip_id chip_id, struct pva_kmd_device *pva_kmd_device_create(enum pva_chip_id chip_id,
uint32_t device_index, uint32_t device_index,
bool app_authenticate, bool app_authenticate,
bool test_mode) bool test_mode, void *plat_data)
{ {
struct pva_kmd_device *pva; struct pva_kmd_device *pva;
enum pva_error err; enum pva_error err;
uint32_t size; uint32_t size;
if (test_mode) { if (test_mode) {
pva_kmd_log_err("Test mode is enabled"); pva_kmd_log_info("Test mode is enabled");
} }
pva = pva_kmd_zalloc_nofail(sizeof(*pva)); pva = pva_kmd_zalloc_nofail(sizeof(*pva));
@@ -189,18 +195,23 @@ struct pva_kmd_device *pva_kmd_device_create(enum pva_chip_id chip_id,
pva->load_from_gsc = false; pva->load_from_gsc = false;
pva->is_hv_mode = true; pva->is_hv_mode = true;
pva->max_n_contexts = PVA_MAX_NUM_USER_CONTEXTS; pva->max_n_contexts = PVA_MAX_NUM_USER_CONTEXTS;
pva_kmd_mutex_init(&pva->powercycle_lock); err = pva_kmd_mutex_init(&pva->powercycle_lock);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"pva_kmd_device_init powercycle_lock init failed");
pva_kmd_free(pva);
return NULL;
}
pva_kmd_sema_init(&pva->fw_boot_sema, 0); pva_kmd_sema_init(&pva->fw_boot_sema, 0);
size = safe_mulu32((uint32_t)sizeof(struct pva_kmd_context), size = safe_mulu32((uint32_t)sizeof(struct pva_kmd_context),
pva->max_n_contexts); pva->max_n_contexts);
pva->context_mem = pva_kmd_zalloc(size); pva->context_mem = pva_kmd_zalloc(size);
ASSERT(pva->context_mem != NULL); ASSERT(pva->context_mem != NULL);
err = pva_kmd_block_allocator_init(&pva->context_allocator, err = pva_kmd_block_allocator_init(
pva->context_mem, &pva->context_allocator, pva->context_mem,
PVA_KMD_USER_CONTEXT_ID_BASE, PVA_KMD_USER_CONTEXT_ID_BASE,
sizeof(struct pva_kmd_context), (uint32_t)sizeof(struct pva_kmd_context), pva->max_n_contexts);
pva->max_n_contexts);
ASSERT(err == PVA_SUCCESS); ASSERT(err == PVA_SUCCESS);
if (chip_id == PVA_CHIP_T23X) { if (chip_id == PVA_CHIP_T23X) {
@@ -211,6 +222,8 @@ struct pva_kmd_device *pva_kmd_device_create(enum pva_chip_id chip_id,
FAULT("SOC not supported"); FAULT("SOC not supported");
} }
/* Set platform data before calling platform init */
pva->plat_data = plat_data;
pva_kmd_device_plat_init(pva); pva_kmd_device_plat_init(pva);
pva_kmd_device_init_submission(pva); pva_kmd_device_init_submission(pva);
@@ -236,7 +249,7 @@ static void pva_kmd_wait_for_active_contexts(struct pva_kmd_device *pva)
ctx = pva_kmd_alloc_block(&pva->context_allocator, &unused_id); ctx = pva_kmd_alloc_block(&pva->context_allocator, &unused_id);
if (ctx != NULL) { if (ctx != NULL) {
allocated = safe_addu32(allocated, 1U); allocated = safe_addu8(allocated, 1U);
} else { } else {
pva_kmd_sleep_us(1000); pva_kmd_sleep_us(1000);
} }
@@ -256,29 +269,48 @@ void pva_kmd_device_destroy(struct pva_kmd_device *pva)
pva_kmd_free(pva); pva_kmd_free(pva);
} }
#if PVA_ENABLE_NSYS_PROFILING == 1
enum pva_error pva_kmd_notify_fw_set_profiling_level(struct pva_kmd_device *pva,
uint32_t level)
{
struct pva_cmd_set_profiling_level cmd = { 0 };
pva_kmd_set_cmd_set_profiling_level(&cmd, level);
return pva_kmd_submit_cmd_sync(&pva->submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
}
#endif
static enum pva_error config_fw_by_cmds(struct pva_kmd_device *pva) static enum pva_error config_fw_by_cmds(struct pva_kmd_device *pva)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
#if PVA_ENABLE_FW_PROFILING == 1
err = pva_kmd_notify_fw_enable_profiling(pva); err = pva_kmd_notify_fw_enable_profiling(pva);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto err_out; return err;
} }
#endif
#if PVA_ENABLE_FW_TRACEPOINTS == 1
/* Set FW trace level */ /* Set FW trace level */
err = pva_kmd_notify_fw_set_trace_level(pva, pva->fw_trace_level); err = pva_kmd_notify_fw_set_trace_level(pva, pva->fw_trace_level);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto err_out; return err;
} }
#endif
#if PVA_ENABLE_NSYS_PROFILING == 1
// If the user had set profiling level before power-on, send the update to FW // If the user had set profiling level before power-on, send the update to FW
err = pva_kmd_notify_fw_set_profiling_level( err = pva_kmd_notify_fw_set_profiling_level(
pva, pva->debugfs_context.profiling_level); pva, pva->debugfs_context.profiling_level);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto err_out; return err;
} }
#endif
err_out:
return err; return err;
} }
@@ -296,8 +328,8 @@ static void pva_kmd_print_version_info(struct pva_kmd_device *pva)
/* Query and print firmware version */ /* Query and print firmware version */
const char *prefix = "PVA FW version: "; const char *prefix = "PVA FW version: ";
const char *kmd_prefix = "PVA KMD version: "; const char *kmd_prefix = "PVA KMD version: ";
uint32_t prefix_len = strlen(prefix); uint32_t prefix_len = (uint32_t)strlen(prefix);
uint32_t kmd_prefix_len = strlen(kmd_prefix); uint32_t kmd_prefix_len = (uint32_t)strlen(kmd_prefix);
/* Store initial string */ /* Store initial string */
(void)memcpy(fw_version, prefix, prefix_len); (void)memcpy(fw_version, prefix, prefix_len);
@@ -306,7 +338,7 @@ static void pva_kmd_print_version_info(struct pva_kmd_device *pva)
safe_subu32(PVA_VERSION_BUFFER_SIZE, safe_subu32(PVA_VERSION_BUFFER_SIZE,
prefix_len)); prefix_len));
if (err == PVA_SUCCESS) { if (err == PVA_SUCCESS) {
pva_kmd_log_err(fw_version); pva_kmd_log_info(fw_version);
} else { } else {
pva_kmd_log_err("Failed to query firmware version"); pva_kmd_log_err("Failed to query firmware version");
} }
@@ -316,7 +348,7 @@ static void pva_kmd_print_version_info(struct pva_kmd_device *pva)
(void)memcpy(kmd_version + kmd_prefix_len, PVA_SYSSW_COMMIT_ID, (void)memcpy(kmd_version + kmd_prefix_len, PVA_SYSSW_COMMIT_ID,
sizeof(PVA_SYSSW_COMMIT_ID)); sizeof(PVA_SYSSW_COMMIT_ID));
kmd_version[kmd_prefix_len + sizeof(PVA_SYSSW_COMMIT_ID)] = '\0'; kmd_version[kmd_prefix_len + sizeof(PVA_SYSSW_COMMIT_ID)] = '\0';
pva_kmd_log_err(kmd_version); pva_kmd_log_info(kmd_version);
} }
static enum pva_error pva_kmd_config_fw_after_boot(struct pva_kmd_device *pva) static enum pva_error pva_kmd_config_fw_after_boot(struct pva_kmd_device *pva)
@@ -331,7 +363,7 @@ static enum pva_error pva_kmd_config_fw_after_boot(struct pva_kmd_device *pva)
pva_kmd_send_queue_info_by_ccq(pva, &pva->dev_queue); pva_kmd_send_queue_info_by_ccq(pva, &pva->dev_queue);
err = pva_kmd_shared_buffer_init(pva, PVA_PRIV_CCQ_ID, err = pva_kmd_shared_buffer_init(pva, PVA_PRIV_CCQ_ID,
PVA_KMD_FW_BUF_ELEMENT_SIZE, (uint32_t)PVA_KMD_FW_BUF_ELEMENT_SIZE,
PVA_KMD_FW_PROFILING_BUF_NUM_ELEMENTS, PVA_KMD_FW_PROFILING_BUF_NUM_ELEMENTS,
NULL, NULL); NULL, NULL);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -386,10 +418,15 @@ void pva_kmd_add_deferred_context_free(struct pva_kmd_device *pva,
static void free_deferred_contexts(struct pva_kmd_device *pva) static void free_deferred_contexts(struct pva_kmd_device *pva)
{ {
uint32_t n_deferred_context_free = uint32_t n_deferred_context_free;
(uint32_t)pva_kmd_atomic_load(&pva->n_deferred_context_free); uint32_t i;
int n_deferred;
for (uint32_t i = 0; i < n_deferred_context_free; i++) { n_deferred = pva_kmd_atomic_load(&pva->n_deferred_context_free);
ASSERT(n_deferred >= 0);
n_deferred_context_free = (uint32_t)n_deferred;
for (i = 0; i < n_deferred_context_free; i++) {
uint8_t ccq_id = pva->deferred_context_free_ids[i]; uint8_t ccq_id = pva->deferred_context_free_ids[i];
struct pva_kmd_context *ctx = pva_kmd_get_context(pva, ccq_id); struct pva_kmd_context *ctx = pva_kmd_get_context(pva, ccq_id);
ASSERT(ctx != NULL); ASSERT(ctx != NULL);
@@ -419,6 +456,7 @@ enum pva_error pva_kmd_deinit_fw(struct pva_kmd_device *pva)
/* No longer in recovery state */ /* No longer in recovery state */
pva->recovery = false; pva->recovery = false;
pva->fw_inited = false; pva->fw_inited = false;
pva->fw_aborted = false;
return err; return err;
} }
@@ -431,7 +469,7 @@ enum pva_error pva_kmd_query_fw_version(struct pva_kmd_device *pva,
struct pva_cmd_get_version get_version_cmd = { 0 }; struct pva_cmd_get_version get_version_cmd = { 0 };
uint32_t version_buffer_size = PVA_VERSION_BUFFER_SIZE; uint32_t version_buffer_size = PVA_VERSION_BUFFER_SIZE;
if (version_buffer == NULL || buffer_size <= 1) { if (version_buffer == NULL || buffer_size <= 1U) {
return PVA_INVAL; return PVA_INVAL;
} }
@@ -444,14 +482,14 @@ enum pva_error pva_kmd_query_fw_version(struct pva_kmd_device *pva,
} }
/* Clear the buffer */ /* Clear the buffer */
memset(device_memory->va, 0, version_buffer_size); (void)memset(device_memory->va, 0, version_buffer_size);
/* Set up the command */ /* Set up the command */
pva_kmd_set_cmd_get_version(&get_version_cmd, device_memory->iova); pva_kmd_set_cmd_get_version(&get_version_cmd, device_memory->iova);
/* Submit the command synchronously */ /* Submit the command synchronously */
err = pva_kmd_submit_cmd_sync(&pva->submitter, &get_version_cmd, err = pva_kmd_submit_cmd_sync(&pva->submitter, &get_version_cmd,
sizeof(get_version_cmd), (uint32_t)sizeof(get_version_cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -460,8 +498,8 @@ enum pva_error pva_kmd_query_fw_version(struct pva_kmd_device *pva,
} }
(void)memcpy(version_buffer, (char *)device_memory->va, (void)memcpy(version_buffer, (char *)device_memory->va,
(buffer_size - 1)); (size_t)buffer_size - 1U);
version_buffer[buffer_size - 1] = '\0'; /* Ensure null termination */ version_buffer[buffer_size - 1U] = '\0'; /* Ensure null termination */
free_memory: free_memory:
pva_kmd_device_memory_free(device_memory); pva_kmd_device_memory_free(device_memory);

View File

@@ -14,193 +14,771 @@
#include "pva_kmd_submitter.h" #include "pva_kmd_submitter.h"
#include "pva_kmd_regs.h" #include "pva_kmd_regs.h"
#include "pva_kmd_thread_sema.h" #include "pva_kmd_thread_sema.h"
#include "pva_kmd_fw_debug.h"
#include "pva_kmd_shim_init.h" #include "pva_kmd_shim_init.h"
#include "pva_kmd_shim_ccq.h" #include "pva_kmd_shim_ccq.h"
#include "pva_kmd_fw_profiler.h" #include "pva_kmd_fw_profiler.h"
#include "pva_kmd_fw_debug.h" #include "pva_kmd_fw_debug_printf.h"
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_kmd_debugfs.h" #include "pva_kmd_debugfs.h"
#include "pva_kmd_co.h" #include "pva_kmd_co.h"
/**
* @brief Class ID for PVA device 0
*
* @details This macro defines the unique class identifier used to identify
* the first PVA device (PVA0) in the system. The class ID is used by various
* hardware and software components to distinguish between different PVA
* instances and route operations to the correct device.
*/
#define NV_PVA0_CLASS_ID 0xF1 #define NV_PVA0_CLASS_ID 0xF1
/**
* @brief Class ID for PVA device 1
*
* @details This macro defines the unique class identifier used to identify
* the second PVA device (PVA1) in the system. The class ID is used by various
* hardware and software components to distinguish between different PVA
* instances and route operations to the correct device.
*/
#define NV_PVA1_CLASS_ID 0xF2 #define NV_PVA1_CLASS_ID 0xF2
/**
* @brief Structure for syncpoint read/write information
*
* @details This structure contains information needed to access a specific
* syncpoint for read and write operations. It includes both the syncpoint
* identifier and its corresponding IOVA address for hardware access.
*/
struct pva_syncpt_rw_info { struct pva_syncpt_rw_info {
/**
* @brief Syncpoint identifier
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t syncpt_id; uint32_t syncpt_id;
/**
* @brief IOVA address of the syncpoint for hardware access
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t syncpt_iova; uint64_t syncpt_iova;
}; };
/** A struct to maintain start and end address of vmem region */ /**
* @brief Structure to maintain start and end address of vmem region
*
* @details This structure defines a contiguous region of vector memory (VMEM)
* by specifying its start and end addresses. VMEM is the fast on-chip memory
* used by the VPU for storing data being actively processed.
*/
struct vmem_region { struct vmem_region {
/**! Start address of vmem region */ /**
* @brief Start address of vmem region
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t start; uint32_t start;
/**! End address of vmem region */
/**
* @brief End address of vmem region
* Valid range: [start .. UINT32_MAX]
*/
uint32_t end; uint32_t end;
}; };
/**
* @brief Structure containing hardware-specific constants for PVA
*
* @details This structure holds various hardware configuration parameters
* that are specific to different PVA hardware generations. These constants
* are used throughout the KMD to adapt behavior based on the underlying
* hardware capabilities and limitations.
*/
struct pva_kmd_hw_constants { struct pva_kmd_hw_constants {
/**
* @brief PVA hardware generation identifier
* Valid values: @ref pva_hw_gen enumeration values
*/
enum pva_hw_gen hw_gen; enum pva_hw_gen hw_gen;
/**
* @brief Number of VMEM regions available
* Valid range: [0 .. UINT8_MAX]
*/
uint8_t n_vmem_regions; uint8_t n_vmem_regions;
/**
* @brief Number of DMA descriptors available
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_dma_descriptors; uint32_t n_dma_descriptors;
/**
* @brief Number of user-accessible DMA channels
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_user_dma_channels; uint32_t n_user_dma_channels;
/**
* @brief Number of hardware sequencer words
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_hwseq_words; uint32_t n_hwseq_words;
/**
* @brief Number of dynamic ADB buffers
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_dynamic_adb_buffs; uint32_t n_dynamic_adb_buffs;
/**
* @brief Number of SMMU contexts available
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_smmu_contexts; uint32_t n_smmu_contexts;
}; };
struct pva_kmd_pfsd_info {
const uint8_t *vpu_elf_data;
uint32_t vpu_elf_size;
const uint8_t *ppe_elf_data;
uint32_t ppe_elf_size;
struct pva_dma_config pfsd_dma_cfg;
enum pva_error (*register_cmd_buffer)(struct pva_kmd_context *ctx);
};
/** /**
* @brief This struct manages a single PVA cluster. * @brief This struct manages a single PVA cluster.
* *
* Fields in this struct should be common across all platforms. Platform * @details Fields in this struct should be common across all platforms. Platform
* specific data is stored in plat_data field. * specific data is stored in plat_data field. This structure represents the
* complete state of a PVA device instance and contains all the resources,
* configuration, and runtime state needed to manage the device.
*/ */
struct pva_kmd_device { struct pva_kmd_device {
/**
* @brief Device index identifying this PVA instance
* Valid range: [0 .. PVA_MAX_DEVICES-1]
*/
uint32_t device_index; uint32_t device_index;
/**
* @brief SMMU context ID for R5 firmware image
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t r5_image_smmu_context_id; uint32_t r5_image_smmu_context_id;
/**
* @brief Array of stream IDs for SMMU contexts
* Valid range: Each element [0 .. UINT32_MAX]
*/
uint32_t stream_ids[PVA_MAX_NUM_SMMU_CONTEXTS]; uint32_t stream_ids[PVA_MAX_NUM_SMMU_CONTEXTS];
/**
* @brief Hardware constants specific to this PVA instance
*/
struct pva_kmd_hw_constants hw_consts; struct pva_kmd_hw_constants hw_consts;
/**
* @brief Physical base addresses for device register apertures
* Valid range: Each element [0 .. UINT64_MAX]
*/
uint64_t reg_phy_base[PVA_KMD_APERTURE_COUNT]; uint64_t reg_phy_base[PVA_KMD_APERTURE_COUNT];
/**
* @brief Sizes of device register apertures
* Valid range: Each element [0 .. UINT64_MAX]
*/
uint64_t reg_size[PVA_KMD_APERTURE_COUNT]; uint64_t reg_size[PVA_KMD_APERTURE_COUNT];
/**
* @brief Register specification structure for device access
*/
struct pva_kmd_regspec regspec; struct pva_kmd_regspec regspec;
/**
* @brief Maximum number of contexts supported by this device
* Valid range: [0 .. PVA_MAX_NUM_USER_CONTEXTS]
*/
uint8_t max_n_contexts; uint8_t max_n_contexts;
/**
* @brief Pointer to allocated memory for context storage
* Valid value: non-null when contexts are allocated
*/
void *context_mem; void *context_mem;
/**
* @brief Block allocator for managing context allocation
*/
struct pva_kmd_block_allocator context_allocator; struct pva_kmd_block_allocator context_allocator;
/**
* @brief Device-level resource table for privileged operations
*/
struct pva_kmd_resource_table dev_resource_table; struct pva_kmd_resource_table dev_resource_table;
/**
* @brief Command submission handler for device-level operations
*/
struct pva_kmd_submitter submitter; struct pva_kmd_submitter submitter;
/** The lock protects the submission to the queue, including
* incrementing the post fence */ /**
* @brief Lock protecting submission operations and post fence increment
*
* @details The lock protects the submission to the queue, including
* incrementing the post fence
*/
pva_kmd_mutex_t submit_lock; pva_kmd_mutex_t submit_lock;
/**
* @brief Device memory allocation for queue operations
*/
struct pva_kmd_device_memory *queue_memory; struct pva_kmd_device_memory *queue_memory;
/**
* @brief Device-level command queue
*/
struct pva_kmd_queue dev_queue; struct pva_kmd_queue dev_queue;
/** memory needed for submission: including command buffer chunks and fences */ /**
* @brief Memory allocation for submission operations
*
* @details Memory needed for submission: including command buffer chunks and fences
*/
struct pva_kmd_device_memory *submit_memory; struct pva_kmd_device_memory *submit_memory;
uint32_t submit_memory_resource_id;
uint64_t fence_offset; /**< fence offset within submit_memory*/
/**
* @brief Resource ID for submission memory in resource table
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t submit_memory_resource_id;
/**
* @brief Offset of fence within submission memory
* Valid range: [0 .. submit_memory_size-1]
*/
uint64_t fence_offset;
/**
* @brief Lock protecting command buffer chunk pool operations
*/
pva_kmd_mutex_t chunk_pool_lock; pva_kmd_mutex_t chunk_pool_lock;
/**
* @brief Pool of command buffer chunks for efficient allocation
*/
struct pva_kmd_cmdbuf_chunk_pool chunk_pool; struct pva_kmd_cmdbuf_chunk_pool chunk_pool;
/**
* @brief Lock protecting power cycle operations
*/
pva_kmd_mutex_t powercycle_lock; pva_kmd_mutex_t powercycle_lock;
/**
* @brief Reference count for device usage tracking
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t refcount; uint32_t refcount;
/** ISR post this semaphore when FW completes boot */ /**
* @brief Semaphore posted by ISR when FW completes boot
*
* @details ISR post this semaphore when FW completes boot
*/
pva_kmd_sema_t fw_boot_sema; pva_kmd_sema_t fw_boot_sema;
bool recovery;
/**
* @brief Flag indicating if device is in recovery mode
* Valid values: true, false
*/
bool recovery;
/** Firmware is aborted and won't respond */
bool fw_aborted;
/**
* @brief Device memory allocation for firmware debug information
*/
struct pva_kmd_device_memory *fw_debug_mem; struct pva_kmd_device_memory *fw_debug_mem;
/**
* @brief Device memory allocation for firmware binary
*/
struct pva_kmd_device_memory *fw_bin_mem; struct pva_kmd_device_memory *fw_bin_mem;
// 'kmd_fw_buffers' holds DRAM buffers shared between KMD and FW /**
// - Today, we have 1 buffer per CCQ. This may need to be extended in future * @brief DRAM buffers shared between KMD and FW
// to support buffered communication through mailbox *
// - Buffers will be used for the following purposes * @details 'kmd_fw_buffers' holds DRAM buffers shared between KMD and FW
// - CCQ 0: Communications common to a VM * - Today, we have 1 buffer per CCQ. This may need to be extended in future
// -- example, FW profiling data and NSIGHT data * to support buffered communication through mailbox
// - CCQ 1-8: Communications specific to each context * - Buffers will be used for the following purposes
// -- example, resource unregistration requests * - CCQ 0: Communications common to a VM
// In the future, we may want to extend this to support communications between * -- example, FW profiling data and NSIGHT data
// FW and Hypervisor * - CCQ 1-8: Communications specific to each context
* -- example, resource unregistration requests
* In the future, we may want to extend this to support communications between
* FW and Hypervisor
*/
struct pva_kmd_shared_buffer kmd_fw_buffers[PVA_MAX_NUM_CCQ]; struct pva_kmd_shared_buffer kmd_fw_buffers[PVA_MAX_NUM_CCQ];
/**
* @brief Current firmware trace level setting
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t fw_trace_level; uint32_t fw_trace_level;
/**
* @brief Buffer for firmware print/debug output
*/
struct pva_kmd_fw_print_buffer fw_print_buffer; struct pva_kmd_fw_print_buffer fw_print_buffer;
/**
* @brief Device memory allocation for Tegra statistics collection
*/
struct pva_kmd_device_memory *tegra_stats_memory; struct pva_kmd_device_memory *tegra_stats_memory;
/**
* @brief Resource ID for Tegra statistics memory
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t tegra_stats_resource_id; uint32_t tegra_stats_resource_id;
/**
* @brief Size of Tegra statistics buffer
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t tegra_stats_buf_size; uint32_t tegra_stats_buf_size;
/**
* @brief Flag indicating if firmware should be loaded from GSC
* Valid values: true, false
*/
bool load_from_gsc; bool load_from_gsc;
/**
* @brief Flag indicating if device is running in hypervisor mode
* Valid values: true, false
*/
bool is_hv_mode; bool is_hv_mode;
/**
* @brief Flag indicating if device is running on silicon hardware
* Valid values: true, false
*/
bool is_silicon; bool is_silicon;
/**
* @brief Debug filesystem context for development and debugging
*/
struct pva_kmd_debugfs_context debugfs_context; struct pva_kmd_debugfs_context debugfs_context;
/** Sector packing format for block linear surfaces */
/**
* @brief Sector packing format for block linear surfaces
* Valid range: [0 .. UINT8_MAX]
*/
uint8_t bl_sector_pack_format; uint8_t bl_sector_pack_format;
/** Offset between 2 syncpoints */ /**
* @brief Size offset between consecutive syncpoints
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t syncpt_page_size; uint32_t syncpt_page_size;
/**
* @brief Base IOVA for read-only syncpoints
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t ro_syncpt_base_iova; uint64_t ro_syncpt_base_iova;
/**
* @brief Number of read-only syncpoints available
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t num_ro_syncpts; uint32_t num_ro_syncpts;
/**
* @brief Base IOVA for read-write syncpoints
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t rw_syncpt_base_iova; uint64_t rw_syncpt_base_iova;
/**
* @brief Size of read-write syncpoint region
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t rw_syncpt_region_size; uint32_t rw_syncpt_region_size;
/**
* @brief Array of read-write syncpoint information
*/
struct pva_syncpt_rw_info rw_syncpts[PVA_NUM_RW_SYNCPTS]; struct pva_syncpt_rw_info rw_syncpts[PVA_NUM_RW_SYNCPTS];
/**
* @brief Pointer to table of VMEM region definitions
*/
struct vmem_region *vmem_regions_tab; struct vmem_region *vmem_regions_tab;
/**
* @brief Flag indicating support for hardware sequencer frame linking
* Valid values: true, false
*/
bool support_hwseq_frame_linking; bool support_hwseq_frame_linking;
/**
* @brief Platform-specific private data pointer
*/
void *plat_data; void *plat_data;
/**
* @brief Pointer to VPU authentication context
*/
struct pva_vpu_auth *pva_auth; struct pva_vpu_auth *pva_auth;
/**
* @brief Flag indicating if firmware has been initialized
* Valid values: true, false
*/
bool fw_inited; bool fw_inited;
/** Carveout info for FW */ /**
* @brief Carveout memory information for firmware
*/
struct pva_co_info fw_carveout; struct pva_co_info fw_carveout;
/**
* @brief Flag indicating if device is in test mode
* Valid values: true, false
*/
bool test_mode; bool test_mode;
/**
* @brief Atomic counter for deferred context free operations
*/
pva_kmd_atomic_t n_deferred_context_free; pva_kmd_atomic_t n_deferred_context_free;
uint32_t deferred_context_free_ids[PVA_MAX_NUM_USER_CONTEXTS];
uint64_t tsc_to_ns_multiplier; /**< TSC to nanoseconds multiplier */ /**
* @brief Array of context IDs pending deferred free
*/
uint8_t deferred_context_free_ids[PVA_MAX_NUM_USER_CONTEXTS];
/**
* @brief Multiplier to convert TSC ticks to nanoseconds
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t tsc_to_ns_multiplier;
/**
* @brief PFSD information
*/
struct pva_kmd_pfsd_info pfsd_info;
#if PVA_ENABLE_R5_OCD == 1
/**
* @brief Flag indicating if R5 on-chip debugging is enabled
* Valid values: true, false
*/
bool r5_ocd_on; bool r5_ocd_on;
#endif
}; };
/**
* @brief Create and initialize a new PVA KMD device instance
*
* @details This function performs the following operations:
* - Allocates memory for a new @ref pva_kmd_device structure
* - Initializes the device based on the specified chip ID and configuration
* - Sets up hardware constants and register mappings for the device
* - Configures authentication settings based on the app_authenticate parameter
* - Initializes internal data structures including resource tables, queues,
* and memory allocators
* - Sets up platform-specific components using @ref pva_kmd_device_plat_init()
* - Configures test mode settings if requested
* - Prepares the device for firmware loading and initialization
*
* The created device must be destroyed using @ref pva_kmd_device_destroy()
* when no longer needed to prevent resource leaks. The device will be in
* an uninitialized state until @ref pva_kmd_init_fw() is called.
*
* @param[in] chip_id Chip identifier specifying the target hardware
* Valid values: @ref pva_chip_id enumeration values
* @param[in] device_index Index of the PVA device instance to create
* Valid range: [0 .. PVA_MAX_DEVICES-1]
* @param[in] app_authenticate Flag to enable application authentication
* Valid values: true, false
* @param[in] test_mode Flag to enable test mode configuration
* Valid values: true, false
*
* @retval non-null Pointer to successfully created @ref pva_kmd_device
* @retval NULL Device creation failed due to memory allocation failure,
* invalid parameters, or platform initialization failure
*/
struct pva_kmd_device *pva_kmd_device_create(enum pva_chip_id chip_id, struct pva_kmd_device *pva_kmd_device_create(enum pva_chip_id chip_id,
uint32_t device_index, uint32_t device_index,
bool app_authenticate, bool app_authenticate,
bool test_mode); bool test_mode, void *plat_data);
/**
* @brief Destroy a PVA KMD device instance and free all resources
*
* @details This function performs the following operations:
* - Deinitializes the firmware using @ref pva_kmd_deinit_fw() if initialized
* - Stops and cleans up all active contexts and their associated resources
* - Frees all allocated device memory including command buffers, queues,
* and shared buffers
* - Releases hardware resources and register mappings
* - Cleans up platform-specific resources through platform callbacks
* - Destroys synchronization primitives including mutexes and semaphores
* - Frees the device structure itself
*
* After calling this function, the device pointer becomes invalid and must
* not be used. Any ongoing operations on the device should be completed
* or cancelled before calling this function.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure to destroy
* Valid value: non-null, must be a valid device created by
* @ref pva_kmd_device_create()
*/
void pva_kmd_device_destroy(struct pva_kmd_device *pva); void pva_kmd_device_destroy(struct pva_kmd_device *pva);
/**
* @brief Add a context ID to the deferred free list
*
* @details This function performs the following operations:
* - Atomically increments the count of deferred context free operations
* - Adds the specified CCQ ID to the deferred context free array
* - Ensures thread-safe access to the deferred free list
* - Marks the context for cleanup during the next power cycle
*
* This function is used when a context cannot be freed immediately,
* typically because the firmware is still processing commands for that
* context. The context will be freed when the device is next powered off
* and reinitialized.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] ccq_id CCQ ID of the context to defer free
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
*/
void pva_kmd_add_deferred_context_free(struct pva_kmd_device *pva, void pva_kmd_add_deferred_context_free(struct pva_kmd_device *pva,
uint8_t ccq_id); uint8_t ccq_id);
/**
* @brief Initialize firmware on the PVA device
*
* @details This function performs the following operations:
* - Loads the firmware binary into device memory using platform-specific loaders
* - Sets up firmware execution environment including memory mappings
* - Initializes communication channels between KMD and firmware
* - Configures hardware resources needed by the firmware
* - Starts the firmware execution and waits for boot completion
* - Sets up shared buffers for KMD-FW communication
* - Initializes firmware debug and profiling capabilities
* - Establishes resource tables for hardware resource management
*
* The device must be created using @ref pva_kmd_device_create() before
* calling this function. After successful initialization, the device is
* ready to accept and process user commands.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
*
* @retval PVA_SUCCESS Firmware initialized successfully
* @retval PVA_TIMEDOUT Firmware boot timeout occurred
* @retval PVA_NOMEM Memory allocation for FW resources failed
* @retval PVA_ERR_FW_ABORTED Firmware operation aborted during recovery
*/
enum pva_error pva_kmd_init_fw(struct pva_kmd_device *pva); enum pva_error pva_kmd_init_fw(struct pva_kmd_device *pva);
/**
* @brief Deinitialize firmware and clean up resources
*
* @details This function performs the following operations:
* - Stops firmware execution and waits for graceful shutdown
* - Frees all firmware-related memory allocations
* - Cleans up communication channels and shared buffers
* - Releases hardware resources allocated to firmware
* - Deinitializes debug and profiling subsystems
* - Resets device hardware to a known state
* - Marks the device as uninitialized for future use
*
* After calling this function, the device can be reinitialized using
* @ref pva_kmd_init_fw() or destroyed using @ref pva_kmd_device_destroy().
* Any ongoing operations should be completed before calling this function.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
*
* @retval PVA_SUCCESS Firmware deinitialized successfully
* @retval PVA_INTERNAL Failed to properly deinitialize firmware
* @retval PVA_TIMEDOUT Firmware shutdown timeout occurred
*/
enum pva_error pva_kmd_deinit_fw(struct pva_kmd_device *pva); enum pva_error pva_kmd_deinit_fw(struct pva_kmd_device *pva);
/**
* @brief Check if the PVA device might be powered on
*
* @details This function performs the following operations:
* - Checks device power state indicators to determine if device is active
* - Reads hardware registers to verify device accessibility
* - Uses platform-specific power management information if available
* - Returns a best-effort assessment of device power state
* - Does not guarantee definitive power state due to timing considerations
*
* This function provides a quick check for device availability without
* performing operations that might cause side effects. The result should
* be treated as a hint rather than a definitive power state.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
*
* @retval true Device appears to be powered on and accessible
* @retval false Device appears to be powered off or inaccessible
*/
bool pva_kmd_device_maybe_on(struct pva_kmd_device *pva); bool pva_kmd_device_maybe_on(struct pva_kmd_device *pva);
/**
* @brief Query the firmware version string from the device
*
* @details This function performs the following operations:
* - Sends a version query command to the firmware
* - Waits for the firmware response containing version information
* - Copies the version string to the provided buffer
* - Ensures null-termination of the version string
* - Handles buffer size limitations gracefully
* - Returns error if firmware is not responsive or accessible
*
* The version information includes firmware build details, version numbers,
* and other identification data useful for debugging and compatibility
* checking. The device must be initialized before calling this function.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[out] version_buffer Buffer to store the firmware version string
* Valid value: non-null
* @param[in] buffer_size Size of the version buffer in bytes
* Valid range: [1 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Version retrieved successfully
* @retval PVA_INVAL Invalid buffer pointer or buffer size <= 1
* @retval PVA_NOMEM Failed to allocate device memory for version query
* @retval PVA_TIMEDOUT Firmware did not respond within timeout
* @retval PVA_ERR_FW_ABORTED Firmware operation aborted during recovery
*/
enum pva_error pva_kmd_query_fw_version(struct pva_kmd_device *pva, enum pva_error pva_kmd_query_fw_version(struct pva_kmd_device *pva,
char *version_buffer, char *version_buffer,
uint32_t buffer_size); uint32_t buffer_size);
/**
* @brief Get the device class ID for the specified PVA device
*
* @details This function performs the following operations:
* - Examines the device index to determine which PVA instance this represents
* - Returns the appropriate class ID for device identification
* - Maps device index 0 to @ref NV_PVA0_CLASS_ID
* - Maps device index 1 to @ref NV_PVA1_CLASS_ID
* - Provides consistent class ID mapping for hardware identification
*
* The class ID is used by various hardware and software components to
* route operations to the correct PVA device instance in multi-device
* systems.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
*
* @retval NV_PVA0_CLASS_ID If device index is 0
* @retval NV_PVA1_CLASS_ID If device index is 1 or any other value
*/
static inline uint32_t pva_kmd_get_device_class_id(struct pva_kmd_device *pva) static inline uint32_t pva_kmd_get_device_class_id(struct pva_kmd_device *pva)
{ {
if (pva->device_index == 0) { if (pva->device_index == 0U) {
return NV_PVA0_CLASS_ID; return NV_PVA0_CLASS_ID;
} else { } else {
return NV_PVA1_CLASS_ID; return NV_PVA1_CLASS_ID;
} }
} }
/**
* @brief Get the maximum command buffer chunk size for the device
*
* @details This function performs the following operations:
* - Checks if the device is configured for test mode operation
* - Returns @ref PVA_TEST_MODE_MAX_CMDBUF_CHUNK_SIZE for test mode
* - Returns @ref PVA_MAX_CMDBUF_CHUNK_SIZE for normal operation
* - Provides appropriate chunk size limits based on device configuration
*
* The chunk size determines the maximum size of individual command buffer
* segments that can be processed by the firmware. Test mode may use smaller
* chunks for validation and debugging purposes.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
*
* @retval PVA_TEST_MODE_MAX_CMDBUF_CHUNK_SIZE If device is in test mode
* @retval PVA_MAX_CMDBUF_CHUNK_SIZE If device is in normal mode
*/
static inline uint16_t static inline uint16_t
pva_kmd_get_max_cmdbuf_chunk_size(struct pva_kmd_device *pva) pva_kmd_get_max_cmdbuf_chunk_size(struct pva_kmd_device *pva)
{ {
/* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
uint16_t max_chunk_size = (uint16_t)PVA_MAX_CMDBUF_CHUNK_SIZE;
#if SYSTEM_TESTS_ENABLED == 1
if (pva->test_mode) { if (pva->test_mode) {
return PVA_TEST_MODE_MAX_CMDBUF_CHUNK_SIZE; max_chunk_size = (uint16_t)PVA_TEST_MODE_MAX_CMDBUF_CHUNK_SIZE;
} else {
return PVA_MAX_CMDBUF_CHUNK_SIZE;
} }
#endif
return max_chunk_size;
} }
/**
* @brief Convert TSC (Time Stamp Counter) value to nanoseconds
*
* @details This function performs the following operations:
* - Multiplies the TSC value by the device-specific conversion multiplier
* - Uses @ref safe_mulu64() to prevent overflow during multiplication
* - Returns the equivalent time value in nanoseconds
* - Provides high-precision timing conversion for performance measurement
*
* The TSC is a hardware counter that increments at a fixed frequency.
* The conversion multiplier is calibrated based on the device's clock
* configuration to provide accurate nanosecond timing.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] tsc TSC value to convert
* Valid range: [0 .. UINT64_MAX]
*
* @retval converted_time TSC value converted to nanoseconds
*/
static inline uint64_t pva_kmd_tsc_to_ns(struct pva_kmd_device *pva, static inline uint64_t pva_kmd_tsc_to_ns(struct pva_kmd_device *pva,
uint64_t tsc) uint64_t tsc)
{ {
// Convert TSC to nanoseconds using the multiplier // Convert TSC to nanoseconds using the multiplier
return safe_mulu64(tsc, pva->tsc_to_ns_multiplier); return safe_mulu64(tsc, pva->tsc_to_ns_multiplier);
} }
/**
* @brief Convert TSC (Time Stamp Counter) value to microseconds
*
* @details This function performs the following operations:
* - Converts the TSC value to nanoseconds using @ref safe_mulu64()
* - Divides the nanosecond result by 1000 to get microseconds
* - Returns the equivalent time value in microseconds
* - Provides medium-precision timing conversion for performance measurement
*
* The TSC is a hardware counter that increments at a fixed frequency.
* This function combines nanosecond conversion with division to provide
* microsecond precision timing suitable for most timing measurements.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] tsc TSC value to convert
* Valid range: [0 .. UINT64_MAX]
*
* @retval converted_time TSC value converted to microseconds
*/
static inline uint64_t pva_kmd_tsc_to_us(struct pva_kmd_device *pva, static inline uint64_t pva_kmd_tsc_to_us(struct pva_kmd_device *pva,
uint64_t tsc) uint64_t tsc)
{ {
// Convert TSC to microseconds using the multiplier // Convert TSC to microseconds using the multiplier
return safe_mulu64(tsc, pva->tsc_to_ns_multiplier) / 1000; return safe_mulu64(tsc, pva->tsc_to_ns_multiplier) / 1000U;
} }
#endif // PVA_KMD_DEVICE_H #endif // PVA_KMD_DEVICE_H

View File

@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_devmem_pool.h" #include "pva_kmd_devmem_pool.h"
#include "pva_kmd_limits.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_kmd_limits.h"
#include "pva_api.h" #include "pva_api.h"
#include "pva_utils.h" #include "pva_utils.h"
@@ -86,10 +88,11 @@ enum pva_error pva_kmd_devmem_pool_init(struct pva_kmd_devmem_pool *pool,
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
/* Initialize the pool structure */ /* Initialize the pool structure */
memset(pool, 0, sizeof(*pool)); (void)memset(pool, 0, sizeof(*pool));
pool->smmu_ctx_idx = smmu_ctx_idx; pool->smmu_ctx_idx = smmu_ctx_idx;
pool->element_size = /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
safe_pow2_roundup_u32(element_size, sizeof(uint64_t)); pool->element_size = (uint32_t)safe_pow2_roundup_u32(
element_size, (uint32_t)sizeof(uint64_t));
pool->n_element_incr = ele_incr_count; pool->n_element_incr = ele_incr_count;
pool->n_free_element = 0; pool->n_free_element = 0;
pool->segment_list_head = NULL; pool->segment_list_head = NULL;
@@ -121,13 +124,14 @@ pva_kmd_devmem_pool_alloc(struct pva_kmd_devmem_pool *pool,
{ {
struct pva_kmd_devmem_pool_segment *segment = NULL; struct pva_kmd_devmem_pool_segment *segment = NULL;
struct pva_kmd_devmem_pool_segment *new_segment = NULL; struct pva_kmd_devmem_pool_segment *new_segment = NULL;
uint32_t ele_idx = (uint32_t)-1; /* Use U32_MAX instead of casting -1 */
uint32_t ele_idx = U32_MAX;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
pva_kmd_mutex_lock(&pool->pool_lock); pva_kmd_mutex_lock(&pool->pool_lock);
/* Check if we have any free elements */ /* Check if we have any free elements */
if (pool->n_free_element == 0) { if (pool->n_free_element == 0U) {
/* Need to allocate a new segment */ /* Need to allocate a new segment */
new_segment = allocate_segment(pool); new_segment = allocate_segment(pool);
if (new_segment == NULL) { if (new_segment == NULL) {
@@ -169,7 +173,7 @@ enum pva_error pva_kmd_devmem_pool_zalloc(struct pva_kmd_devmem_pool *pool,
return err; return err;
} }
memset(pva_kmd_get_devmem_va(devmem), 0, pool->element_size); (void)memset(pva_kmd_get_devmem_va(devmem), 0, pool->element_size);
return PVA_SUCCESS; return PVA_SUCCESS;
} }
@@ -216,12 +220,14 @@ void pva_kmd_devmem_pool_free(struct pva_kmd_devmem_element *devmem)
struct pva_kmd_devmem_pool *pool = devmem->segment->owner_pool; struct pva_kmd_devmem_pool *pool = devmem->segment->owner_pool;
struct pva_kmd_devmem_pool_segment *current_segment = devmem->segment; struct pva_kmd_devmem_pool_segment *current_segment = devmem->segment;
uint32_t threshold; uint32_t threshold;
enum pva_error tmp_err;
pva_kmd_mutex_lock(&pool->pool_lock); pva_kmd_mutex_lock(&pool->pool_lock);
/* Free the element */ /* Free the element */
pva_kmd_free_block_unsafe(&current_segment->elem_allocator, tmp_err = pva_kmd_free_block_unsafe(&current_segment->elem_allocator,
devmem->ele_idx); devmem->ele_idx);
ASSERT(tmp_err == PVA_SUCCESS);
pool->n_free_element = safe_addu32(pool->n_free_element, 1); pool->n_free_element = safe_addu32(pool->n_free_element, 1);
current_segment->n_free_ele = current_segment->n_free_ele =
safe_addu32(current_segment->n_free_ele, 1); safe_addu32(current_segment->n_free_ele, 1);

View File

@@ -6,79 +6,189 @@
#include "pva_kmd_block_allocator.h" #include "pva_kmd_block_allocator.h"
#include "pva_kmd_device_memory.h" #include "pva_kmd_device_memory.h"
/** @brief A segment of a device memory pool. /**
* @brief A segment of a device memory pool
* *
* It holds a fixed size array of device memory blocks. A pool is a linked list * @details A segment holds a fixed size array of device memory blocks within
* of segments. * a device memory pool. The pool is implemented as a linked list of segments,
* allowing dynamic expansion of the pool capacity as needed. Each segment
* manages its own allocation state and provides efficient block allocation
* and deallocation within the segment.
*/ */
struct pva_kmd_devmem_pool_segment { struct pva_kmd_devmem_pool_segment {
/** The owner pool. */ /**
* @brief Pointer to the owner pool
*/
struct pva_kmd_devmem_pool *owner_pool; struct pva_kmd_devmem_pool *owner_pool;
/** The next segment in the pool. */
/**
* @brief Pointer to the next segment in the pool linked list
*/
struct pva_kmd_devmem_pool_segment *next; struct pva_kmd_devmem_pool_segment *next;
/** The device memory for the segment. */
/**
* @brief Device memory allocation for this segment
*/
struct pva_kmd_device_memory *mem; struct pva_kmd_device_memory *mem;
/** The allocator for the elements in the segment. */
/**
* @brief Block allocator for managing elements within this segment
*/
struct pva_kmd_block_allocator elem_allocator; struct pva_kmd_block_allocator elem_allocator;
/** The number of free elements in the segment. */
/**
* @brief Number of free elements currently available in this segment
* Valid range: [0 .. n_element_incr]
*/
uint32_t n_free_ele; uint32_t n_free_ele;
}; };
/** @brief A device memory pool that holds fixed size elements. /**
* @brief A device memory pool that manages fixed-size elements
* *
* It allocates memory in segments, each segment contains n_element_incr * @details A device memory pool that holds fixed size elements with automatic
* elements. * capacity expansion. The pool allocates memory in segments, each segment
* - element_size will be rounded up to the nearest 8 bytes for alignment. * containing n_element_incr elements. Key features include:
* - The pool is initialized with element_size * n_element_incr capacity. * - element_size is rounded up to nearest 8 bytes for alignment
* - Once exhausted, the pool will allocate a new segment of memory and increase * - Pool initialized with element_size * n_element_incr capacity
* the capacity by n_element_incr. * - Automatic segment allocation when pool exhausted
* - When an element is freed, the pool does not immediately release the whole * - Intelligent segment deallocation to maintain efficiency
* segment even if the whole segment is empty. However, if there are 2 * * - Thread-safe operations with mutex protection
* n_element_incr free elements, the pool will release a whole segment, so * - SMMU context-aware memory allocation
* that there's still at least n_element_incr free elements.
* - The pool is thread safe.
*/ */
struct pva_kmd_devmem_pool { struct pva_kmd_devmem_pool {
/** The SMMU context index for the pool. */ /**
* @brief SMMU context index for memory allocation
* Valid range: [0 .. PVA_MAX_NUM_SMMU_CONTEXTS-1]
*/
uint8_t smmu_ctx_idx; uint8_t smmu_ctx_idx;
/** The size of each element in the pool. */
/**
* @brief Size of each element in the pool in bytes
* Valid range: [1 .. UINT32_MAX], rounded up to 8-byte alignment
*/
uint32_t element_size; uint32_t element_size;
/** The number of elements to allocate in each segment. */
/**
* @brief Number of elements to allocate in each segment
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t n_element_incr; uint32_t n_element_incr;
/** The total number of free elements in the pool, across all segments. */
/**
* @brief Total number of free elements across all segments
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_free_element; uint32_t n_free_element;
/** The head of the segment list. */
/**
* @brief Head of the segment linked list
*/
struct pva_kmd_devmem_pool_segment *segment_list_head; struct pva_kmd_devmem_pool_segment *segment_list_head;
/** The PVA device. */
/**
* @brief Pointer to the PVA device
*/
struct pva_kmd_device *pva; struct pva_kmd_device *pva;
/** The mutex for the pool. */
/**
* @brief Mutex for thread-safe pool operations
*/
pva_kmd_mutex_t pool_lock; pva_kmd_mutex_t pool_lock;
}; };
/** @brief Device memory from a pool. /**
* @brief Device memory element from a pool
* *
* It is an element in a segment of a pool. * @details Represents a single element allocated from a device memory pool.
* The element is contained within a specific segment of the pool and can
* be used to access the allocated memory through IOVA addresses or virtual
* addresses as needed by the application.
*/ */
struct pva_kmd_devmem_element { struct pva_kmd_devmem_element {
/** The segment that contains the element. */ /**
* @brief Pointer to the segment containing this element
*/
struct pva_kmd_devmem_pool_segment *segment; struct pva_kmd_devmem_pool_segment *segment;
/** The index of the element in the segment. */
/**
* @brief Index of this element within the segment
* Valid range: [0 .. n_element_incr-1]
*/
uint32_t ele_idx; uint32_t ele_idx;
}; };
/** @brief Get the IOVA of a device memory element. */ /**
* @brief Get the IOVA address of a device memory element
*
* @details This function performs the following operations:
* - Calculates the IOVA address for the specified device memory element
* - Uses the segment's device memory base address and element index
* - Accounts for element size and alignment requirements
* - Returns hardware-accessible address for DMA operations
* - Provides address suitable for programming hardware registers
*
* The returned IOVA can be used by hardware to access the element
* memory directly through the SMMU context associated with the pool.
*
* @param[in] devmem Pointer to @ref pva_kmd_devmem_element structure
* Valid value: non-null, must be allocated from pool
*
* @retval iova_address IOVA address of the device memory element
*/
uint64_t pva_kmd_get_devmem_iova(struct pva_kmd_devmem_element const *devmem); uint64_t pva_kmd_get_devmem_iova(struct pva_kmd_devmem_element const *devmem);
/** @brief Get the virtual address of a device memory element. */ /**
* @brief Get the virtual address of a device memory element
*
* @details This function performs the following operations:
* - Calculates the virtual address for the specified device memory element
* - Uses the segment's device memory base virtual address and element index
* - Accounts for element size and alignment requirements
* - Returns CPU-accessible virtual address for software operations
* - Provides address suitable for direct memory access by CPU
*
* The returned virtual address can be used by software to read and write
* the element memory directly using normal memory operations.
*
* @param[in] devmem Pointer to @ref pva_kmd_devmem_element structure
* Valid value: non-null, must be allocated from pool
*
* @retval virtual_address Virtual address pointer to the device memory element
*/
void *pva_kmd_get_devmem_va(struct pva_kmd_devmem_element const *devmem); void *pva_kmd_get_devmem_va(struct pva_kmd_devmem_element const *devmem);
/** @brief Initialize a device memory pool. /**
* @brief Initialize a device memory pool
* *
* @param pool The device memory pool to initialize. * @details This function performs the following operations:
* @param pva The PVA device. * - Initializes the device memory pool structure with specified parameters
* @param smmu_ctx_idx The SMMU context index for the pool. * - Rounds element_size up to 8-byte alignment for optimal access
* @param element_size The size of each element in the pool. * - Allocates initial segment with n_element_incr elements
* @param ele_incr_count The number of elements to allocate in each segment. * - Sets up SMMU context for memory allocation and mapping
* - Initializes mutex for thread-safe pool operations
* - Configures automatic segment management policies
* - Prepares pool for element allocation and deallocation
*
* The initialized pool is ready for element allocation using
* @ref pva_kmd_devmem_pool_zalloc() and will automatically expand
* capacity by adding new segments as needed.
*
* @param[out] pool Pointer to @ref pva_kmd_devmem_pool structure to initialize
* Valid value: non-null
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] smmu_ctx_idx SMMU context index for memory allocation
* Valid range: [0 .. PVA_MAX_NUM_SMMU_CONTEXTS-1]
* @param[in] element_size Size of each element in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[in] ele_incr_count Number of elements per segment
* Valid range: [1 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Pool initialized successfully
* @retval PVA_NOMEM Failed to allocate initial segment
* @retval PVA_INTERNAL Failed to initialize pool mutex
* @retval PVA_INVAL Failed to map memory to SMMU context
*/ */
enum pva_error pva_kmd_devmem_pool_init(struct pva_kmd_devmem_pool *pool, enum pva_error pva_kmd_devmem_pool_init(struct pva_kmd_devmem_pool *pool,
struct pva_kmd_device *pva, struct pva_kmd_device *pva,
@@ -86,15 +196,76 @@ enum pva_error pva_kmd_devmem_pool_init(struct pva_kmd_devmem_pool *pool,
uint32_t element_size, uint32_t element_size,
uint32_t ele_incr_count); uint32_t ele_incr_count);
/** @brief Allocate a device memory element from a pool and zero-initialize it. */ /**
* @brief Allocate and zero-initialize a device memory element from pool
*
* @details This function performs the following operations:
* - Searches for available element in existing segments
* - Allocates new segment if all existing segments are full
* - Assigns element from segment using block allocator
* - Zero-initializes the allocated element memory
* - Updates pool statistics and segment free counts
* - Returns element information for subsequent use
* - Ensures thread-safe allocation through mutex protection
*
* The allocated element is zero-initialized and ready for use. The
* element remains allocated until freed using @ref pva_kmd_devmem_pool_free().
*
* @param[in] pool Pointer to @ref pva_kmd_devmem_pool structure
* Valid value: non-null, must be initialized
* @param[out] devmem Pointer to @ref pva_kmd_devmem_element to populate
* Valid value: non-null
*
* @retval PVA_SUCCESS Element allocated successfully
* @retval PVA_NOMEM Failed to allocate new segment
* @retval PVA_ENOSPC Pool limits exceeded
* @retval PVA_INVAL Failed to map new segment memory
*/
enum pva_error enum pva_error
pva_kmd_devmem_pool_zalloc(struct pva_kmd_devmem_pool *pool, pva_kmd_devmem_pool_zalloc(struct pva_kmd_devmem_pool *pool,
struct pva_kmd_devmem_element *devmem); struct pva_kmd_devmem_element *devmem);
/** @brief Free a device memory element from a pool. */ /**
* @brief Free a device memory element back to its pool
*
* @details This function performs the following operations:
* - Validates the element belongs to a valid segment and pool
* - Returns the element to its segment's block allocator
* - Updates segment and pool free element counts
* - Checks for segment deallocation opportunities
* - Frees empty segments if pool has excess capacity
* - Maintains optimal pool memory usage
* - Ensures thread-safe deallocation through mutex protection
*
* The pool automatically manages segment deallocation to maintain
* efficiency while avoiding unnecessary memory fragmentation.
* Segments are freed when there are more than 2 * n_element_incr
* free elements, ensuring at least n_element_incr remain available.
*
* @param[in] devmem Pointer to @ref pva_kmd_devmem_element to free
* Valid value: non-null, must be allocated from pool
*/
void pva_kmd_devmem_pool_free(struct pva_kmd_devmem_element *devmem); void pva_kmd_devmem_pool_free(struct pva_kmd_devmem_element *devmem);
/** @brief Deinitialize a device memory pool. */ /**
* @brief Deinitialize a device memory pool and free all resources
*
* @details This function performs the following operations:
* - Ensures all elements have been freed back to the pool
* - Traverses segment linked list and frees all segments
* - Unmaps device memory from SMMU contexts
* - Releases all allocated device memory
* - Destroys mutex and synchronization primitives
* - Cleans up pool data structures and state
* - Invalidates pool for future use
*
* All elements must be freed before calling this function. After
* deinitialization, the pool cannot be used for further operations
* and any remaining element references become invalid.
*
* @param[in, out] pool Pointer to @ref pva_kmd_devmem_pool structure to deinitialize
* Valid value: non-null, must be initialized, all elements freed
*/
void pva_kmd_devmem_pool_deinit(struct pva_kmd_devmem_pool *pool); void pva_kmd_devmem_pool_deinit(struct pva_kmd_devmem_pool *pool);
#endif #endif

View File

@@ -6,13 +6,13 @@
#include "pva_kmd_resource_table.h" #include "pva_kmd_resource_table.h"
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#define PVA_KMD_INVALID_CH_IDX 0xFF #define PVA_KMD_INVALID_CH_IDX 0xFFU
void pva_kmd_unload_dma_config_unsafe(struct pva_kmd_dma_resource_aux *dma_aux) void pva_kmd_unload_dma_config_unsafe(struct pva_kmd_dma_resource_aux *dma_aux)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < dma_aux->dram_res_count; i++) { for (i = 0U; i < dma_aux->dram_res_count; i++) {
pva_kmd_drop_resource_unsafe(dma_aux->res_table, pva_kmd_drop_resource_unsafe(dma_aux->res_table,
dma_aux->static_dram_res_ids[i]); dma_aux->static_dram_res_ids[i]);
} }
@@ -31,31 +31,33 @@ static void trace_dma_channels(struct pva_dma_config const *dma_config,
const struct pva_dma_channel *channel; const struct pva_dma_channel *channel;
uint32_t num_descs = dma_config->header.num_descriptors; uint32_t num_descs = dma_config->header.num_descriptors;
for (ch_index = 0; ch_index < cfg_hdr->num_channels; ch_index++) { for (ch_index = 0U; ch_index < cfg_hdr->num_channels; ch_index++) {
uint8_t desc_index; uint8_t desc_index;
channel = &dma_config->channels[ch_index]; channel = &dma_config->channels[ch_index];
desc_index = channel->desc_index; desc_index = channel->desc_index;
for (uint32_t i = 0; i < PVA_MAX_NUM_DMA_DESC; i++) { for (uint32_t i = 0U; i < PVA_MAX_NUM_DMA_DESC; i++) {
desc_index = array_index_nospec(desc_index, num_descs); desc_index = (uint8_t)array_index_nospec(desc_index,
num_descs);
if (desc_to_ch[desc_index] != PVA_KMD_INVALID_CH_IDX) { if (desc_to_ch[desc_index] != PVA_KMD_INVALID_CH_IDX) {
//Already traced this descriptor //Already traced this descriptor
break; break;
} }
desc_to_ch[desc_index] = ch_index; desc_to_ch[desc_index] = (uint8_t)ch_index;
desc_index = sat_sub8( desc_index = sat_sub8(
dma_config->descriptors[desc_index].link_desc_id, dma_config->descriptors[desc_index].link_desc_id,
1); 1);
desc_index =
sat_sub8(desc_index, cfg_hdr->base_descriptor);
} }
} }
} }
enum pva_error enum pva_error pva_kmd_load_dma_config(
pva_kmd_load_dma_config(struct pva_kmd_resource_table *resource_table, struct pva_kmd_resource_table *resource_table,
const struct pva_ops_dma_config_register *dma_cfg_hdr, const struct pva_ops_dma_config_register *dma_cfg_hdr,
uint32_t dma_config_size, uint32_t dma_config_size, struct pva_kmd_dma_resource_aux *dma_aux,
struct pva_kmd_dma_resource_aux *dma_aux, void *fw_dma_cfg, uint32_t *out_fw_fetch_size, bool skip_validation)
void *fw_dma_cfg, uint32_t *out_fw_fetch_size)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
uint32_t fw_fetch_size; uint32_t fw_fetch_size;
@@ -72,23 +74,26 @@ pva_kmd_load_dma_config(struct pva_kmd_resource_table *resource_table,
goto err_out; goto err_out;
} }
for (uint32_t i = 0; i < PVA_MAX_NUM_DMA_DESC; i++) { for (uint32_t i = 0U; i < PVA_MAX_NUM_DMA_DESC; i++) {
desc_to_ch[i] = PVA_KMD_INVALID_CH_IDX; desc_to_ch[i] = PVA_KMD_INVALID_CH_IDX;
} }
err = pva_kmd_parse_dma_config(dma_cfg_hdr, dma_config_size, err = pva_kmd_parse_dma_config(dma_cfg_hdr, dma_config_size,
&dma_config, &dma_config,
&resource_table->pva->hw_consts); &resource_table->pva->hw_consts,
skip_validation);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto free_scratch_buf; goto free_scratch_buf;
} }
err = pva_kmd_validate_dma_config(&dma_config, if (!skip_validation) { // Skip validation for PFSD and test mode
&resource_table->pva->hw_consts, err = pva_kmd_validate_dma_config(
scratch_buf->access_sizes, &dma_config, &resource_table->pva->hw_consts,
scratch_buf->hw_dma_descs_mask); scratch_buf->access_sizes,
if (err != PVA_SUCCESS) { scratch_buf->hw_dma_descs_mask);
goto free_scratch_buf; if (err != PVA_SUCCESS) {
goto free_scratch_buf;
}
} }
trace_dma_channels(&dma_config, desc_to_ch); trace_dma_channels(&dma_config, desc_to_ch);
@@ -123,9 +128,10 @@ pva_kmd_load_dma_config(struct pva_kmd_resource_table *resource_table,
} }
err = pva_kmd_bind_static_buffers( err = pva_kmd_bind_static_buffers(
fw_dma_cfg, dma_aux, scratch_buf->static_slots, (struct pva_dma_config_resource *)fw_dma_cfg, dma_aux,
dma_config.header.num_static_slots, scratch_buf->static_relocs, scratch_buf->static_slots, dma_config.header.num_static_slots,
dma_config.static_bindings, dma_config.header.num_static_slots); scratch_buf->static_relocs, dma_config.static_bindings,
dma_config.header.num_static_slots);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto drop_res; goto drop_res;
} }

View File

@@ -7,80 +7,330 @@
#include "pva_kmd.h" #include "pva_kmd.h"
#include "pva_resource.h" #include "pva_resource.h"
/* Mask to extract the GOB offset from the Surface address */ /**
* @brief Mask to extract the GOB offset from the Surface address
*
* @details Mask to extract the GOB offset from the Surface address
* Used for block linear DMA configuration processing.
* Value: 0x3E00
*/
#define PVA_DMA_BL_GOB_OFFSET_MASK 0x3E00U #define PVA_DMA_BL_GOB_OFFSET_MASK 0x3E00U
/* Right shift value for moving GOB offset value extracted from surface address to LSB */ /**
* @brief Right shift value for moving GOB offset to LSB
*
* @details Right shift value for moving GOB offset value extracted from surface address to LSB
* Used in conjunction with PVA_DMA_BL_GOB_OFFSET_MASK for block linear addressing.
* Value: 6
*/
#define PVA_DMA_BL_GOB_OFFSET_MASK_RSH 6U #define PVA_DMA_BL_GOB_OFFSET_MASK_RSH 6U
/**
* @brief Maximum descriptor ID value supported by hardware
*
* @details Maximum descriptor ID value supported by hardware
* Used for DMA descriptor validation and range checking.
* Value: 0x3F (63 decimal)
*/
#define MAX_DESC_ID 0x3FU #define MAX_DESC_ID 0x3FU
/**
* @brief Enumeration of DMA frame replication modes
*
* @details Defines the different frame replication modes supported by the DMA engine.
* Frame replication allows efficient broadcasting of data to multiple destinations
* or processing paths, optimizing memory bandwidth usage for certain algorithms.
*/
enum pva_dma_frame_rep { enum pva_dma_frame_rep {
/** @brief No replication - single copy operation */
REPLICATION_NONE = 0, REPLICATION_NONE = 0,
/** @brief Two-way replication - data copied to 2 destinations */
REPLICATION_TWO_WAY, REPLICATION_TWO_WAY,
/** @brief Four-way replication - data copied to 4 destinations */
REPLICATION_FOUR_WAY, REPLICATION_FOUR_WAY,
/** @brief Eight-way replication - data copied to 8 destinations */
REPLICATION_EIGHT_WAY, REPLICATION_EIGHT_WAY,
/** @brief Sixteen-way replication - data copied to 16 destinations */
REPLICATION_SIXTEEN_WAY, REPLICATION_SIXTEEN_WAY,
/** @brief Thirty-two-way replication - data copied to 32 destinations */
REPLICATION_THIRTYTWO_WAY, REPLICATION_THIRTYTWO_WAY,
/** @brief Full replication - maximum supported replication */
REPLICATION_FULL REPLICATION_FULL
}; };
/**
* @brief DMA access range entry for validation
*
* @details This structure defines a memory access range with start and end addresses
* used for DMA validation. It ensures that DMA operations do not access memory
* outside of allocated and mapped regions, providing memory protection and
* preventing buffer overruns.
*/
struct pva_kmd_dma_access_entry { struct pva_kmd_dma_access_entry {
/**
* @brief Starting address of the access range
* Valid range: [INT64_MIN .. INT64_MAX]
*/
int64_t start_addr; int64_t start_addr;
/**
* @brief Ending address of the access range (inclusive)
* Valid range: [start_addr .. INT64_MAX]
*/
int64_t end_addr; int64_t end_addr;
}; };
/**
* @brief Complete DMA access information for validation
*
* @details This structure contains access range information for all potential
* DMA targets including source, primary destination, and secondary destination.
* It is used during DMA configuration validation to ensure all memory accesses
* are within valid ranges and properly bounded.
*/
struct pva_kmd_dma_access { struct pva_kmd_dma_access {
/** @brief Source buffer access range */
struct pva_kmd_dma_access_entry src; struct pva_kmd_dma_access_entry src;
/** @brief Primary destination buffer access range */
struct pva_kmd_dma_access_entry dst; struct pva_kmd_dma_access_entry dst;
/** @brief Secondary destination buffer access range */
struct pva_kmd_dma_access_entry dst2; struct pva_kmd_dma_access_entry dst2;
}; };
struct pva_kmd_resource_table; struct pva_kmd_resource_table;
struct pva_kmd_hw_constants; struct pva_kmd_hw_constants;
/** Auxiliary information needed for managing DMA resources: /**
* @brief Auxiliary information for DMA resource management
* *
* - Hold references to DRAM buffers and VPU bin used by the DMA configuration. * @details Auxiliary information needed for managing DMA resources including
* - Scratch buffers needed during DMA configuration loading. * holding references to DRAM buffers and VPU binaries used by DMA configuration,
* and providing scratch buffers needed during DMA configuration loading.
* This structure maintains resource lifetime and dependency tracking.
*/ */
struct pva_kmd_dma_resource_aux { struct pva_kmd_dma_resource_aux {
/**
* @brief Pointer to the resource table for resource management
*/
struct pva_kmd_resource_table *res_table; struct pva_kmd_resource_table *res_table;
/**
* @brief Resource ID of the VPU binary used by this DMA configuration
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t vpu_bin_res_id; uint32_t vpu_bin_res_id;
/**
* @brief Number of DRAM resources referenced by this DMA configuration
* Valid range: [0 .. PVA_KMD_MAX_NUM_DMA_DRAM_SLOTS]
*/
uint32_t dram_res_count; uint32_t dram_res_count;
/** DRAM buffers statically referenced by the DMA configuration */
/**
* @brief Array of DRAM buffer resource IDs statically referenced by DMA configuration
*
* @details DRAM buffers statically referenced by the DMA configuration
*/
uint32_t static_dram_res_ids[PVA_KMD_MAX_NUM_DMA_DRAM_SLOTS]; uint32_t static_dram_res_ids[PVA_KMD_MAX_NUM_DMA_DRAM_SLOTS];
}; };
/* Scratch buffers needed during DMA configuration loading. They don't fit on stack. */ /**
* @brief Scratch buffers for DMA configuration processing
*
* @details Scratch buffers needed during DMA configuration loading that don't fit on stack.
* These buffers provide temporary storage for parsing, validation, and conversion
* operations during DMA configuration setup. They help avoid stack overflow issues
* and provide efficient memory management for DMA operations.
*/
struct pva_kmd_dma_scratch_buffer { struct pva_kmd_dma_scratch_buffer {
/**
* @brief Static slot definitions for firmware
*/
struct pva_fw_dma_slot static_slots[PVA_KMD_MAX_NUM_DMA_SLOTS]; struct pva_fw_dma_slot static_slots[PVA_KMD_MAX_NUM_DMA_SLOTS];
/**
* @brief Static relocation information for firmware
*/
struct pva_fw_dma_reloc static_relocs[PVA_KMD_MAX_NUM_DMA_SLOTS]; struct pva_fw_dma_reloc static_relocs[PVA_KMD_MAX_NUM_DMA_SLOTS];
/**
* @brief Access size validation information for each descriptor
*/
struct pva_kmd_dma_access access_sizes[PVA_MAX_NUM_DMA_DESC]; struct pva_kmd_dma_access access_sizes[PVA_MAX_NUM_DMA_DESC];
/**
* @brief Bitmask for hardware DMA descriptors tracking
*/
uint64_t hw_dma_descs_mask[((PVA_MAX_NUM_DMA_DESC / 64ULL) + 1ULL)]; uint64_t hw_dma_descs_mask[((PVA_MAX_NUM_DMA_DESC / 64ULL) + 1ULL)];
}; };
enum pva_error /**
pva_kmd_parse_dma_config(const struct pva_ops_dma_config_register *dma_cfg_hdr, * @brief Parse and validate user-provided DMA configuration
uint32_t dma_config_size, *
struct pva_dma_config *out_cfg, * @details This function performs the following operations:
struct pva_kmd_hw_constants const *hw_consts); * - Parses the user-provided DMA configuration data structure
* - Validates configuration parameters against hardware constants
* - Converts user format to internal representation for processing
* - Checks descriptor counts, slot assignments, and parameter ranges
* - Ensures configuration compatibility with hardware capabilities
* - Prepares configuration for further validation and loading steps
*
* The parsing includes validation of DMA descriptors, slot configurations,
* addressing modes, and other parameters required for safe DMA operation.
* Any invalid parameters or unsupported configurations will result in
* appropriate error codes.
*
* @param[in] dma_cfg_hdr Pointer to user DMA configuration header
* Valid value: non-null
* @param[in] dma_config_size Size of the DMA configuration data in bytes
* Valid range: [sizeof(header) .. UINT32_MAX]
* @param[out] out_cfg Pointer to parsed DMA configuration output
* Valid value: non-null
* @param[in] hw_consts Pointer to hardware constants for validation
* Valid value: non-null
* @param[in] skip_validation Skip DMA validation if true
* Valid value: true, false
*
* @retval PVA_SUCCESS DMA configuration parsed successfully
* @retval PVA_INVALID_DMA_CONFIG Invalid configuration parameters
* @retval PVA_NOT_IMPL Unsupported DMA configuration feature
* @retval PVA_INVAL Invalid input parameters
*/
enum pva_error pva_kmd_parse_dma_config(
const struct pva_ops_dma_config_register *dma_cfg_hdr,
uint32_t dma_config_size, struct pva_dma_config *out_cfg,
struct pva_kmd_hw_constants const *hw_consts, bool skip_validation);
/**
* @brief Acquire references to resources used by DMA configuration
*
* @details This function performs the following operations:
* - Identifies all resources (DRAM buffers, VPU binaries) used by DMA config
* - Acquires reference counts for these resources to prevent premature cleanup
* - Updates the auxiliary structure with resource tracking information
* - Ensures resource lifetime extends through DMA configuration usage
* - Provides dependency management for proper resource cleanup ordering
*
* This function must be called before using a DMA configuration to ensure
* all referenced resources remain valid. The references should be released
* using @ref pva_kmd_unload_dma_config_unsafe() when the configuration is
* no longer needed.
*
* @param[in] dma_cfg Pointer to parsed DMA configuration
* Valid value: non-null
* @param[in, out] dma_aux Pointer to DMA auxiliary structure to update
* Valid value: non-null
*
* @retval PVA_SUCCESS Resources acquired successfully
* @retval PVA_INVALID_RESOURCE Resource in invalid state for acquisition
* @retval PVA_INVAL Invalid configuration or auxiliary pointer
*/
enum pva_error enum pva_error
pva_kmd_dma_use_resources(struct pva_dma_config const *dma_cfg, pva_kmd_dma_use_resources(struct pva_dma_config const *dma_cfg,
struct pva_kmd_dma_resource_aux *dma_aux); struct pva_kmd_dma_resource_aux *dma_aux);
/**
* @brief Validate DMA configuration against hardware constraints
*
* @details This function performs the following operations:
* - Validates DMA configuration parameters against hardware capabilities
* - Checks descriptor limits, slot usage, and addressing constraints
* - Computes access ranges for memory validation
* - Builds hardware descriptor usage masks for tracking
* - Ensures configuration will execute safely on hardware
* - Verifies memory access patterns and alignment requirements
*
* The validation covers all aspects of DMA operation including transfer
* sizes, addressing modes, descriptor linking, and hardware resource usage.
* This comprehensive validation prevents runtime errors and ensures
* reliable DMA operation.
*
* @param[in] dma_cfg Pointer to DMA configuration to validate
* Valid value: non-null
* @param[in] hw_consts Pointer to hardware constants for validation
* Valid value: non-null
* @param[out] access_sizes Array to store computed access size information
* Valid value: non-null, min size PVA_MAX_NUM_DMA_DESC
* @param[out] hw_dma_descs_mask Bitmask for tracking hardware descriptor usage
* Valid value: non-null
*
* @retval PVA_SUCCESS DMA configuration validated successfully
* @retval PVA_INVALID_DMA_CONFIG Configuration violates hardware constraints
* @retval PVA_ENOSPC Configuration exceeds hardware limits
* @retval PVA_INVAL Invalid configuration or output pointers
*/
enum pva_error enum pva_error
pva_kmd_validate_dma_config(struct pva_dma_config const *dma_cfg, pva_kmd_validate_dma_config(struct pva_dma_config const *dma_cfg,
struct pva_kmd_hw_constants const *hw_consts, struct pva_kmd_hw_constants const *hw_consts,
struct pva_kmd_dma_access *access_sizes, struct pva_kmd_dma_access *access_sizes,
uint64_t *hw_dma_descs_mask); uint64_t *hw_dma_descs_mask);
/**
* @brief Compute memory access patterns for DMA configuration
*
* @details This function performs the following operations:
* - Analyzes DMA descriptors to determine memory access patterns
* - Computes source and destination address ranges for each operation
* - Builds hardware descriptor usage masks for resource tracking
* - Calculates total memory footprint and access requirements
* - Provides information needed for memory validation and protection
* - Determines optimal memory layout and access strategies
*
* The computed access information is used for memory validation, SMMU
* programming, and ensuring DMA operations remain within allocated
* buffer boundaries. This analysis is critical for memory protection
* and system stability.
*
* @param[in] dma_cfg Pointer to DMA configuration to analyze
* Valid value: non-null
* @param[out] access_sizes Array to store computed access information
* Valid value: non-null, min size PVA_MAX_NUM_DMA_DESC
* @param[out] hw_dma_descs_mask Bitmask for tracking hardware descriptor usage
* Valid value: non-null
*
* @retval PVA_SUCCESS Access patterns computed successfully
* @retval PVA_INVALID_DMA_CONFIG Invalid DMA configuration for analysis
* @retval PVA_INVAL Invalid configuration or output pointers
*/
enum pva_error enum pva_error
pva_kmd_compute_dma_access(struct pva_dma_config const *dma_cfg, pva_kmd_compute_dma_access(struct pva_dma_config const *dma_cfg,
struct pva_kmd_dma_access *access_sizes, struct pva_kmd_dma_access *access_sizes,
uint64_t *hw_dma_descs_mask); uint64_t *hw_dma_descs_mask);
/**
* @brief Collect relocation information for firmware DMA configuration
*
* @details This function performs the following operations:
* - Extracts static and dynamic slot information from DMA configuration
* - Builds relocation tables for firmware address patching
* - Separates static slots (bound at load time) from dynamic slots
* - Generates firmware-compatible slot and relocation structures
* - Maps descriptor channels to slots for proper address resolution
* - Prepares data needed for firmware DMA setup and execution
*
* The relocation information enables firmware to properly patch addresses
* in DMA descriptors at runtime, supporting both static (pre-bound) and
* dynamic (runtime-bound) memory slots for flexible DMA operation.
*
* @param[in] dma_cfg Pointer to DMA configuration
* Valid value: non-null
* @param[in] access_sizes Array of access size information
* Valid value: non-null
* @param[out] out_static_slots Array to store static slot information
* Valid value: non-null, min size num_static_slots
* @param[in] num_static_slots Number of static slots to process
* Valid range: [0 .. PVA_KMD_MAX_NUM_DMA_SLOTS]
* @param[out] out_static_relocs Array to store static relocation information
* Valid value: non-null
* @param[out] out_dyn_slots Array to store dynamic slot information
* Valid value: non-null, min size num_dyn_slots
* @param[in] num_dyn_slots Number of dynamic slots to process
* Valid range: [0 .. PVA_KMD_MAX_NUM_DMA_SLOTS]
* @param[out] out_dyn_relocs Array to store dynamic relocation information
* Valid value: non-null
* @param[in] desc_to_ch Array mapping descriptors to channels
* Valid value: non-null
*/
void pva_kmd_collect_relocs(struct pva_dma_config const *dma_cfg, void pva_kmd_collect_relocs(struct pva_dma_config const *dma_cfg,
struct pva_kmd_dma_access const *access_sizes, struct pva_kmd_dma_access const *access_sizes,
struct pva_fw_dma_slot *out_static_slots, struct pva_fw_dma_slot *out_static_slots,
@@ -92,13 +342,39 @@ void pva_kmd_collect_relocs(struct pva_dma_config const *dma_cfg,
uint8_t const *desc_to_ch); uint8_t const *desc_to_ch);
/** /**
* @brief Bind static buffers to the DMA configuration. * @brief Bind static buffers to the DMA configuration
* *
* When binding static buffers, we edit pva_dma_config in-place and replace the * @details This function performs the following operations:
* offset field with the final addresses of static buffers. * - Edits @ref pva_dma_config in-place to replace offset fields with final addresses
* - Resolves static buffer addresses from resource table entries
* - Validates that DMA configuration does not access static buffers out of range
* - Updates firmware DMA configuration with bound address information
* - Ensures memory protection by validating all access patterns
* - Prepares configuration for safe execution with static buffer bindings
* *
* We also validate that the DMA configuration does not access those static * When binding static buffers, this function modifies the DMA configuration
* buffers out of range. * to embed actual memory addresses, enabling efficient firmware execution
* without runtime address resolution for static resources.
*
* @param[in, out] fw_dma_cfg Pointer to firmware DMA configuration to update
* Valid value: non-null
* @param[in] dma_aux Pointer to DMA auxiliary resource information
* Valid value: non-null
* @param[in] static_slots Array of static slot definitions
* Valid value: non-null
* @param[in] num_static_slots Number of static slots to bind
* Valid range: [0 .. PVA_KMD_MAX_NUM_DMA_SLOTS]
* @param[in] static_relocs Array of static relocation information
* Valid value: non-null
* @param[in] static_bindings Array of static binding specifications
* Valid value: non-null
* @param[in] num_static_bindings Number of static bindings to process
* Valid range: [0 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Static buffers bound successfully
* @retval PVA_INVALID_BINDING Invalid binding specification
* @retval PVA_BUF_OUT_OF_RANGE Buffer access would exceed valid range
* @retval PVA_INVALID_RESOURCE Resource in invalid state for binding
*/ */
enum pva_error pva_kmd_bind_static_buffers( enum pva_error pva_kmd_bind_static_buffers(
struct pva_dma_config_resource *fw_dma_cfg, struct pva_dma_config_resource *fw_dma_cfg,
@@ -109,7 +385,28 @@ enum pva_error pva_kmd_bind_static_buffers(
uint32_t num_static_bindings); uint32_t num_static_bindings);
/** /**
* @brief Convert user DMA configuration to firmware format. * @brief Convert user DMA configuration to firmware format
*
* @details This function performs the following operations:
* - Converts parsed DMA configuration to firmware-compatible format
* - Serializes configuration data for efficient firmware consumption
* - Calculates the size of configuration data needed in firmware memory
* - Optimizes configuration layout for firmware execution performance
* - Handles hardware-specific formatting and alignment requirements
* - Prepares configuration for transfer to firmware execution environment
*
* The firmware format is optimized for efficient parsing and execution
* by the PVA firmware, with proper alignment and layout for direct
* hardware register programming.
*
* @param[in] dma_cfg Pointer to parsed DMA configuration
* Valid value: non-null
* @param[out] fw_dma_config Buffer for firmware DMA configuration output
* Valid value: non-null, sufficient size
* @param[out] out_fw_fetch_size Pointer to store firmware fetch size
* Valid value: non-null
* @param[in] support_hwseq_frame_linking Whether hardware sequence frame linking is supported
* Valid values: true, false
*/ */
void pva_kmd_write_fw_dma_config(struct pva_dma_config const *dma_cfg, void pva_kmd_write_fw_dma_config(struct pva_dma_config const *dma_cfg,
void *fw_dma_config, void *fw_dma_config,
@@ -117,31 +414,62 @@ void pva_kmd_write_fw_dma_config(struct pva_dma_config const *dma_cfg,
bool support_hwseq_frame_linking); bool support_hwseq_frame_linking);
/** /**
* @brief Load DMA configuration into firmware format. * @brief Load DMA configuration into firmware format
* *
* This function mostly does the following things: * @details This function performs comprehensive DMA configuration loading including:
* - Validates the DMA configuration against hardware constraints
* - Binds static resources (buffers) and embeds their addresses in firmware configuration
* - Holds references to DRAM buffers and VPU binaries used by the configuration
* - Converts the DMA configuration into optimized firmware format
* - Computes memory requirements and access patterns
* - Ensures proper resource lifetime management and dependency tracking
* - Provides complete configuration ready for firmware execution
* *
* - Validate the DMA configuration. * This function integrates all aspects of DMA configuration processing
* - Bind static resources (buffers) and embed their addresses directly in the * into a single operation, producing a validated and optimized configuration
* firmware DMA configuration. * that can be safely executed by the firmware.
* - Hold references to DRAM buffers and VPU bin used by the DMA configuration.
* - Convert the DMA configuration into firmware format.
* *
* @param resource_table the resource table for the context. * @param[in] resource_table Pointer to resource table for the context
* @param dma_config DMA configuration from user space. * Valid value: non-null, must be initialized
* @param dma_config_size Size of the dma_config buffer. * @param[in] dma_cfg_hdr Pointer to user DMA configuration header
* @param dma_aux Auxiliary information needed for loading the DMA * Valid value: non-null
* configuration. * @param[in] dma_config_size Size of the dma_config buffer in bytes
* @param fw_dma_cfg Output buffer for the firmware DMA configuration. * Valid range: [sizeof(header) .. UINT32_MAX]
* @param out_fw_fetch_size Size of the firmware DMA configuration that needs to * @param[in, out] dma_aux Pointer to auxiliary information for DMA loading
* be fetched into TCM. * Valid value: non-null
* @param[out] fw_dma_cfg Output buffer for firmware DMA configuration
* Valid value: non-null, sufficient size
* @param[out] out_fw_fetch_size Pointer to store size of configuration to fetch into TCM
* Valid value: non-null
*
* @retval PVA_SUCCESS DMA configuration loaded successfully
* @retval PVA_INVALID_DMA_CONFIG Invalid or unsupported DMA configuration
* @retval PVA_INVALID_RESOURCE Resource in invalid state for loading
* @retval PVA_NOMEM Failed to allocate required memory
* @retval PVA_BUF_OUT_OF_RANGE Configuration would violate memory protection
*/ */
enum pva_error enum pva_error pva_kmd_load_dma_config(
pva_kmd_load_dma_config(struct pva_kmd_resource_table *resource_table, struct pva_kmd_resource_table *resource_table,
const struct pva_ops_dma_config_register *dma_cfg_hdr, const struct pva_ops_dma_config_register *dma_cfg_hdr,
uint32_t dma_config_size, uint32_t dma_config_size, struct pva_kmd_dma_resource_aux *dma_aux,
struct pva_kmd_dma_resource_aux *dma_aux, void *fw_dma_cfg, uint32_t *out_fw_fetch_size, bool priv);
void *fw_dma_cfg, uint32_t *out_fw_fetch_size);
/**
* @brief Unload DMA configuration and release associated resources (unsafe version)
*
* @details This function performs the following operations:
* - Releases all resource references held by the DMA configuration
* - Cleans up auxiliary resource tracking information
* - Frees memory allocations associated with the configuration
* - Invalidates the DMA auxiliary structure for future use
* - Does not perform thread-safe locking (caller's responsibility)
*
* This function is not thread-safe and requires external synchronization.
* It should be called when a DMA configuration is no longer needed to
* ensure proper resource cleanup and prevent memory leaks.
*
* @param[in, out] dma_aux Pointer to DMA auxiliary structure to clean up
* Valid value: non-null, must have been initialized
*/
void pva_kmd_unload_dma_config_unsafe(struct pva_kmd_dma_resource_aux *dma_aux); void pva_kmd_unload_dma_config_unsafe(struct pva_kmd_dma_resource_aux *dma_aux);
#endif // PVA_KMD_DMA_CFG_H #endif // PVA_KMD_DMA_CFG_H

View File

@@ -9,6 +9,9 @@
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
/* DMA channels per engine (matches PVA_NUM_DMA_CHANNELS in pva_fw_constants.h) */
#define PVA_KMD_DMA_CHANNELS_PER_ENGINE 16U
static uint32_t get_slot_line_pitch(struct pva_fw_dma_descriptor *descs, static uint32_t get_slot_line_pitch(struct pva_fw_dma_descriptor *descs,
struct pva_fw_dma_reloc const *relocs, struct pva_fw_dma_reloc const *relocs,
struct pva_fw_dma_slot const *slot) struct pva_fw_dma_slot const *slot)
@@ -20,9 +23,15 @@ static uint32_t get_slot_line_pitch(struct pva_fw_dma_descriptor *descs,
PVA_EXTRACT(first_desc->transfer_control1, 1, 0, uint8_t); PVA_EXTRACT(first_desc->transfer_control1, 1, 0, uint8_t);
if (reloc->field == PVA_FW_DMA_RELOC_FIELD_SRC) { if (reloc->field == PVA_FW_DMA_RELOC_FIELD_SRC) {
return first_desc->slp_adv << log2_bpp; /* MISRA 10.8, INT31-C: Cast and shift in separate steps */
uint16_t slp_adv_u16 = (uint16_t)first_desc->slp_adv;
uint32_t result = (uint32_t)slp_adv_u16 << log2_bpp;
return result;
} else { } else {
return first_desc->dlp_adv << log2_bpp; /* MISRA 10.8, INT31-C: Cast and shift in separate steps */
uint16_t dlp_adv_u16 = (uint16_t)first_desc->dlp_adv;
uint32_t result = (uint32_t)dlp_adv_u16 << log2_bpp;
return result;
} }
} }
@@ -39,9 +48,12 @@ set_channel_block_height(struct pva_dma_config_resource *dma_config,
return PVA_ERR_CMD_INVALID_BLOCK_HEIGHT; return PVA_ERR_CMD_INVALID_BLOCK_HEIGHT;
} }
while (ch_mask > 0) { while (ch_mask > 0U) {
uint8_t ch_index = __builtin_ctz(ch_mask); uint8_t ch_index = (uint8_t)__builtin_ctz(ch_mask);
if (dma_config->ch_block_height_fixed_mask & (1 << ch_index)) { /* CERT INT34-C: ch_index from ctz(uint16_t) is guaranteed < 16 DMA channels */
ASSERT(ch_index < PVA_KMD_DMA_CHANNELS_PER_ENGINE);
if ((dma_config->ch_block_height_fixed_mask &
((uint16_t)1U << ch_index)) != 0U) {
/* If this bit is already set, it means block height cannot be changed. */ /* If this bit is already set, it means block height cannot be changed. */
uint8_t set_bh = PVA_EXTRACT(channels[ch_index].cntl0, uint8_t set_bh = PVA_EXTRACT(channels[ch_index].cntl0,
27, 25, uint8_t); 27, 25, uint8_t);
@@ -55,50 +67,24 @@ set_channel_block_height(struct pva_dma_config_resource *dma_config,
PVA_INSERT(log2_block_height, 27, 25); PVA_INSERT(log2_block_height, 27, 25);
dma_config->ch_block_height_fixed_mask |= dma_config->ch_block_height_fixed_mask |=
(1 << ch_index); ((uint16_t)1U << ch_index);
} }
ch_mask &= ~(1 << ch_index); ch_mask &= ~((uint16_t)1U << ch_index);
} }
return PVA_SUCCESS; return PVA_SUCCESS;
} }
static enum pva_error static enum pva_error
bind_static_dram_slot(struct pva_dma_config_resource *dma_config, validate_dram_slot_flags(struct pva_fw_dma_slot const *slot,
struct pva_kmd_dma_resource_aux *dma_aux, struct pva_kmd_dram_resource *dram_res)
struct pva_fw_dma_slot const *slot,
struct pva_fw_dma_reloc const *static_relocs,
struct pva_dma_dram_binding const *dram_bd)
{ {
struct pva_fw_dma_descriptor *descs =
pva_dma_config_get_descriptors(dma_config);
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
struct pva_fw_dma_reloc const *relocs;
bool is_block_linear =
(dram_bd->surface_format == PVA_SURF_FMT_BLOCK_LINEAR);
uint32_t line_pitch = get_slot_line_pitch(descs, static_relocs, slot);
uint8_t log2_block_height = dram_bd->log2_block_height;
struct pva_kmd_dram_resource *dram_res =
&pva_kmd_peek_resource(dma_aux->res_table, dram_bd->resource_id)
->dram;
uint64_t slot_offset_pl = dram_bd->slot_offset;
uint64_t surface_base_addr =
sat_add64(dram_bd->surface_base_offset, dram_res->mem->iova);
/* When binding a buffer, we add the binding->surface_base_offset to the
* buffer base address. Therefore, the effective buffer size is
* reduced by the offset. */
uint64_t max_surface_size =
sat_sub64(dram_res->mem->size, dram_bd->surface_base_offset);
uint64_t sector_pack_format = 0;
int64_t slot_access_start_addr = 0LL;
int64_t slot_access_end_addr = 0LL;
uint64_t slot_surface_combined_offset = 0ULL;
pva_math_error math_error = MATH_OP_SUCCESS;
uint8_t slot_access_flags = uint8_t slot_access_flags =
PVA_EXTRACT16(slot->flags, PVA_FW_DMA_SLOT_FLAG_ACCESS_MSB, PVA_EXTRACT16(slot->flags, PVA_FW_DMA_SLOT_FLAG_ACCESS_MSB,
PVA_FW_DMA_SLOT_FLAG_ACCESS_LSB, uint8_t); PVA_FW_DMA_SLOT_FLAG_ACCESS_LSB, uint8_t);
if ((slot->flags & PVA_FW_DMA_SLOT_FLAG_DRAM) == 0) { if ((slot->flags & PVA_FW_DMA_SLOT_FLAG_DRAM) == 0U) {
pva_kmd_log_err("Binding DRAM buffer to incompatible slot"); pva_kmd_log_err("Binding DRAM buffer to incompatible slot");
err = PVA_INVALID_BINDING; err = PVA_INVALID_BINDING;
goto out; goto out;
@@ -109,90 +95,150 @@ bind_static_dram_slot(struct pva_dma_config_resource *dma_config,
pva_kmd_log_err( pva_kmd_log_err(
"DRAM buffer does not have the required access permissions"); "DRAM buffer does not have the required access permissions");
err = PVA_INVALID_BINDING; err = PVA_INVALID_BINDING;
}
out:
return err;
}
static enum pva_error
setup_block_linear_params(struct pva_dma_config_resource *dma_config,
struct pva_kmd_dma_resource_aux *dma_aux,
struct pva_fw_dma_slot const *slot,
struct pva_dma_dram_binding const *dram_bd,
uint64_t surface_base_addr, uint32_t line_pitch,
uint64_t *max_surface_size,
uint64_t *sector_pack_format)
{
enum pva_error err = PVA_SUCCESS;
pva_math_error math_error = MATH_OP_SUCCESS;
if ((slot->flags & PVA_FW_DMA_SLOT_FLAG_CB) != 0U) {
pva_kmd_log_err(
"Block linear surface is not compatible with circular buffer");
err = PVA_INVALID_BINDING;
goto out; goto out;
} }
if (is_block_linear) { *max_surface_size = pva_max_bl_surface_size(*max_surface_size,
if (slot->flags & PVA_FW_DMA_SLOT_FLAG_CB) { dram_bd->log2_block_height,
pva_kmd_log_err( line_pitch, &math_error);
"Block linear surface is not compatible with circular buffer"); if (math_error != MATH_OP_SUCCESS) {
err = PVA_INVALID_BINDING; pva_kmd_log_err(
goto out; "bind_static_dram_slot pva_max_bl_surface_size triggered a math error");
} err = PVA_ERR_MATH_OP;
max_surface_size = goto out;
pva_max_bl_surface_size(max_surface_size,
log2_block_height, line_pitch,
&math_error);
if (math_error != MATH_OP_SUCCESS) {
pva_kmd_log_err(
"bind_static_dram_slot pva_max_bl_surface_size triggered a math error");
err = PVA_ERR_MATH_OP;
goto out;
}
if (!pva_is_512B_aligned(surface_base_addr)) {
pva_kmd_log_err(
"BL surface base address is not 512B aligned");
err = PVA_BAD_SURFACE_BASE_ALIGNMENT;
goto out;
}
err = set_channel_block_height(dma_config, slot->ch_use_mask,
dram_bd->log2_block_height);
if (err != PVA_SUCCESS) {
goto out;
}
sector_pack_format =
dma_aux->res_table->pva->bl_sector_pack_format;
} }
slot_surface_combined_offset = addu64( if (!pva_is_512B_aligned(surface_base_addr)) {
slot_offset_pl, dram_bd->surface_base_offset, &math_error); pva_kmd_log_err("BL surface base address is not 512B aligned");
err = PVA_BAD_SURFACE_BASE_ALIGNMENT;
goto out;
}
if (slot_surface_combined_offset >= (uint64_t)MAX_INT64) { err = set_channel_block_height(dma_config, slot->ch_use_mask,
dram_bd->log2_block_height);
if (err != PVA_SUCCESS) {
goto out;
}
*sector_pack_format = dma_aux->res_table->pva->bl_sector_pack_format;
out:
return err;
}
static enum pva_error calculate_slot_offsets(
struct pva_fw_dma_slot const *slot,
struct pva_dma_dram_binding const *dram_bd, uint64_t max_surface_size,
int64_t *slot_access_start_addr, int64_t *slot_access_end_addr,
uint64_t *slot_surface_combined_offset,
uint64_t *adjusted_max_surface_size, pva_math_error *math_error)
{
enum pva_error err = PVA_SUCCESS;
*slot_surface_combined_offset = addu64(
dram_bd->slot_offset, dram_bd->surface_base_offset, math_error);
if (*slot_surface_combined_offset >= (uint64_t)MAX_INT64) {
pva_kmd_log_err("Slot surface offset too large"); pva_kmd_log_err("Slot surface offset too large");
return PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE; err = PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE;
goto out;
} }
slot_access_start_addr = *slot_access_start_addr =
adds64(slot->start_addr, (int64_t)slot_surface_combined_offset, adds64(slot->start_addr, (int64_t)*slot_surface_combined_offset,
&math_error); math_error);
slot_access_end_addr = *slot_access_end_addr =
adds64(slot->end_addr, (int64_t)slot_surface_combined_offset, adds64(slot->end_addr, (int64_t)*slot_surface_combined_offset,
&math_error); math_error);
max_surface_size = addu64(max_surface_size, *adjusted_max_surface_size = addu64(
dram_bd->surface_base_offset, &math_error); max_surface_size, dram_bd->surface_base_offset, math_error);
if (max_surface_size >= (uint64_t)MAX_INT64) { out:
pva_kmd_log_err("DRAM buffer too large for slot binding"); return err;
return PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE; }
static enum pva_error validate_slot_access_bounds(
int64_t slot_access_start_addr, int64_t slot_access_end_addr,
uint64_t adjusted_max_surface_size, pva_math_error math_error)
{
enum pva_error err = PVA_SUCCESS;
if (adjusted_max_surface_size >= (uint64_t)MAX_INT64) {
pva_kmd_log_err(
"bind_static_dram_slot: DRAM buffer too large for slot binding");
err = PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE;
goto out;
} }
if (math_error != MATH_OP_SUCCESS) { if (math_error != MATH_OP_SUCCESS) {
pva_kmd_log_err("Math error during slot binding"); pva_kmd_log_err(
return PVA_ERR_MATH_OP; "bind_static_dram_slot: Math error during slot binding");
err = PVA_ERR_MATH_OP;
goto out;
} }
if (slot_access_start_addr < 0LL) { if (slot_access_start_addr < 0LL) {
pva_kmd_log_err( pva_kmd_log_err(
"DRAM buffer offset underflows for slot binding"); "bind_static_dram_slot: DRAM buffer offset underflows for slot binding");
return PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE; err = PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE;
goto out;
} }
if (slot_access_end_addr > (int64_t)max_surface_size) { if (slot_access_end_addr > (int64_t)adjusted_max_surface_size) {
pva_kmd_log_err("DRAM buffer too small for slot binding"); pva_kmd_log_err(
return PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE; "bind_static_dram_slot: DRAM buffer too small for slot binding");
err = PVA_ERR_CMD_DRAM_BUF_OUT_OF_RANGE;
} }
out:
return err;
}
static enum pva_error
process_slot_relocations(struct pva_dma_config_resource *dma_config,
struct pva_fw_dma_slot const *slot,
struct pva_fw_dma_reloc const *static_relocs,
struct pva_dma_dram_binding const *dram_bd,
uint64_t surface_base_addr, uint64_t slot_offset_pl,
uint64_t sector_pack_format, uint32_t line_pitch,
bool is_block_linear)
{
enum pva_error err = PVA_SUCCESS;
struct pva_fw_dma_descriptor *descs =
pva_dma_config_get_descriptors(dma_config);
struct pva_fw_dma_reloc const *relocs;
pva_math_error math_error = MATH_OP_SUCCESS;
relocs = &static_relocs[slot->reloc_start_idx]; relocs = &static_relocs[slot->reloc_start_idx];
for (uint32_t i = 0; i < slot->reloc_count; i++) { for (uint32_t i = 0; i < slot->reloc_count; i++) {
struct pva_fw_dma_reloc const *reloc = &relocs[i]; struct pva_fw_dma_reloc const *reloc = &relocs[i];
struct pva_fw_dma_descriptor *desc = &descs[reloc->desc_index]; struct pva_fw_dma_descriptor *desc = &descs[reloc->desc_index];
uint8_t *addr_hi_ptr; uint8_t *addr_hi_ptr;
uint32_t *addr_lo_ptr; uint32_t *addr_lo_ptr;
uint32_t format_field_shift = 0; uint8_t format_field_shift = 0;
uint64_t addr; uint64_t addr;
uint64_t desc_offset_pl; uint64_t desc_offset_pl;
uint64_t offset; uint64_t offset;
@@ -200,11 +246,11 @@ bind_static_dram_slot(struct pva_dma_config_resource *dma_config,
if (reloc->field == PVA_FW_DMA_RELOC_FIELD_SRC) { if (reloc->field == PVA_FW_DMA_RELOC_FIELD_SRC) {
addr_hi_ptr = &desc->src_adr1; addr_hi_ptr = &desc->src_adr1;
addr_lo_ptr = &desc->src_adr0; addr_lo_ptr = &desc->src_adr0;
format_field_shift = 3; //SRC_TF in TRANSFER_CONTROL0 format_field_shift = 3U; //SRC_TF in TRANSFER_CONTROL0
} else if (reloc->field == PVA_FW_DMA_RELOC_FIELD_DST) { } else if (reloc->field == PVA_FW_DMA_RELOC_FIELD_DST) {
addr_hi_ptr = &desc->dst_adr1; addr_hi_ptr = &desc->dst_adr1;
addr_lo_ptr = &desc->dst_adr0; addr_lo_ptr = &desc->dst_adr0;
format_field_shift = 7; //DST_TF in TRANSFER_CONTROL0 format_field_shift = 7U; //DST_TF in TRANSFER_CONTROL0
} else { /* PVA_FW_DMA_RELOC_FIELD_DST2 */ } else { /* PVA_FW_DMA_RELOC_FIELD_DST2 */
pva_kmd_log_err("Binding DRAM buffer to DST2 slot"); pva_kmd_log_err("Binding DRAM buffer to DST2 slot");
err = PVA_INVAL; err = PVA_INVAL;
@@ -212,20 +258,24 @@ bind_static_dram_slot(struct pva_dma_config_resource *dma_config,
} }
desc_offset_pl = assemble_addr(*addr_hi_ptr, *addr_lo_ptr); desc_offset_pl = assemble_addr(*addr_hi_ptr, *addr_lo_ptr);
offset = sat_add64(slot_offset_pl, desc_offset_pl); offset = sat_add64(slot_offset_pl, desc_offset_pl);
desc->transfer_control0 &= ~(1 << format_field_shift); /* CERT INT31-C: Bitwise NOT of shifted value, result masked by uint8_t cast,
* safe as only lower 8 bits are used in bitwise AND */
desc->transfer_control0 &=
(uint8_t) ~(1U << format_field_shift);
if (is_block_linear) { if (is_block_linear) {
/* We need to insert bits surface_base_addr[13, 9] to /* We need to insert bits surface_base_addr[13, 9] to
* transfer_control2[7:3] as specified by DMA IAS. This helps the * transfer_control2[7:3] as specified by DMA IAS. This helps the
* HW identify starting GOB index inside a block. */ * HW identify starting GOB index inside a block. */
desc->transfer_control2 &= ~PVA_MASK(7, 3); desc->transfer_control2 &= ~PVA_MASK8(7U, 3U);
desc->transfer_control2 |= desc->transfer_control2 |=
PVA_INSERT8(PVA_EXTRACT64(surface_base_addr, 13, PVA_INSERT8(PVA_EXTRACT64(surface_base_addr, 13,
9, uint8_t), 9, uint8_t),
7, 3); 7, 3);
desc->transfer_control0 |= 1 << format_field_shift; desc->transfer_control0 |=
(uint8_t)(1U << format_field_shift);
offset = pva_pl_to_bl_offset(offset, line_pitch, offset = pva_pl_to_bl_offset(offset, line_pitch,
log2_block_height, dram_bd->log2_block_height,
&math_error); &math_error);
if (math_error != MATH_OP_SUCCESS) { if (math_error != MATH_OP_SUCCESS) {
pva_kmd_log_err( pva_kmd_log_err(
@@ -245,6 +295,92 @@ bind_static_dram_slot(struct pva_dma_config_resource *dma_config,
*addr_hi_ptr = iova_hi(addr); *addr_hi_ptr = iova_hi(addr);
*addr_lo_ptr = iova_lo(addr); *addr_lo_ptr = iova_lo(addr);
} }
out:
return err;
}
static enum pva_error
bind_static_dram_slot(struct pva_dma_config_resource *dma_config,
struct pva_kmd_dma_resource_aux *dma_aux,
struct pva_fw_dma_slot const *slot,
struct pva_fw_dma_reloc const *static_relocs,
struct pva_dma_dram_binding const *dram_bd)
{
struct pva_fw_dma_descriptor *descs =
pva_dma_config_get_descriptors(dma_config);
bool is_block_linear =
(dram_bd->surface_format == (uint8_t)PVA_SURF_FMT_BLOCK_LINEAR);
uint32_t line_pitch = get_slot_line_pitch(descs, static_relocs, slot);
struct pva_kmd_resource_record *resource_record =
pva_kmd_peek_resource(dma_aux->res_table, dram_bd->resource_id);
struct pva_kmd_dram_resource *dram_res;
uint64_t slot_offset_pl;
uint64_t surface_base_addr;
uint64_t max_surface_size;
uint64_t sector_pack_format = 0;
int64_t slot_access_start_addr = 0LL;
int64_t slot_access_end_addr = 0LL;
uint64_t slot_surface_combined_offset = 0ULL;
uint64_t adjusted_max_surface_size = 0ULL;
pva_math_error math_error = MATH_OP_SUCCESS;
enum pva_error err = PVA_SUCCESS;
if (resource_record == NULL) {
return PVA_INVAL;
}
dram_res = &resource_record->dram;
slot_offset_pl = dram_bd->slot_offset;
surface_base_addr =
sat_add64(dram_bd->surface_base_offset, dram_res->mem->iova);
/* When binding a buffer, we add the binding->surface_base_offset to the
* buffer base address. Therefore, the effective buffer size is
* reduced by the offset. */
max_surface_size =
sat_sub64(dram_res->mem->size, dram_bd->surface_base_offset);
/* Validate slot flags and access permissions */
err = validate_dram_slot_flags(slot, dram_res);
if (err != PVA_SUCCESS) {
goto out;
}
/* Handle block linear specific setup if needed */
if (is_block_linear) {
err = setup_block_linear_params(dma_config, dma_aux, slot,
dram_bd, surface_base_addr,
line_pitch, &max_surface_size,
&sector_pack_format);
if (err != PVA_SUCCESS) {
goto out;
}
}
/* Calculate and validate slot offsets and ranges */
err = calculate_slot_offsets(slot, dram_bd, max_surface_size,
&slot_access_start_addr,
&slot_access_end_addr,
&slot_surface_combined_offset,
&adjusted_max_surface_size, &math_error);
if (err != PVA_SUCCESS) {
goto out;
}
err = validate_slot_access_bounds(slot_access_start_addr,
slot_access_end_addr,
adjusted_max_surface_size,
math_error);
if (err != PVA_SUCCESS) {
goto out;
}
err = process_slot_relocations(dma_config, slot, static_relocs, dram_bd,
surface_base_addr, slot_offset_pl,
sector_pack_format, line_pitch,
is_block_linear);
out: out:
return err; return err;
} }
@@ -256,18 +392,21 @@ bind_static_vmem_slot(struct pva_dma_config_resource *dma_config,
struct pva_fw_dma_reloc const *static_relocs, struct pva_fw_dma_reloc const *static_relocs,
struct pva_dma_vmem_binding const *vmem_bd) struct pva_dma_vmem_binding const *vmem_bd)
{ {
enum pva_error err = PVA_SUCCESS;
struct pva_fw_dma_descriptor *descs = struct pva_fw_dma_descriptor *descs =
pva_dma_config_get_descriptors(dma_config); pva_dma_config_get_descriptors(dma_config);
struct pva_kmd_vpu_bin_resource *vpu_bin; struct pva_kmd_vpu_bin_resource *vpu_bin;
struct pva_symbol_info *sym; struct pva_symbol_info *sym;
uint32_t buffer_size, buffer_addr; uint32_t buffer_size;
uint32_t buffer_addr;
struct pva_fw_dma_reloc const *relocs; struct pva_fw_dma_reloc const *relocs;
enum pva_symbol_type needed_sym_type; enum pva_symbol_type needed_sym_type;
struct pva_kmd_resource_record *vpu_res;
uint32_t i;
enum pva_error err = PVA_SUCCESS;
if (slot->flags & PVA_FW_DMA_SLOT_FLAG_VMEM_DATA) { if ((slot->flags & PVA_FW_DMA_SLOT_FLAG_VMEM_DATA) != 0U) {
needed_sym_type = PVA_SYM_TYPE_DATA; needed_sym_type = PVA_SYM_TYPE_DATA;
} else if (slot->flags & PVA_FW_DMA_SLOT_FLAG_VMEM_VPUC_TABLE) { } else if ((slot->flags & PVA_FW_DMA_SLOT_FLAG_VMEM_VPUC_TABLE) != 0U) {
needed_sym_type = PVA_SYM_TYPE_VPUC_TABLE; needed_sym_type = PVA_SYM_TYPE_VPUC_TABLE;
} else { } else {
pva_kmd_log_err("Unexpected VMEM slot flags"); pva_kmd_log_err("Unexpected VMEM slot flags");
@@ -275,13 +414,16 @@ bind_static_vmem_slot(struct pva_dma_config_resource *dma_config,
goto out; goto out;
} }
#if defined(WAR_PVAAS16267) vpu_res = pva_kmd_peek_resource(dma_aux->res_table,
needed_sym_type = PVA_SYM_TYPE_DATA; dma_aux->vpu_bin_res_id);
#endif
vpu_bin = &pva_kmd_peek_resource(dma_aux->res_table, if (vpu_res == NULL) {
dma_aux->vpu_bin_res_id) pva_kmd_log_err("Failed to get VPU resource");
->vpu_bin; err = PVA_INVAL;
goto out;
}
vpu_bin = &vpu_res->vpu_bin;
sym = pva_kmd_get_symbol_with_type(&vpu_bin->symbol_table, sym = pva_kmd_get_symbol_with_type(&vpu_bin->symbol_table,
vmem_bd->addr.symbol_id, vmem_bd->addr.symbol_id,
needed_sym_type); needed_sym_type);
@@ -300,7 +442,7 @@ bind_static_vmem_slot(struct pva_dma_config_resource *dma_config,
} }
relocs = &static_relocs[slot->reloc_start_idx]; relocs = &static_relocs[slot->reloc_start_idx];
for (uint32_t i = 0; i < slot->reloc_count; i++) { for (i = 0; i < slot->reloc_count; i++) {
struct pva_fw_dma_reloc const *reloc = &relocs[i]; struct pva_fw_dma_reloc const *reloc = &relocs[i];
struct pva_fw_dma_descriptor *desc = &descs[reloc->desc_index]; struct pva_fw_dma_descriptor *desc = &descs[reloc->desc_index];
@@ -316,9 +458,12 @@ bind_static_vmem_slot(struct pva_dma_config_resource *dma_config,
goto out; goto out;
} }
/* CERT INT31-C: buffer_addr >> 6 cast to uint16_t then masked with 0x7FFF.
* The uint16_t cast naturally truncates to 16 bits, then mask keeps 15 bits.
* This is intentional for VMEM address computation. */
desc->frda = desc->frda =
((uint16_t)(buffer_addr >> 6U) + desc->frda) & ((uint16_t)(buffer_addr >> 6U) + desc->frda) &
0x7FFF; 0x7FFFU;
} }
} }
@@ -351,7 +496,7 @@ enum pva_error pva_kmd_bind_static_buffers(
struct pva_dma_static_binding const *binding = struct pva_dma_static_binding const *binding =
&static_bindings[slot_id]; &static_bindings[slot_id];
if (binding->type == PVA_DMA_STATIC_BINDING_DRAM) { if (binding->type == (uint8_t)PVA_DMA_STATIC_BINDING_DRAM) {
err = bind_static_dram_slot(fw_dma_cfg_hdr, dma_aux, err = bind_static_dram_slot(fw_dma_cfg_hdr, dma_aux,
st_slot, static_relocs, st_slot, static_relocs,
&binding->dram); &binding->dram);

View File

@@ -10,6 +10,7 @@
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#include "pva_math_utils.h" #include "pva_math_utils.h"
#include "pva_utils.h" #include "pva_utils.h"
#include "pva_kmd_limits.h"
struct pva_fw_dma_reloc_slot_info { struct pva_fw_dma_reloc_slot_info {
struct pva_fw_dma_slot *slots; struct pva_fw_dma_slot *slots;
@@ -51,7 +52,9 @@ validate_channel_mapping(struct pva_dma_config const *out_cfg,
for (uint8_t i = 0U; i < cfg_hdr->num_channels; i++) { for (uint8_t i = 0U; i < cfg_hdr->num_channels; i++) {
channel = &out_cfg->channels[i]; channel = &out_cfg->channels[i];
if ((channel->desc_index >= out_cfg->header.num_descriptors) || if ((channel->desc_index >= out_cfg->header.num_descriptors) ||
(pva_is_reserved_desc(channel->desc_index))) { (pva_is_reserved_desc(addu8(channel->desc_index,
cfg_hdr->base_descriptor,
&math_err)))) {
pva_kmd_log_err( pva_kmd_log_err(
"ERR: Invalid Channel Descriptor Index"); "ERR: Invalid Channel Descriptor Index");
return PVA_INVAL; return PVA_INVAL;
@@ -98,22 +101,22 @@ static bool is_valid_vpu_trigger_mode(const struct pva_dma_descriptor *desc)
bool valid = true; bool valid = true;
if (desc->trig_event_mode != 0U) { if (desc->trig_event_mode != 0U) {
switch (desc->trig_vpu_events) { switch (desc->trig_vpu_events) {
case PVA_DMA_NO_TRIG: case (uint8_t)PVA_DMA_NO_TRIG:
//HW Sequencer check //HW Sequencer check
break; break;
case PVA_DMA_TRIG_VPU_CFG: case (uint8_t)PVA_DMA_TRIG_VPU_CFG:
if (desc->src.transfer_mode != if (desc->src.transfer_mode !=
PVA_DMA_TRANS_MODE_VPUCFG) { (uint8_t)PVA_DMA_TRANS_MODE_VPUCFG) {
valid = false; valid = false;
} }
break; break;
case PVA_DMA_TRIG_READ0: case (uint8_t)PVA_DMA_TRIG_READ0:
case PVA_DMA_TRIG_READ1: case (uint8_t)PVA_DMA_TRIG_READ1:
case PVA_DMA_TRIG_READ2: case (uint8_t)PVA_DMA_TRIG_READ2:
case PVA_DMA_TRIG_READ3: case (uint8_t)PVA_DMA_TRIG_READ3:
case PVA_DMA_TRIG_READ4: case (uint8_t)PVA_DMA_TRIG_READ4:
case PVA_DMA_TRIG_READ5: case (uint8_t)PVA_DMA_TRIG_READ5:
case PVA_DMA_TRIG_READ6: case (uint8_t)PVA_DMA_TRIG_READ6:
if ((desc->src.transfer_mode != if ((desc->src.transfer_mode !=
(uint8_t)PVA_DMA_TRANS_MODE_VPUCFG) && (uint8_t)PVA_DMA_TRANS_MODE_VPUCFG) &&
(desc->dst.transfer_mode != (desc->dst.transfer_mode !=
@@ -121,13 +124,13 @@ static bool is_valid_vpu_trigger_mode(const struct pva_dma_descriptor *desc)
valid = false; valid = false;
} }
break; break;
case PVA_DMA_TRIG_WRITE0: case (uint8_t)PVA_DMA_TRIG_WRITE0:
case PVA_DMA_TRIG_WRITE1: case (uint8_t)PVA_DMA_TRIG_WRITE1:
case PVA_DMA_TRIG_WRITE2: case (uint8_t)PVA_DMA_TRIG_WRITE2:
case PVA_DMA_TRIG_WRITE3: case (uint8_t)PVA_DMA_TRIG_WRITE3:
case PVA_DMA_TRIG_WRITE4: case (uint8_t)PVA_DMA_TRIG_WRITE4:
case PVA_DMA_TRIG_WRITE5: case (uint8_t)PVA_DMA_TRIG_WRITE5:
case PVA_DMA_TRIG_WRITE6: case (uint8_t)PVA_DMA_TRIG_WRITE6:
if ((desc->src.transfer_mode != if ((desc->src.transfer_mode !=
(uint8_t)PVA_DMA_TRANS_MODE_VPUCFG) && (uint8_t)PVA_DMA_TRANS_MODE_VPUCFG) &&
(desc->src.transfer_mode != (desc->src.transfer_mode !=
@@ -173,6 +176,88 @@ static bool validate_src_dst_adv_val(const struct pva_dma_descriptor *desc,
return true; return true;
} }
/**
* @brief Validate DMA descriptor transfer control modes
*
* @details This function validates the source and destination transfer modes
* for a DMA descriptor to ensure they form a valid combination according to
* hardware constraints. It performs the following operations:
* - Validates source transfer mode (VMEM, DRAM, L2SRAM, VPUCFG)
* - For VPUCFG sources, skips destination validation (VPUCFG is special case)
* - For non-VPUCFG sources, validates destination transfer mode
* - Enforces MMIO destination only with VPUCFG source
* - Restricts TCM destination to test mode only
* - Ensures transfer mode combinations are hardware-compatible
*
* Valid transfer mode combinations:
* - VMEM/DRAM/L2SRAM -> VMEM/DRAM/L2SRAM (standard transfers)
* - VPUCFG -> Any (VPU configuration transfers - validated separately)
* - Non-VPUCFG -> MMIO (rejected as invalid)
* - Any -> TCM (only in test mode)
*
* @param[in] desc Pointer to DMA descriptor to validate
* Valid value: non-null, properly initialized descriptor
*
* @retval PVA_SUCCESS Transfer modes validated successfully
* @retval PVA_INVAL Invalid transfer mode or unsupported combination
*/
static enum pva_error
validate_dma_desc_trans_cntl0(const struct pva_dma_descriptor *desc)
{
enum pva_error err = PVA_SUCCESS;
bool valid_src = false;
/* Validate source transfer mode */
switch (desc->src.transfer_mode) {
case (uint8_t)PVA_DMA_TRANS_MODE_VMEM:
valid_src = true;
break;
case (uint8_t)PVA_DMA_TRANS_MODE_DRAM:
valid_src = true;
break;
case (uint8_t)PVA_DMA_TRANS_MODE_L2SRAM:
valid_src = true;
break;
case (uint8_t)PVA_DMA_TRANS_MODE_VPUCFG:
valid_src = true;
break;
default:
valid_src = false;
break;
}
if (!valid_src) {
err = PVA_INVAL;
}
/* For VPUCFG source, skip destination validation (early exit) */
if ((err != PVA_SUCCESS) ||
(desc->src.transfer_mode == (uint8_t)PVA_DMA_TRANS_MODE_VPUCFG)) {
/* Function exit point for VPUCFG or error cases */
} else {
/* Validate destination transfer mode for non-VPUCFG sources */
switch (desc->dst.transfer_mode) {
case (uint8_t)PVA_DMA_TRANS_MODE_L2SRAM:
err = PVA_SUCCESS;
break;
case (uint8_t)PVA_DMA_TRANS_MODE_VMEM:
err = PVA_SUCCESS;
break;
case (uint8_t)PVA_DMA_TRANS_MODE_DRAM:
err = PVA_SUCCESS;
break;
case (uint8_t)PVA_DMA_TRANS_MODE_MMIO:
/* MMIO only valid with VPUCFG source (already filtered out) */
err = PVA_INVAL;
break;
default:
err = PVA_INVAL;
break;
}
}
return err;
}
static enum pva_error static enum pva_error
validate_dma_desc_trans_cntl2(const struct pva_dma_descriptor *desc) validate_dma_desc_trans_cntl2(const struct pva_dma_descriptor *desc)
{ {
@@ -187,12 +272,13 @@ validate_dma_desc_trans_cntl2(const struct pva_dma_descriptor *desc)
static enum pva_error static enum pva_error
validate_descriptor(const struct pva_dma_descriptor *desc, validate_descriptor(const struct pva_dma_descriptor *desc,
struct pva_dma_config_header const *cfg_hdr) struct pva_dma_config_header const *cfg_hdr,
bool relax_dim3_check)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
err = validate_padding(desc); err = validate_padding(desc);
if ((desc->dst.transfer_mode == PVA_DMA_TRANS_MODE_VMEM) && if ((desc->dst.transfer_mode == (uint8_t)PVA_DMA_TRANS_MODE_VMEM) &&
(err != PVA_SUCCESS)) { (err != PVA_SUCCESS)) {
return err; return err;
} }
@@ -203,12 +289,16 @@ validate_descriptor(const struct pva_dma_descriptor *desc,
} }
/** Check src/dstADV values with respect to ECET bits */ /** Check src/dstADV values with respect to ECET bits */
if (false == validate_src_dst_adv_val(desc, false)) { if (false == validate_src_dst_adv_val(desc, relax_dim3_check)) {
pva_kmd_log_err( pva_kmd_log_err(
"Invalid src/dst ADV values with respect to ECET"); "Invalid src/dst ADV values with respect to ECET");
return PVA_INVAL; return PVA_INVAL;
} }
if (PVA_SUCCESS != validate_dma_desc_trans_cntl0(desc)) {
pva_kmd_log_err("Bad trans cntl 0");
return PVA_INVAL;
}
/* DMA_DESC_TRANS CNTL2 */ /* DMA_DESC_TRANS CNTL2 */
if (PVA_SUCCESS != validate_dma_desc_trans_cntl2(desc)) { if (PVA_SUCCESS != validate_dma_desc_trans_cntl2(desc)) {
pva_kmd_log_err("Bad trans cntl 2"); pva_kmd_log_err("Bad trans cntl 2");
@@ -216,9 +306,11 @@ validate_descriptor(const struct pva_dma_descriptor *desc,
} }
/* DMA_DESC_LDID */ /* DMA_DESC_LDID */
if ((desc->link_desc_id > cfg_hdr->num_descriptors) || if ((desc->link_desc_id - cfg_hdr->base_descriptor >
((desc->link_desc_id != 0) && cfg_hdr->num_descriptors) ||
pva_is_reserved_desc(desc->link_desc_id - PVA_DMA_DESC_ID_BASE))) { ((desc->link_desc_id != 0U) &&
pva_is_reserved_desc(desc->link_desc_id -
(uint8_t)PVA_DMA_DESC_ID_BASE))) {
pva_kmd_log_err("ERR: Invalid linker Desc ID"); pva_kmd_log_err("ERR: Invalid linker Desc ID");
return PVA_INVAL; return PVA_INVAL;
} }
@@ -233,6 +325,57 @@ struct pva_kmd_offset_pairs {
#define PVA_KMD_DMA_CONFIG_ARRAY_COUNT 4U #define PVA_KMD_DMA_CONFIG_ARRAY_COUNT 4U
static bool
validate_dma_config_bounds(struct pva_dma_config_header const *cfg_hdr,
struct pva_kmd_hw_constants const *hw_consts)
{
bool is_valid = true;
if ((((uint32_t)cfg_hdr->base_descriptor +
(uint32_t)cfg_hdr->num_descriptors) >
hw_consts->n_dma_descriptors) ||
(((uint32_t)cfg_hdr->base_channel +
(uint32_t)cfg_hdr->num_channels) >
(hw_consts->n_user_dma_channels + 1U)) ||
(((uint32_t)cfg_hdr->base_hwseq_word +
(uint32_t)cfg_hdr->num_hwseq_words) > hw_consts->n_hwseq_words) ||
(cfg_hdr->num_static_slots > PVA_KMD_MAX_NUM_DMA_SLOTS) ||
(cfg_hdr->num_dynamic_slots > PVA_KMD_MAX_NUM_DMA_RELOCS) ||
(cfg_hdr->base_channel == 0U)) {
is_valid = false;
}
return is_valid;
}
static bool validate_dma_offsets(struct pva_kmd_offset_pairs const *offsets,
uint32_t dma_config_size)
{
bool is_valid = true;
uint32_t i;
//Validate:
// 1. All start offsets are aligned to 8 bytes
// 2. All end offsets are within the dma_config_size
// Note: We do not check if the ranges overlap because we do not modify the buffer in place.
for (i = 0; i < PVA_KMD_DMA_CONFIG_ARRAY_COUNT; i++) {
if ((offsets[i].start % 8U) != 0U) {
pva_kmd_log_err(
"DMA config field offset is not aligned to 8 bytes");
is_valid = false;
goto out;
}
if (offsets[i].end > dma_config_size) {
pva_kmd_log_err("DMA config field is out of bounds");
is_valid = false;
goto out;
}
}
out:
return is_valid;
}
static bool static bool
is_dma_config_header_valid(struct pva_ops_dma_config_register const *ops_hdr, is_dma_config_header_valid(struct pva_ops_dma_config_register const *ops_hdr,
uint32_t dma_config_size, uint32_t dma_config_size,
@@ -241,31 +384,27 @@ is_dma_config_header_valid(struct pva_ops_dma_config_register const *ops_hdr,
struct pva_kmd_offset_pairs offsets[PVA_KMD_DMA_CONFIG_ARRAY_COUNT]; struct pva_kmd_offset_pairs offsets[PVA_KMD_DMA_CONFIG_ARRAY_COUNT];
struct pva_dma_config_header const *cfg_hdr; struct pva_dma_config_header const *cfg_hdr;
pva_math_error math_err = MATH_OP_SUCCESS; pva_math_error math_err = MATH_OP_SUCCESS;
bool is_valid = true;
if (dma_config_size < sizeof(*ops_hdr)) { if (dma_config_size < sizeof(*ops_hdr)) {
pva_kmd_log_err("DMA configuration too small"); pva_kmd_log_err("DMA configuration too small");
return PVA_INVAL; is_valid = false;
goto out;
} }
cfg_hdr = &ops_hdr->dma_config_header; cfg_hdr = &ops_hdr->dma_config_header;
if (((cfg_hdr->base_descriptor + cfg_hdr->num_descriptors) > if (!validate_dma_config_bounds(cfg_hdr, hw_consts)) {
hw_consts->n_dma_descriptors) || is_valid = false;
((cfg_hdr->base_channel + cfg_hdr->num_channels) > goto out;
(hw_consts->n_user_dma_channels + 1U)) ||
((cfg_hdr->base_hwseq_word + cfg_hdr->num_hwseq_words) >
hw_consts->n_hwseq_words) ||
(cfg_hdr->num_static_slots > PVA_KMD_MAX_NUM_DMA_SLOTS) ||
(cfg_hdr->num_dynamic_slots > PVA_KMD_MAX_NUM_DMA_RELOCS) ||
(cfg_hdr->base_channel == 0U)) {
return false;
} }
offsets[0].start = ops_hdr->channels_offset; offsets[0].start = ops_hdr->channels_offset;
offsets[0].end = addu32( offsets[0].end = addu32(
ops_hdr->channels_offset, ops_hdr->channels_offset,
align8_u32(mulu32(cfg_hdr->num_channels, align8_u32(mulu32(cfg_hdr->num_channels,
sizeof(struct pva_dma_channel), &math_err), (uint32_t)sizeof(struct pva_dma_channel),
&math_err),
&math_err), &math_err),
&math_err); &math_err);
@@ -273,59 +412,54 @@ is_dma_config_header_valid(struct pva_ops_dma_config_register const *ops_hdr,
offsets[1].end = addu32( offsets[1].end = addu32(
ops_hdr->descriptors_offset, ops_hdr->descriptors_offset,
align8_u32(mulu32(cfg_hdr->num_descriptors, align8_u32(mulu32(cfg_hdr->num_descriptors,
sizeof(struct pva_dma_descriptor), &math_err), (uint32_t)sizeof(struct pva_dma_descriptor),
&math_err),
&math_err), &math_err),
&math_err); &math_err);
offsets[2].start = ops_hdr->hwseq_words_offset; offsets[2].start = ops_hdr->hwseq_words_offset;
offsets[2].end = addu32(ops_hdr->hwseq_words_offset, offsets[2].end =
align8_u32(mulu32(cfg_hdr->num_hwseq_words, addu32(ops_hdr->hwseq_words_offset,
sizeof(uint32_t), &math_err), align8_u32(mulu32(cfg_hdr->num_hwseq_words,
&math_err), (uint32_t)sizeof(uint32_t), &math_err),
&math_err); &math_err),
&math_err);
offsets[3].start = ops_hdr->static_bindings_offset; offsets[3].start = ops_hdr->static_bindings_offset;
offsets[3].end = offsets[3].end =
addu32(ops_hdr->static_bindings_offset, addu32(ops_hdr->static_bindings_offset,
align8_u32(mulu32(cfg_hdr->num_static_slots, align8_u32(mulu32(cfg_hdr->num_static_slots,
sizeof(struct pva_dma_static_binding), (uint32_t)sizeof(
struct pva_dma_static_binding),
&math_err), &math_err),
&math_err), &math_err),
&math_err); &math_err);
if (math_err != MATH_OP_SUCCESS) { if (math_err != MATH_OP_SUCCESS) {
pva_kmd_log_err("DMA config field offset math error"); pva_kmd_log_err("DMA config field offset math error");
return false; is_valid = false;
} goto out;
//Validate:
// 1. All start offsets are aligned to 8 bytes
// 2. All end offsets are within the dma_config_size
// Note: We do not check if the ranges overlap because we do not modify the buffer in place.
for (uint32_t i = 0; i < PVA_KMD_DMA_CONFIG_ARRAY_COUNT; i++) {
if (offsets[i].start % 8 != 0) {
pva_kmd_log_err(
"DMA config field offset is not aligned to 8 bytes");
return false;
}
if (offsets[i].end > dma_config_size) {
pva_kmd_log_err("DMA config field is out of bounds");
return false;
}
} }
return true; if (!validate_dma_offsets(offsets, dma_config_size)) {
is_valid = false;
}
out:
return is_valid;
} }
enum pva_error enum pva_error pva_kmd_parse_dma_config(
pva_kmd_parse_dma_config(const struct pva_ops_dma_config_register *ops_hdr, const struct pva_ops_dma_config_register *ops_hdr,
uint32_t dma_config_size, uint32_t dma_config_size, struct pva_dma_config *out_cfg,
struct pva_dma_config *out_cfg, struct pva_kmd_hw_constants const *hw_consts, bool skip_validation)
struct pva_kmd_hw_constants const *hw_consts)
{ {
if (!(is_dma_config_header_valid(ops_hdr, dma_config_size, if (!skip_validation) { // Skip validation for PFSD and test mode
hw_consts))) { if (!(is_dma_config_header_valid(ops_hdr, dma_config_size,
pva_kmd_log_err("Invalid PVA DMA Configuration Header"); hw_consts))) {
return PVA_INVAL; pva_kmd_log_err("Invalid PVA DMA Configuration Header");
return PVA_INVAL;
}
} }
out_cfg->header = ops_hdr->dma_config_header; out_cfg->header = ops_hdr->dma_config_header;
@@ -346,46 +480,59 @@ pva_kmd_parse_dma_config(const struct pva_ops_dma_config_register *ops_hdr,
} }
static enum pva_error static enum pva_error
validate_descriptors(const struct pva_dma_config *dma_config) validate_descriptors(const struct pva_dma_config *dma_config,
uint64_t const *hw_dma_descs_mask)
{ {
uint32_t i = 0U; uint8_t i = 0U;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
const struct pva_dma_config_header *cfg_hdr = &dma_config->header; const struct pva_dma_config_header *cfg_hdr = &dma_config->header;
const struct pva_dma_descriptor *desc; const struct pva_dma_descriptor *desc;
bool relax_dim3_check = true;
uint8_t desc_id;
pva_math_error math_err = MATH_OP_SUCCESS;
for (i = 0; i < cfg_hdr->num_descriptors; i++) { for (i = 0U; i < cfg_hdr->num_descriptors; i++) {
if (pva_is_reserved_desc(i)) { desc_id = addu8(i, cfg_hdr->base_descriptor, &math_err);
if (pva_is_reserved_desc(desc_id)) {
// skip over the reserved descriptor range // skip over the reserved descriptor range
i = PVA_RESERVED_DESCRIPTORS_END;
continue; continue;
} }
relax_dim3_check =
((hw_dma_descs_mask[desc_id / 64ULL] &
(1ULL << (desc_id & MAX_DESC_ID))) != 0ULL);
desc = &dma_config->descriptors[i]; desc = &dma_config->descriptors[i];
err = validate_descriptor(desc, cfg_hdr); err = validate_descriptor(desc, cfg_hdr, relax_dim3_check);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
return err; return err;
} }
} }
if (math_err != MATH_OP_SUCCESS) {
pva_kmd_log_err("validate_descriptors math error");
return PVA_ERR_MATH_OP;
}
return err; return err;
} }
enum pva_error enum pva_error
pva_kmd_validate_dma_config(struct pva_dma_config const *dma_config, pva_kmd_validate_dma_config(struct pva_dma_config const *dma_cfg,
struct pva_kmd_hw_constants const *hw_consts, struct pva_kmd_hw_constants const *hw_consts,
struct pva_kmd_dma_access *access_sizes, struct pva_kmd_dma_access *access_sizes,
uint64_t *hw_dma_descs_mask) uint64_t *hw_dma_descs_mask)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
err = validate_channel_mapping(dma_config, hw_consts); err = validate_channel_mapping(dma_cfg, hw_consts);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err("Bad Channels"); pva_kmd_log_err("Bad Channels");
return err; return err;
} }
if (dma_config->header.num_hwseq_words != 0U) { if (dma_cfg->header.num_hwseq_words != 0U) {
err = validate_hwseq(dma_config, hw_consts, access_sizes, err = validate_hwseq(dma_cfg, hw_consts, access_sizes,
hw_dma_descs_mask); hw_dma_descs_mask);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err("Bad HW Sequencer Blob"); pva_kmd_log_err("Bad HW Sequencer Blob");
@@ -393,7 +540,7 @@ pva_kmd_validate_dma_config(struct pva_dma_config const *dma_config,
} }
} }
err = validate_descriptors(dma_config); err = validate_descriptors(dma_cfg, hw_dma_descs_mask);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err("Bad Descriptors"); pva_kmd_log_err("Bad Descriptors");
return err; return err;
@@ -402,6 +549,98 @@ pva_kmd_validate_dma_config(struct pva_dma_config const *dma_config,
return err; return err;
} }
static enum pva_error
use_vpu_bin_resource(struct pva_dma_config const *dma_cfg,
struct pva_kmd_dma_resource_aux *dma_aux,
struct pva_kmd_vpu_bin_resource **vpu_bin)
{
enum pva_error err = PVA_SUCCESS;
struct pva_kmd_resource_record *vpu_bin_rec;
*vpu_bin = NULL;
if (dma_cfg->header.vpu_exec_resource_id == PVA_RESOURCE_ID_INVALID) {
goto out;
}
vpu_bin_rec = pva_kmd_use_resource_unsafe(
dma_aux->res_table, dma_cfg->header.vpu_exec_resource_id);
if (vpu_bin_rec == NULL) {
pva_kmd_log_err(
"VPU exec resource id used by DMA config does not exist");
err = PVA_INVAL;
goto out;
}
dma_aux->vpu_bin_res_id = dma_cfg->header.vpu_exec_resource_id;
if (vpu_bin_rec->type != PVA_RESOURCE_TYPE_EXEC_BIN) {
pva_kmd_log_err(
"Invalid VPU exec resource id used by DMA config");
err = PVA_INVAL;
pva_kmd_drop_resource_unsafe(dma_aux->res_table,
dma_aux->vpu_bin_res_id);
dma_aux->vpu_bin_res_id = PVA_RESOURCE_ID_INVALID;
goto out;
}
*vpu_bin = &vpu_bin_rec->vpu_bin;
out:
return err;
}
static enum pva_error
process_static_dram_binding(struct pva_kmd_dma_resource_aux *dma_aux,
struct pva_dma_static_binding const *slot_buf)
{
enum pva_error err = PVA_SUCCESS;
struct pva_kmd_resource_record *rec;
rec = pva_kmd_use_resource_unsafe(dma_aux->res_table,
slot_buf->dram.resource_id);
if (rec == NULL) {
pva_kmd_log_err("DRAM buffers used by DMA config do not exist");
err = PVA_INVAL;
goto out;
}
dma_aux->static_dram_res_ids[dma_aux->dram_res_count] =
slot_buf->dram.resource_id;
dma_aux->dram_res_count = safe_addu32(dma_aux->dram_res_count, 1U);
if (rec->type != PVA_RESOURCE_TYPE_DRAM) {
pva_kmd_log_err("Invalid DRAM resource id used DMA config");
err = PVA_INVAL;
}
out:
return err;
}
static enum pva_error
process_static_vmem_binding(struct pva_kmd_vpu_bin_resource *vpu_bin,
struct pva_dma_static_binding const *slot_buf)
{
enum pva_error err = PVA_SUCCESS;
if (vpu_bin == NULL) {
pva_kmd_log_err(
"VPU bin resource not found for static VMEM buffer");
err = PVA_INVAL;
goto out;
}
if (pva_kmd_get_symbol(&vpu_bin->symbol_table,
slot_buf->vmem.addr.symbol_id) == NULL) {
pva_kmd_log_err("Invalid VMEM symbol ID");
err = PVA_INVAL;
}
out:
return err;
}
enum pva_error enum pva_error
pva_kmd_dma_use_resources(struct pva_dma_config const *dma_cfg, pva_kmd_dma_use_resources(struct pva_dma_config const *dma_cfg,
struct pva_kmd_dma_resource_aux *dma_aux) struct pva_kmd_dma_resource_aux *dma_aux)
@@ -411,27 +650,9 @@ pva_kmd_dma_use_resources(struct pva_dma_config const *dma_cfg,
uint32_t i; uint32_t i;
/* Increment reference count for VPU bin */ /* Increment reference count for VPU bin */
if (dma_cfg->header.vpu_exec_resource_id != PVA_RESOURCE_ID_INVALID) { err = use_vpu_bin_resource(dma_cfg, dma_aux, &vpu_bin);
struct pva_kmd_resource_record *vpu_bin_rec; if (err != PVA_SUCCESS) {
goto err_out;
vpu_bin_rec = pva_kmd_use_resource_unsafe(
dma_aux->res_table,
dma_cfg->header.vpu_exec_resource_id);
if (vpu_bin_rec == NULL) {
pva_kmd_log_err(
"VPU exec resource id used by DMA config does not exist");
err = PVA_INVAL;
goto err_out;
}
dma_aux->vpu_bin_res_id = dma_cfg->header.vpu_exec_resource_id;
if (vpu_bin_rec->type != PVA_RESOURCE_TYPE_EXEC_BIN) {
pva_kmd_log_err(
"Invalid VPU exec resource id used by DMA config");
err = PVA_INVAL;
goto drop_vpu_bin;
}
vpu_bin = &vpu_bin_rec->vpu_bin;
} }
/* Increment reference count for all static DRAM buffers; For static /* Increment reference count for all static DRAM buffers; For static
@@ -440,58 +661,31 @@ pva_kmd_dma_use_resources(struct pva_dma_config const *dma_cfg,
struct pva_dma_static_binding const *slot_buf = struct pva_dma_static_binding const *slot_buf =
&dma_cfg->static_bindings[i]; &dma_cfg->static_bindings[i];
if (slot_buf->type == PVA_DMA_STATIC_BINDING_DRAM) { if (slot_buf->type == (uint8_t)PVA_DMA_STATIC_BINDING_DRAM) {
struct pva_kmd_resource_record *rec; err = process_static_dram_binding(dma_aux, slot_buf);
if (err != PVA_SUCCESS) {
rec = pva_kmd_use_resource_unsafe( goto drop_resources;
dma_aux->res_table, slot_buf->dram.resource_id);
if (rec == NULL) {
pva_kmd_log_err(
"DRAM buffers used by DMA config do not exist");
err = PVA_INVAL;
goto drop_dram;
} }
} else if (slot_buf->type ==
dma_aux->static_dram_res_ids[dma_aux->dram_res_count] = (uint8_t)PVA_DMA_STATIC_BINDING_VMEM) {
slot_buf->dram.resource_id; err = process_static_vmem_binding(vpu_bin, slot_buf);
dma_aux->dram_res_count = if (err != PVA_SUCCESS) {
safe_addu32(dma_aux->dram_res_count, 1U); goto drop_resources;
if (rec->type != PVA_RESOURCE_TYPE_DRAM) {
pva_kmd_log_err(
"Invalid DRAM resource id used DMA config");
err = PVA_INVAL;
goto drop_dram;
}
} else if (slot_buf->type == PVA_DMA_STATIC_BINDING_VMEM) {
if (vpu_bin == NULL) {
pva_kmd_log_err(
"VPU bin resource not found for static VMEM buffer");
err = PVA_INVAL;
goto drop_dram;
}
if (pva_kmd_get_symbol(&vpu_bin->symbol_table,
slot_buf->vmem.addr.symbol_id) ==
NULL) {
pva_kmd_log_err("Invalid VMEM symbol ID");
err = PVA_INVAL;
goto drop_dram;
} }
} else { } else {
pva_kmd_log_err("Invalid slot buffer type"); pva_kmd_log_err("Invalid slot buffer type");
err = PVA_INVAL; err = PVA_INVAL;
goto drop_dram; goto drop_resources;
} }
} }
return PVA_SUCCESS; return PVA_SUCCESS;
drop_dram: drop_resources:
for (i = 0; i < dma_aux->dram_res_count; i++) { for (i = 0; i < dma_aux->dram_res_count; i++) {
pva_kmd_drop_resource_unsafe(dma_aux->res_table, pva_kmd_drop_resource_unsafe(dma_aux->res_table,
dma_aux->static_dram_res_ids[i]); dma_aux->static_dram_res_ids[i]);
} }
drop_vpu_bin: /* Drop VPU bin if it was acquired */
if (dma_aux->vpu_bin_res_id != PVA_RESOURCE_ID_INVALID) { if (dma_aux->vpu_bin_res_id != PVA_RESOURCE_ID_INVALID) {
pva_kmd_drop_resource_unsafe(dma_aux->res_table, pva_kmd_drop_resource_unsafe(dma_aux->res_table,
dma_aux->vpu_bin_res_id); dma_aux->vpu_bin_res_id);
@@ -509,13 +703,13 @@ static uint16_t get_slot_flag(uint8_t transfer_mode, bool cb_enable,
bool is_dst) bool is_dst)
{ {
uint16_t flags = 0; uint16_t flags = 0;
if (transfer_mode == PVA_DMA_TRANS_MODE_VMEM) { if (transfer_mode == (uint8_t)PVA_DMA_TRANS_MODE_VMEM) {
flags |= PVA_FW_DMA_SLOT_FLAG_VMEM_DATA; flags |= PVA_FW_DMA_SLOT_FLAG_VMEM_DATA;
} else if (transfer_mode == PVA_DMA_TRANS_MODE_L2SRAM) { } else if (transfer_mode == (uint8_t)PVA_DMA_TRANS_MODE_L2SRAM) {
flags |= PVA_FW_DMA_SLOT_FLAG_L2SRAM; flags |= PVA_FW_DMA_SLOT_FLAG_L2SRAM;
} else if (transfer_mode == PVA_DMA_TRANS_MODE_DRAM) { } else if (transfer_mode == (uint8_t)PVA_DMA_TRANS_MODE_DRAM) {
flags |= PVA_FW_DMA_SLOT_FLAG_DRAM; flags |= PVA_FW_DMA_SLOT_FLAG_DRAM;
} else if (transfer_mode == PVA_DMA_TRANS_MODE_VPUCFG) { } else if (transfer_mode == (uint8_t)PVA_DMA_TRANS_MODE_VPUCFG) {
flags |= PVA_FW_DMA_SLOT_FLAG_VMEM_VPUC_TABLE; flags |= PVA_FW_DMA_SLOT_FLAG_VMEM_VPUC_TABLE;
} }
@@ -523,11 +717,11 @@ static uint16_t get_slot_flag(uint8_t transfer_mode, bool cb_enable,
flags |= PVA_FW_DMA_SLOT_FLAG_CB; flags |= PVA_FW_DMA_SLOT_FLAG_CB;
} }
if (is_dst) { if (is_dst) {
flags |= PVA_INSERT(PVA_ACCESS_WO, flags |= PVA_INSERT((uint32_t)PVA_ACCESS_WO,
PVA_FW_DMA_SLOT_FLAG_ACCESS_MSB, PVA_FW_DMA_SLOT_FLAG_ACCESS_MSB,
PVA_FW_DMA_SLOT_FLAG_ACCESS_LSB); PVA_FW_DMA_SLOT_FLAG_ACCESS_LSB);
} else { } else {
flags |= PVA_INSERT(PVA_ACCESS_RO, flags |= PVA_INSERT((uint32_t)PVA_ACCESS_RO,
PVA_FW_DMA_SLOT_FLAG_ACCESS_MSB, PVA_FW_DMA_SLOT_FLAG_ACCESS_MSB,
PVA_FW_DMA_SLOT_FLAG_ACCESS_LSB); PVA_FW_DMA_SLOT_FLAG_ACCESS_LSB);
} }
@@ -541,14 +735,14 @@ static void update_reloc_count(uint16_t slot, uint8_t transfer_mode,
struct pva_fw_dma_slot *out_dyn_slots, struct pva_fw_dma_slot *out_dyn_slots,
uint16_t num_dyn_slots, bool is_dst) uint16_t num_dyn_slots, bool is_dst)
{ {
uint8_t slot_id = get_slot_id(slot); uint16_t slot_id = get_slot_id(slot);
if (slot & PVA_DMA_DYNAMIC_SLOT) { if ((slot & PVA_DMA_DYNAMIC_SLOT) != 0U) {
out_dyn_slots[slot_id].reloc_count = out_dyn_slots[slot_id].reloc_count =
safe_addu16(out_dyn_slots[slot_id].reloc_count, 1U); safe_addu16(out_dyn_slots[slot_id].reloc_count, 1U);
out_dyn_slots[slot_id].flags |= out_dyn_slots[slot_id].flags |=
get_slot_flag(transfer_mode, cb_enable, is_dst); get_slot_flag(transfer_mode, cb_enable, is_dst);
} else if (slot & PVA_DMA_STATIC_SLOT) { } else if ((slot & PVA_DMA_STATIC_SLOT) != 0U) {
out_static_slots[slot_id].reloc_count = out_static_slots[slot_id].reloc_count =
safe_addu16(out_static_slots[slot_id].reloc_count, 1U); safe_addu16(out_static_slots[slot_id].reloc_count, 1U);
out_static_slots[slot_id].flags |= out_static_slots[slot_id].flags |=
@@ -562,31 +756,41 @@ static void count_relocs(struct pva_dma_config const *dma_cfg,
struct pva_fw_dma_slot *out_dyn_slots, struct pva_fw_dma_slot *out_dyn_slots,
uint16_t num_dyn_slots) uint16_t num_dyn_slots)
{ {
uint8_t i; uint8_t i = 0U;
const struct pva_dma_descriptor *desc; const struct pva_dma_descriptor *desc;
for (i = 0U; i < dma_cfg->header.num_descriptors; i++) { /* CERT INT30-C: Use safe arithmetic to prevent potential wrap */
if (pva_is_reserved_desc(i)) { while (i < dma_cfg->header.num_descriptors) {
uint8_t desc_id =
safe_addu8(i, dma_cfg->header.base_descriptor);
if (pva_is_reserved_desc(desc_id)) {
// skip over the reserved descriptor range // skip over the reserved descriptor range
i = PVA_RESERVED_DESCRIPTORS_END; /* CERT INT31-C: Use safe subtract to handle underflow gracefully */
i = safe_subu8(PVA_RESERVED_DESCRIPTORS_END,
dma_cfg->header.base_descriptor);
/* Skip to first descriptor after reserved range */
i = safe_addu8(i, 1U);
continue; continue;
} }
desc = &dma_cfg->descriptors[i]; desc = &dma_cfg->descriptors[i];
update_reloc_count(desc->src.slot, desc->src.transfer_mode, update_reloc_count(desc->src.slot, desc->src.transfer_mode,
desc->src.cb_enable, out_static_slots, (bool)desc->src.cb_enable, out_static_slots,
num_static_slots, out_dyn_slots, num_static_slots, out_dyn_slots,
num_dyn_slots, false); num_dyn_slots, false);
update_reloc_count(desc->dst.slot, desc->dst.transfer_mode, update_reloc_count(desc->dst.slot, desc->dst.transfer_mode,
desc->dst.cb_enable, out_static_slots, (bool)desc->dst.cb_enable, out_static_slots,
num_static_slots, out_dyn_slots, num_static_slots, out_dyn_slots,
num_dyn_slots, true); num_dyn_slots, true);
update_reloc_count(desc->dst2_slot, desc->dst.transfer_mode, update_reloc_count(desc->dst2_slot, desc->dst.transfer_mode,
desc->dst.cb_enable, out_static_slots, (bool)desc->dst.cb_enable, out_static_slots,
num_static_slots, out_dyn_slots, num_static_slots, out_dyn_slots,
num_dyn_slots, true); num_dyn_slots, true);
/* CERT INT30-C: Use safe addition to prevent wrap */
i = safe_addu8(i, 1U);
} }
} }
@@ -599,18 +803,26 @@ static void write_one_reloc(uint8_t ch_index, uint32_t desc_index,
uint16_t slot_id = get_slot_id(slot); uint16_t slot_id = get_slot_id(slot);
uint16_t reloc_id = safe_addu16(info->slots[slot_id].reloc_start_idx, uint16_t reloc_id = safe_addu16(info->slots[slot_id].reloc_start_idx,
info->reloc_off[slot_id]); info->reloc_off[slot_id]);
int64_t old_start_addr = info->slots[slot_id].start_addr; int64_t old_start_addr = info->slots[slot_id].start_addr;
int64_t old_end_addr = info->slots[slot_id].end_addr; int64_t old_end_addr = info->slots[slot_id].end_addr;
uint32_t shift_amount = (uint32_t)ch_index & 0x0FU;
uint32_t shift_result = (uint32_t)1U << shift_amount;
uint16_t ch_mask_u16;
uint16_t new_mask;
info->slots[slot_id].start_addr = info->slots[slot_id].start_addr =
mins64(access_entry->start_addr, old_start_addr); mins64(access_entry->start_addr, old_start_addr);
info->slots[slot_id].end_addr = info->slots[slot_id].end_addr =
maxs64(access_entry->end_addr, old_end_addr); maxs64(access_entry->end_addr, old_end_addr);
info->slots[slot_id].ch_use_mask |= (1U << (ch_index & 0x1FU)); ASSERT(shift_result <= (uint32_t)U16_MAX);
ch_mask_u16 = (uint16_t)shift_result;
new_mask = info->slots[slot_id].ch_use_mask | ch_mask_u16;
info->slots[slot_id].ch_use_mask = new_mask;
info->relocs[reloc_id].desc_index = desc_index; /* desc_index field is uint8_t - validated by DMA config validation */
ASSERT(desc_index <= (uint32_t)U8_MAX);
info->relocs[reloc_id].desc_index = (uint8_t)desc_index;
info->relocs[reloc_id].field = reloc_field; info->relocs[reloc_id].field = reloc_field;
info->reloc_off[slot_id] = safe_addu8(info->reloc_off[slot_id], 1U); info->reloc_off[slot_id] = safe_addu8(info->reloc_off[slot_id], 1U);
} }
@@ -621,10 +833,10 @@ static void handle_reloc(uint16_t slot, uint8_t transfer_mode,
uint8_t reloc_field, uint8_t ch_index, uint8_t reloc_field, uint8_t ch_index,
uint8_t desc_index) uint8_t desc_index)
{ {
if (slot & PVA_DMA_DYNAMIC_SLOT) { if ((slot & PVA_DMA_DYNAMIC_SLOT) != 0U) {
write_one_reloc(ch_index, desc_index, slot, transfer_mode, write_one_reloc(ch_index, desc_index, slot, transfer_mode,
reloc_field, &rel_info->dyn_slot, access_entry); reloc_field, &rel_info->dyn_slot, access_entry);
} else if (slot & PVA_DMA_STATIC_SLOT) { } else if ((slot & PVA_DMA_STATIC_SLOT) != 0U) {
write_one_reloc(ch_index, desc_index, slot, transfer_mode, write_one_reloc(ch_index, desc_index, slot, transfer_mode,
reloc_field, &rel_info->static_slot, reloc_field, &rel_info->static_slot,
access_entry); access_entry);
@@ -636,7 +848,7 @@ static void write_relocs(const struct pva_dma_config *dma_cfg,
struct pva_fw_dma_reloc_slots *rel_info, struct pva_fw_dma_reloc_slots *rel_info,
uint8_t const *desc_to_ch) uint8_t const *desc_to_ch)
{ {
uint32_t i; uint8_t i;
uint16_t start_idx = 0U; uint16_t start_idx = 0U;
const struct pva_dma_descriptor *desc = NULL; const struct pva_dma_descriptor *desc = NULL;
uint8_t ch_index = 0U; uint8_t ch_index = 0U;
@@ -653,9 +865,9 @@ static void write_relocs(const struct pva_dma_config *dma_cfg,
} }
for (i = 0U; i < dma_cfg->header.num_descriptors; i++) { for (i = 0U; i < dma_cfg->header.num_descriptors; i++) {
if (pva_is_reserved_desc(i)) { if (pva_is_reserved_desc(
safe_addu8(i, dma_cfg->header.base_descriptor))) {
// skip over the reserved descriptor range // skip over the reserved descriptor range
i = PVA_RESERVED_DESCRIPTORS_END;
continue; continue;
} }
desc = &dma_cfg->descriptors[i]; desc = &dma_cfg->descriptors[i];
@@ -763,16 +975,20 @@ static enum pva_error get_access_size(const struct pva_dma_descriptor *desc,
end += adds64((int64_t)dim_offset_U, (int64_t)tx, &math_err); end += adds64((int64_t)dim_offset_U, (int64_t)tx, &math_err);
// 3rd dim // 3rd dim
// 3rd dim dim_offset =
dim_offset = muls32((attr->adv1), (int32_t)(attr->rpt1), &math_err); muls32((int32_t)(attr->adv1), (int32_t)(attr->rpt1), &math_err);
start += mins32(dim_offset, 0); start += mins32(dim_offset, 0);
end += maxs32(dim_offset, 0); end += maxs32(dim_offset, 0);
// 4th dim // 4th dim
dim_offset = muls32((attr->adv2), (int32_t)(attr->rpt2), &math_err); dim_offset =
muls32((int32_t)(attr->adv2), (int32_t)(attr->rpt2), &math_err);
start += mins32(dim_offset, 0); start += mins32(dim_offset, 0);
end += maxs32(dim_offset, 0); end += maxs32(dim_offset, 0);
// 5th dim // 5th dim
dim_offset = muls32((attr->adv3), (int32_t)(attr->rpt3), &math_err); dim_offset =
muls32((int32_t)(attr->adv3), (int32_t)(attr->rpt3), &math_err);
start += mins32(dim_offset, 0); start += mins32(dim_offset, 0);
end += maxs32(dim_offset, 0); end += maxs32(dim_offset, 0);
// convert to byte range // convert to byte range
@@ -813,12 +1029,12 @@ pva_kmd_compute_dma_access(struct pva_dma_config const *dma_cfg,
struct pva_kmd_dma_access *access_sizes, struct pva_kmd_dma_access *access_sizes,
uint64_t *hw_dma_descs_mask) uint64_t *hw_dma_descs_mask)
{ {
uint32_t i; uint8_t i;
const struct pva_dma_descriptor *desc = NULL; const struct pva_dma_descriptor *desc = NULL;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
bool skip_swseq_size_compute = false; bool skip_swseq_size_compute = false;
for (i = 0; i < dma_cfg->header.num_descriptors; i++) { for (i = 0U; i < dma_cfg->header.num_descriptors; i++) {
/** /**
* Check if DMA descriptor has been used in HW Sequencer. * Check if DMA descriptor has been used in HW Sequencer.
* If used, skip_swseq_size_compute = true * If used, skip_swseq_size_compute = true
@@ -829,9 +1045,11 @@ pva_kmd_compute_dma_access(struct pva_dma_config const *dma_cfg,
*/ */
skip_swseq_size_compute = ((hw_dma_descs_mask[i / 64ULL] & skip_swseq_size_compute = ((hw_dma_descs_mask[i / 64ULL] &
(1ULL << (i & 0x3FU))) == 1U); (1ULL << (i & 0x3FU))) == 1U);
if (pva_is_reserved_desc(i)) { if (pva_is_reserved_desc(
safe_addu8(i, dma_cfg->header.base_descriptor))) {
// skip over the reserved descriptor range // skip over the reserved descriptor range
i = PVA_RESERVED_DESCRIPTORS_END; i = safe_subu8(PVA_RESERVED_DESCRIPTORS_END,
dma_cfg->header.base_descriptor);
continue; continue;
} }
@@ -878,8 +1096,8 @@ void pva_kmd_collect_relocs(struct pva_dma_config const *dma_cfg,
count_relocs(dma_cfg, out_static_slots, num_static_slots, out_dyn_slots, count_relocs(dma_cfg, out_static_slots, num_static_slots, out_dyn_slots,
num_dyn_slots); num_dyn_slots);
memset(static_reloc_off, 0U, sizeof(static_reloc_off)); (void)memset(static_reloc_off, 0, sizeof(static_reloc_off));
memset(dyn_reloc_off, 0U, sizeof(dyn_reloc_off)); (void)memset(dyn_reloc_off, 0, sizeof(dyn_reloc_off));
rel_info.dyn_slot.slots = out_dyn_slots; rel_info.dyn_slot.slots = out_dyn_slots;
rel_info.dyn_slot.relocs = out_dyn_relocs; rel_info.dyn_slot.relocs = out_dyn_relocs;

View File

@@ -16,48 +16,55 @@ static void write_dma_channel(struct pva_dma_channel const *ch,
bool support_hwseq_frame_linking) bool support_hwseq_frame_linking)
{ {
/* DMA_CHANNEL_CNTL0_CHSDID: DMA_CHANNEL_CNTL0[0] = descIndex + 1;*/ /* DMA_CHANNEL_CNTL0_CHSDID: DMA_CHANNEL_CNTL0[0] = descIndex + 1;*/
fw_ch->cntl0 = uint8_t desc_sum_u8 =
(((ch->desc_index + base_desc_index + 1U) & 0xFFU) << 0U); safe_addu8(safe_addu8(ch->desc_index, base_desc_index), 1U);
uint8_t cntl1_val;
uint16_t hwseqcntl_val;
fw_ch->cntl0 = (uint32_t)desc_sum_u8;
/* DMA_CHANNEL_CNTL0_CHVMEMOREQ */ /* DMA_CHANNEL_CNTL0_CHVMEMOREQ */
fw_ch->cntl0 |= ((ch->vdb_count & 0xFFU) << 8U); fw_ch->cntl0 |= (((uint32_t)ch->vdb_count & 0xFFU) << 8U);
/* DMA_CHANNEL_CNTL0_CHBH */ /* DMA_CHANNEL_CNTL0_CHBH */
fw_ch->cntl0 |= ((ch->adb_count & 0x1FFU) << 16U); fw_ch->cntl0 |= (((uint32_t)ch->adb_count & 0x1FFU) << 16U);
/* DMA_CHANNEL_CNTL0_CHPREF */ /* DMA_CHANNEL_CNTL0_CHPREF */
fw_ch->cntl0 |= ((ch->prefetch_enable & 1U) << 30U); fw_ch->cntl0 |= (((uint32_t)ch->prefetch_enable & 1U) << 30U);
/* DMA_CHANNEL_CNTL1_CHPWT */ /* DMA_CHANNEL_CNTL1_CHPWT */
fw_ch->cntl1 = ((ch->req_per_grant & 0x7U) << 2U); cntl1_val = (ch->req_per_grant & 0x7U) << 2U;
fw_ch->cntl1 = (uint32_t)cntl1_val;
/* DMA_CHANNEL_CNTL1_CHVDBSTART */ /* DMA_CHANNEL_CNTL1_CHVDBSTART */
fw_ch->cntl1 |= ((ch->vdb_offset & 0x7FU) << 16U); fw_ch->cntl1 |= (((uint32_t)ch->vdb_offset & 0x7FU) << 16U);
/* DMA_CHANNEL_CNTL1_CHADBSTART */ /* DMA_CHANNEL_CNTL1_CHADBSTART */
fw_ch->cntl1 |= ((ch->adb_offset & 0x1FFU) << 23U); fw_ch->cntl1 |= (((uint32_t)ch->adb_offset & 0x1FFU) << 23U);
fw_ch->boundary_pad = ch->pad_value; fw_ch->boundary_pad = ch->pad_value;
fw_ch->cntl1 |= ((ch->ch_rep_factor & 0x7U) << 8U); fw_ch->cntl1 |= (((uint32_t)ch->ch_rep_factor & 0x7U) << 8U);
/* DMA_CHANNEL_HWSEQCNTL_CHHWSEQSTART */ /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQSTART */
fw_ch->hwseqcntl = ((ch->hwseq_start & 0x1FFU) << 0U); hwseqcntl_val = (ch->hwseq_start & 0x1FFU) << 0U;
fw_ch->hwseqcntl = (uint32_t)hwseqcntl_val;
/* DMA_CHANNEL_HWSEQCNTL_CHHWSEQEND */ /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQEND */
fw_ch->hwseqcntl |= ((ch->hwseq_end & 0x1FFU) << 12U); fw_ch->hwseqcntl |= (((uint32_t)ch->hwseq_end & 0x1FFU) << 12U);
/* DMA_CHANNEL_HWSEQCNTL_CHHWSEQTD */ /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQTD */
fw_ch->hwseqcntl |= ((ch->hwseq_trigger_done & 0x3U) << 24U); fw_ch->hwseqcntl |= (((uint32_t)ch->hwseq_trigger_done & 0x3U) << 24U);
/* DMA_CHANNEL_HWSEQCNTL_CHHWSEQTS */ /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQTS */
fw_ch->hwseqcntl |= ((ch->hwseq_tx_select & 0x1U) << 27U); fw_ch->hwseqcntl |= (((uint32_t)ch->hwseq_tx_select & 0x1U) << 27U);
/* DMA_CHANNEL_HWSEQCNTL_CHHWSEQTO */ /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQTO */
fw_ch->hwseqcntl |= ((ch->hwseq_traversal_order & 0x1U) << 30U); fw_ch->hwseqcntl |=
(((uint32_t)ch->hwseq_traversal_order & 0x1U) << 30U);
/* DMA_CHANNEL_HWSEQCNTL_CHHWSEQEN */ /* DMA_CHANNEL_HWSEQCNTL_CHHWSEQEN */
fw_ch->hwseqcntl |= ((ch->hwseq_enable & 0x1U) << 31U); fw_ch->hwseqcntl |= (((uint32_t)ch->hwseq_enable & 0x1U) << 31U);
/* DMA_CHANNEL_HWSEQFSCNTL_CHHWSEQFCNT*/ /* DMA_CHANNEL_HWSEQFSCNTL_CHHWSEQFCNT*/
fw_ch->hwseqfscntl |= fw_ch->hwseqfscntl |=
@@ -86,20 +93,24 @@ static void write_dma_descriptor(struct pva_dma_descriptor const *desc,
fw_desc->dst_adr1 = iova_hi(desc->dst.offset); fw_desc->dst_adr1 = iova_hi(desc->dst.offset);
/* DMA_DESC_TRANS CNTL0 */ /* DMA_DESC_TRANS CNTL0 */
fw_desc->transfer_control0 = PVA_INSERT(desc->src.transfer_mode, 2, 0) | /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
PVA_INSERT(desc->dst.transfer_mode, 6, 4); fw_desc->transfer_control0 =
(uint8_t)(PVA_INSERT((uint8_t)desc->src.transfer_mode, 2, 0) |
PVA_INSERT((uint8_t)desc->dst.transfer_mode, 6, 4));
/* DMA_DESC_TRANS CNTL1 */ /* DMA_DESC_TRANS CNTL1 */
fw_desc->transfer_control1 = fw_desc->transfer_control1 =
PVA_INSERT(desc->log2_pixel_size, 1, 0) | (uint8_t)(PVA_INSERT((uint8_t)desc->log2_pixel_size, 1, 0) |
PVA_INSERT(desc->px_direction, 2, 2) | PVA_INSERT((uint8_t)desc->px_direction, 2, 2) |
PVA_INSERT(desc->py_direction, 3, 3) | PVA_INSERT((uint8_t)desc->py_direction, 3, 3) |
PVA_INSERT(desc->boundary_pixel_extension, 4, 4) | PVA_INSERT((uint8_t)desc->boundary_pixel_extension, 4,
PVA_INSERT(desc->tts, 5, 5) | 4) |
PVA_INSERT(desc->trigger_completion, 7, 7); PVA_INSERT((uint8_t)desc->tts, 5, 5) |
PVA_INSERT((uint8_t)desc->trigger_completion, 7, 7));
/* DMA_DESC_TRANS CNTL2 */ /* DMA_DESC_TRANS CNTL2 */
fw_desc->transfer_control2 = PVA_INSERT(desc->prefetch_enable, 0, 0) | fw_desc->transfer_control2 =
PVA_INSERT(desc->dst.cb_enable, 1, 1) | (uint8_t)(PVA_INSERT((uint8_t)desc->prefetch_enable, 0, 0) |
PVA_INSERT(desc->src.cb_enable, 2, 2); PVA_INSERT((uint8_t)desc->dst.cb_enable, 1, 1) |
PVA_INSERT((uint8_t)desc->src.cb_enable, 2, 2));
fw_desc->link_did = desc->link_desc_id; fw_desc->link_did = desc->link_desc_id;
@@ -111,71 +122,85 @@ static void write_dma_descriptor(struct pva_dma_descriptor const *desc,
fw_desc->dlp_adv = desc->dst.line_pitch; fw_desc->dlp_adv = desc->dst.line_pitch;
/* DMA_DESC_SLP_ADV */ /* DMA_DESC_SLP_ADV */
fw_desc->slp_adv = desc->src.line_pitch; fw_desc->slp_adv = desc->src.line_pitch;
/* DMA_DESC_DB_START */ /* DMA_DESC_DB_START - lower 16 bits, bit 16 stored in cb_ext */
fw_desc->db_start = desc->dst.cb_start; /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
/* DMA_DESC_DB_SIZE */ fw_desc->db_start = (uint16_t)(desc->dst.cb_start & 0xFFFFU);
fw_desc->db_size = desc->dst.cb_size;
/* DMA_DESC_SB_START */ /* DMA_DESC_DB_SIZE - lower 16 bits, bit 16 stored in cb_ext */
fw_desc->sb_start = desc->src.cb_start; /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
/* DMA_DESC_SB_SIZE */ fw_desc->db_size = (uint16_t)(desc->dst.cb_size & 0xFFFFU);
fw_desc->sb_size = desc->src.cb_size;
/* DMA_DESC_SB_START - lower 16 bits, bit 16 stored in cb_ext */
/* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
fw_desc->sb_start = (uint16_t)(desc->src.cb_start & 0xFFFFU);
/* DMA_DESC_SB_SIZE - lower 16 bits, bit 16 stored in cb_ext */
/* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
fw_desc->sb_size = (uint16_t)(desc->src.cb_size & 0xFFFFU);
/* DMA_DESC_TRIG_CH */ /* DMA_DESC_TRIG_CH */
/* Channel events are not supported */ /* Channel events are not supported */
fw_desc->trig_ch_events = 0U; fw_desc->trig_ch_events = 0U;
/* DMA_DESC_HW_SW_TRIG */ /* DMA_DESC_HW_SW_TRIG */
/* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
fw_desc->hw_sw_trig_events = fw_desc->hw_sw_trig_events =
PVA_INSERT(desc->trig_event_mode, 1, 0) | (uint16_t)(PVA_INSERT((uint8_t)desc->trig_event_mode, 1, 0) |
PVA_INSERT(desc->trig_vpu_events, 5, 2) | PVA_INSERT((uint8_t)desc->trig_vpu_events, 5, 2) |
PVA_INSERT(desc->desc_reload_enable, 12, 12); PVA_INSERT((uint8_t)desc->desc_reload_enable, 12,
12));
/* DMA_DESC_PX */ /* DMA_DESC_PX */
fw_desc->px = desc->px; fw_desc->px = desc->px;
/* DMA_DESC_PY */ /* DMA_DESC_PY */
fw_desc->py = desc->py; fw_desc->py = desc->py;
/* DMA_DESC_FRDA */ /* DMA_DESC_FRDA */
fw_desc->frda = ((desc->dst2_offset >> 6U) & 0x7FFF); fw_desc->frda = (uint16_t)((desc->dst2_offset >> 6U) & 0x7FFFU);
/* DMA_DESC_NDTM_CNTL0 */ /* DMA_DESC_NDTM_CNTL0 */
fw_desc->cb_ext = (((desc->src.cb_start >> 16) & 0x1) << 0) | fw_desc->cb_ext = (uint8_t)((((desc->src.cb_start >> 16) & 0x1U) << 0) |
(((desc->dst.cb_start >> 16) & 0x1) << 2) | (((desc->dst.cb_start >> 16) & 0x1U) << 2) |
(((desc->src.cb_size >> 16) & 0x1) << 4) | (((desc->src.cb_size >> 16) & 0x1U) << 4) |
(((desc->dst.cb_size >> 16) & 0x1) << 6); (((desc->dst.cb_size >> 16) & 0x1U) << 6));
/* DMA_DESC_NS1_ADV & DMA_DESC_ST1_ADV */ /* DMA_DESC_NS1_ADV & DMA_DESC_ST1_ADV */
/* adv fields are signed int32_t, cast to uint32_t for bit packing */
fw_desc->srcpt1_cntl = fw_desc->srcpt1_cntl =
assemble_rpt_cntl(desc->src.rpt1, desc->src.adv1); assemble_rpt_cntl(desc->src.rpt1, (uint32_t)desc->src.adv1);
fw_desc->srcpt2_cntl = fw_desc->srcpt2_cntl =
assemble_rpt_cntl(desc->src.rpt2, desc->src.adv2); assemble_rpt_cntl(desc->src.rpt2, (uint32_t)desc->src.adv2);
fw_desc->srcpt3_cntl = fw_desc->srcpt3_cntl =
assemble_rpt_cntl(desc->src.rpt3, desc->src.adv3); assemble_rpt_cntl(desc->src.rpt3, (uint32_t)desc->src.adv3);
fw_desc->dstpt1_cntl = fw_desc->dstpt1_cntl =
assemble_rpt_cntl(desc->dst.rpt1, desc->dst.adv1); assemble_rpt_cntl(desc->dst.rpt1, (uint32_t)desc->dst.adv1);
fw_desc->dstpt2_cntl = fw_desc->dstpt2_cntl =
assemble_rpt_cntl(desc->dst.rpt2, desc->dst.adv2); assemble_rpt_cntl(desc->dst.rpt2, (uint32_t)desc->dst.adv2);
fw_desc->dstpt3_cntl = fw_desc->dstpt3_cntl =
assemble_rpt_cntl(desc->dst.rpt3, desc->dst.adv3); assemble_rpt_cntl(desc->dst.rpt3, (uint32_t)desc->dst.adv3);
} }
static void write_triggers(struct pva_dma_config const *dma_cfg, static void write_triggers(struct pva_dma_config const *dma_cfg,
struct pva_dma_config_resource *fw_cfg, struct pva_dma_config_resource *fw_cfg,
struct pva_dma_resource_map *dma_resource_map) struct pva_dma_resource_map *dma_resource_map)
{ {
uint32_t i, j; uint8_t i, j;
bool trigger_required = false; bool trigger_required = false;
memset(fw_cfg->output_enable, 0, sizeof(fw_cfg->output_enable)); (void)memset(fw_cfg->output_enable, 0, sizeof(fw_cfg->output_enable));
for (i = 0; i < dma_cfg->header.num_channels; i++) { for (i = 0; i < dma_cfg->header.num_channels; i++) {
struct pva_dma_channel const *ch = &dma_cfg->channels[i]; struct pva_dma_channel const *ch;
uint8_t ch_num = i + dma_cfg->header.base_channel; uint8_t ch_num;
uint32_t mask; uint32_t mask;
ch = &dma_cfg->channels[i];
/* CERT INT31-C: Hardware constraints ensure num_channels and base_channel
* are bounded such that their sum always fits in uint8_t, safe to cast */
ch_num = safe_addu8(i, dma_cfg->header.base_channel);
mask = ch->output_enable_mask; mask = ch->output_enable_mask;
/* READ/STORE triggers */ /* READ/STORE triggers */
for (j = 0; j < 7; j++) { for (j = 0U; j < 7U; j++) {
fw_cfg->output_enable[j] |= fw_cfg->output_enable[j] |=
(((mask >> 2 * j) & 1U) << ch_num); (((mask >> (2U * j)) & 1U) << ch_num);
fw_cfg->output_enable[j] |= fw_cfg->output_enable[j] |=
(((mask >> (2 * j + 1)) & 1U) (((mask >> ((2U * j) + 1U)) & 1U)
<< (ch_num + 16U)); << (ch_num + 16U));
} }
@@ -186,7 +211,7 @@ static void write_triggers(struct pva_dma_config const *dma_cfg,
fw_cfg->output_enable[8] |= fw_cfg->output_enable[8] |=
(((mask >> 16) & 1U) << (ch_num + 16U)); (((mask >> 16) & 1U) << (ch_num + 16U));
if (mask != 0) { if (mask != 0U) {
trigger_required = true; trigger_required = true;
} }
} }
@@ -208,7 +233,7 @@ void pva_kmd_write_fw_dma_config(struct pva_dma_config const *dma_cfg,
struct pva_dma_resource_map *dma_resource_map; struct pva_dma_resource_map *dma_resource_map;
uint32_t *hwseq_words; uint32_t *hwseq_words;
uintptr_t offset; uintptr_t offset;
uint32_t i; uint8_t i;
hdr = fw_dma_config; hdr = fw_dma_config;
hdr->base_channel = dma_cfg->header.base_channel; hdr->base_channel = dma_cfg->header.base_channel;
@@ -235,8 +260,8 @@ void pva_kmd_write_fw_dma_config(struct pva_dma_config const *dma_cfg,
offset = sizeof(*hdr); offset = sizeof(*hdr);
fw_slots = pva_offset_pointer(fw_dma_config, offset); fw_slots = pva_offset_pointer(fw_dma_config, offset);
if (hdr->num_dynamic_slots > 0) { if (hdr->num_dynamic_slots > 0U) {
last_slot = &fw_slots[hdr->num_dynamic_slots - 1]; last_slot = &fw_slots[hdr->num_dynamic_slots - 1U];
hdr->num_relocs = safe_addu16(last_slot->reloc_start_idx, hdr->num_relocs = safe_addu16(last_slot->reloc_start_idx,
last_slot->reloc_count); last_slot->reloc_count);
@@ -251,37 +276,41 @@ void pva_kmd_write_fw_dma_config(struct pva_dma_config const *dma_cfg,
} }
fw_channels = pva_offset_pointer(fw_dma_config, offset); fw_channels = pva_offset_pointer(fw_dma_config, offset);
offset += sizeof(*fw_channels) * hdr->num_channels; /* MISRA C-2023 Rule 10.3: Explicit cast for narrowing conversion */
offset += (uint32_t)(sizeof(*fw_channels) * hdr->num_channels);
fw_descs = pva_offset_pointer(fw_dma_config, offset); fw_descs = pva_offset_pointer(fw_dma_config, offset);
offset += sizeof(*fw_descs) * hdr->num_descriptors; offset += sizeof(*fw_descs) * hdr->num_descriptors;
/* Do not include fields beyond descriptors as they are not fetched to /* Do not include fields beyond descriptors as they are not fetched to
* TCM */ * TCM */
*out_fw_fetch_size = offset; *out_fw_fetch_size = (uint32_t)offset;
for (i = 0; i < hdr->num_channels; i++) { for (i = 0U; i < hdr->num_channels; i++) {
write_dma_channel(&dma_cfg->channels[i], write_dma_channel(&dma_cfg->channels[i],
dma_cfg->header.base_descriptor, dma_cfg->header.base_descriptor,
&fw_channels[i], dma_resource_map, &fw_channels[i], dma_resource_map,
support_hwseq_frame_linking); support_hwseq_frame_linking);
} }
for (i = 0; i < dma_cfg->header.num_descriptors; i++) { for (i = 0U; i < dma_cfg->header.num_descriptors; i++) {
if (pva_is_reserved_desc(i)) { if (pva_is_reserved_desc(
safe_addu8(i, dma_cfg->header.base_descriptor))) {
// skip over the reserved descriptor range // skip over the reserved descriptor range
i = PVA_RESERVED_DESCRIPTORS_END; i = safe_subu8(PVA_RESERVED_DESCRIPTORS_END,
dma_cfg->header.base_descriptor);
continue; continue;
} }
write_dma_descriptor(&dma_cfg->descriptors[i], &fw_descs[i]); write_dma_descriptor(&dma_cfg->descriptors[i], &fw_descs[i]);
} }
write_triggers(dma_cfg, fw_dma_config, dma_resource_map); write_triggers(dma_cfg, (struct pva_dma_config_resource *)fw_dma_config,
dma_resource_map);
hwseq_words = pva_offset_pointer(fw_dma_config, offset); hwseq_words = pva_offset_pointer(fw_dma_config, offset);
memcpy(hwseq_words, dma_cfg->hwseq_words, (void)memcpy(hwseq_words, dma_cfg->hwseq_words,
sizeof(*hwseq_words) * hdr->num_hwseq_words); sizeof(*hwseq_words) * hdr->num_hwseq_words);
/*TODO: write hdr->common_config for hwseq and MISR*/ /*TODO: write hdr->common_config for hwseq and MISR*/
} }

View File

@@ -9,11 +9,51 @@
struct pva_kmd_device; struct pva_kmd_device;
struct pva_kmd_device_memory; struct pva_kmd_device_memory;
/**
* @brief Symbol table for executable debugging and runtime information
*
* @details This structure maintains a symbol table for a loaded executable,
* providing access to symbol information used for debugging, profiling, and
* runtime symbol resolution. The symbol table contains metadata about functions,
* variables, and other symbols within the executable that can be referenced
* during execution or debugging operations.
*/
struct pva_kmd_exec_symbol_table { struct pva_kmd_exec_symbol_table {
/**
* @brief Number of symbols in the symbol table
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_symbols; uint32_t n_symbols;
/**
* @brief Array of symbol information structures
* Valid value: non-null if n_symbols > 0, null if n_symbols == 0
*/
struct pva_symbol_info *symbols; struct pva_symbol_info *symbols;
}; };
/**
* @brief Get symbol information by symbol ID
*
* @details This function performs the following operations:
* - Validates the symbol ID against the symbol table bounds
* - Converts external symbol ID to internal array index
* - Retrieves the symbol information structure for the specified symbol
* - Provides access to symbol metadata for debugging and runtime operations
* - Returns null for invalid or out-of-range symbol IDs
*
* The symbol ID is expected to be in the external format with PVA_SYMBOL_ID_BASE
* offset. This function handles the conversion to internal array indexing
* automatically.
*
* @param[in] symbol_table Pointer to @ref pva_kmd_exec_symbol_table structure
* Valid value: non-null, must be initialized
* @param[in] symbol_id External symbol ID to retrieve
* Valid range: [PVA_SYMBOL_ID_BASE .. PVA_SYMBOL_ID_BASE+n_symbols-1]
*
* @retval non-null Pointer to @ref pva_symbol_info if symbol exists
* @retval NULL Invalid symbol ID or symbol not found
*/
static inline struct pva_symbol_info * static inline struct pva_symbol_info *
pva_kmd_get_symbol(struct pva_kmd_exec_symbol_table *symbol_table, pva_kmd_get_symbol(struct pva_kmd_exec_symbol_table *symbol_table,
uint32_t symbol_id) uint32_t symbol_id)
@@ -30,6 +70,30 @@ pva_kmd_get_symbol(struct pva_kmd_exec_symbol_table *symbol_table,
return symbol; return symbol;
} }
/**
* @brief Get symbol information with type validation
*
* @details This function performs the following operations:
* - Calls @ref pva_kmd_get_symbol() to retrieve symbol information
* - Validates that the symbol has the expected type
* - Returns the symbol information only if type matches
* - Provides type-safe access to symbol information
* - Logs error for type mismatches to aid debugging
*
* This function provides additional type safety when accessing symbols
* by ensuring the symbol type matches expectations before returning
* the symbol information.
*
* @param[in] symbol_table Pointer to @ref pva_kmd_exec_symbol_table structure
* Valid value: non-null, must be initialized
* @param[in] symbol_id External symbol ID to retrieve
* Valid range: [PVA_SYMBOL_ID_BASE .. PVA_SYMBOL_ID_BASE+n_symbols-1]
* @param[in] symbol_type Expected symbol type for validation
* Valid values: @ref pva_symbol_type enumeration values
*
* @retval non-null Pointer to @ref pva_symbol_info if symbol exists and type matches
* @retval NULL Invalid symbol ID, symbol not found, or type mismatch
*/
static inline struct pva_symbol_info * static inline struct pva_symbol_info *
pva_kmd_get_symbol_with_type(struct pva_kmd_exec_symbol_table *symbol_table, pva_kmd_get_symbol_with_type(struct pva_kmd_exec_symbol_table *symbol_table,
uint32_t symbol_id, uint32_t symbol_id,
@@ -38,20 +102,56 @@ pva_kmd_get_symbol_with_type(struct pva_kmd_exec_symbol_table *symbol_table,
struct pva_symbol_info *symbol = NULL; struct pva_symbol_info *symbol = NULL;
symbol = pva_kmd_get_symbol(symbol_table, symbol_id); symbol = pva_kmd_get_symbol(symbol_table, symbol_id);
if (!symbol) { if (symbol == NULL) {
return NULL; return NULL;
} }
#if !defined(PVA_SKIP_SYMBOL_TYPE_CHECK)
if (symbol->symbol_type != symbol_type) { if (symbol->symbol_type != symbol_type) {
pva_kmd_log_err("Unexpected symbol type\n"); pva_kmd_log_err("Unexpected symbol type\n");
return NULL; return NULL;
} }
#endif
return symbol; return symbol;
} }
/**
* @brief Load and prepare VPU executable for execution
*
* @details This function performs the following operations:
* - Validates the executable format and structure
* - Parses executable sections including code, data, and metadata
* - Allocates device memory for executable storage
* - Maps executable sections to appropriate SMMU contexts
* - Extracts and builds symbol table for debugging support
* - Sets up memory permissions for code and data sections
* - Prepares executable for hardware execution by the VPU
* - Returns all necessary information for executable management
*
* The loaded executable is stored in device memory accessible by the VPU
* hardware, with proper memory protection and SMMU mapping. The symbol
* table provides debugging and profiling capabilities.
*
* @param[in] executable_data Pointer to executable binary data
* Valid value: non-null
* @param[in] executable_size Size of executable binary in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] dma_smmu_id SMMU context ID for DMA operations
* Valid range: [0 .. PVA_MAX_NUM_SMMU_CONTEXTS-1]
* @param[out] out_symbol_table Pointer to store symbol table information
* Valid value: non-null
* @param[out] out_metainfo Pointer to store executable metadata memory
* Valid value: non-null
* @param[out] out_sections Pointer to store executable sections memory
* Valid value: non-null
*
* @retval PVA_SUCCESS Executable loaded successfully
* @retval PVA_INVALID_SYMBOL Executable format is invalid or corrupted
* @retval PVA_NOMEM Failed to allocate device memory
* @retval PVA_INVAL Failed to map executable to SMMU context
* @retval PVA_NOT_IMPL Executable uses unsupported features
*/
enum pva_error enum pva_error
pva_kmd_load_executable(const void *executable_data, uint32_t executable_size, pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
struct pva_kmd_device *pva, uint8_t dma_smmu_id, struct pva_kmd_device *pva, uint8_t dma_smmu_id,
@@ -59,6 +159,28 @@ pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
struct pva_kmd_device_memory **out_metainfo, struct pva_kmd_device_memory **out_metainfo,
struct pva_kmd_device_memory **out_sections); struct pva_kmd_device_memory **out_sections);
/**
* @brief Unload executable and free associated resources
*
* @details This function performs the following operations:
* - Frees the symbol table and all symbol information
* - Unmaps executable sections from SMMU contexts
* - Releases device memory allocated for executable metadata
* - Releases device memory allocated for executable code and data sections
* - Cleans up all resources associated with the executable
* - Invalidates all pointers and structures for the executable
*
* This function should be called when an executable is no longer needed
* to ensure proper cleanup of all associated resources. After calling
* this function, the executable cannot be used for further operations.
*
* @param[in, out] symbol_table Pointer to symbol table to clean up
* Valid value: non-null, must have been initialized
* @param[in] metainfo Pointer to executable metadata memory to free
* Valid value: non-null, must have been allocated
* @param[in] sections Pointer to executable sections memory to free
* Valid value: non-null, must have been allocated
*/
void pva_kmd_unload_executable(struct pva_kmd_exec_symbol_table *symbol_table, void pva_kmd_unload_executable(struct pva_kmd_exec_symbol_table *symbol_table,
struct pva_kmd_device_memory *metainfo, struct pva_kmd_device_memory *metainfo,
struct pva_kmd_device_memory *sections); struct pva_kmd_device_memory *sections);

View File

@@ -1,91 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_utils.h"
#include "pva_api.h"
#include "pva_api_cmdbuf.h"
#include "pva_api_types.h"
#include "pva_bit.h"
#include "pva_fw.h"
#include "pva_kmd_cmdbuf.h"
#include "pva_kmd_device.h"
#include "pva_kmd_fw_debug.h"
#include "pva_kmd_constants.h"
#include "pva_utils.h"
enum pva_error pva_kmd_notify_fw_set_trace_level(struct pva_kmd_device *pva,
uint32_t trace_level)
{
struct pva_cmd_set_trace_level cmd = { 0 };
pva_kmd_set_cmd_set_trace_level(&cmd, trace_level);
return pva_kmd_submit_cmd_sync(&pva->submitter, &cmd, sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
}
enum pva_error pva_kmd_notify_fw_set_profiling_level(struct pva_kmd_device *pva,
uint32_t level)
{
struct pva_cmd_set_profiling_level cmd = { 0 };
pva_kmd_set_cmd_set_profiling_level(&cmd, level);
return pva_kmd_submit_cmd_sync(&pva->submitter, &cmd, sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
}
void pva_kmd_drain_fw_print(struct pva_kmd_fw_print_buffer *print_buffer)
{
struct pva_fw_print_buffer_header *buf_info = print_buffer->buffer_info;
uint32_t tail = buf_info->tail;
if (tail > buf_info->size) {
pva_kmd_log_err(
"Firmware print tail is out of bounds! Refusing to print\n");
return;
}
if (buf_info->head > buf_info->size) {
pva_kmd_log_err(
"Firmware print head is out of bounds! Refusing to print\n");
return;
}
while (buf_info->head != tail) {
uint32_t max_len;
uint32_t head = buf_info->head;
const char *str = print_buffer->content + head;
uint32_t print_size;
if ((head + PVA_MAX_DEBUG_LOG_MSG_CHARACTERS) >
buf_info->size) {
buf_info->head = 0;
continue;
}
if (head < tail) {
max_len = tail - head;
} else {
max_len = buf_info->size - head;
}
print_size = strnlen(str, max_len);
pva_kmd_print_str(str);
/* +1 for null terminator */
head = (head + print_size + 1);
if (head >= buf_info->size) {
head = 0;
}
buf_info->head = head;
}
if (print_buffer->buffer_info->flags & PVA_FW_PRINT_BUFFER_OVERFLOWED) {
pva_kmd_log_err("Firmware print buffer overflowed!");
}
if (print_buffer->buffer_info->flags & PVA_FW_PRINT_FAILURE) {
pva_kmd_log_err("Firmware print failed!");
}
}

View File

@@ -1,23 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_FW_DEBUG_H
#define PVA_KMD_FW_DEBUG_H
#include "pva_api.h"
#include "pva_fw.h"
#include "pva_kmd_device.h"
struct pva_kmd_fw_print_buffer {
struct pva_fw_print_buffer_header *buffer_info;
char const *content;
};
enum pva_error pva_kmd_notify_fw_set_trace_level(struct pva_kmd_device *pva,
uint32_t trace_level);
enum pva_error pva_kmd_notify_fw_set_profiling_level(struct pva_kmd_device *pva,
uint32_t level);
void pva_kmd_drain_fw_print(struct pva_kmd_fw_print_buffer *print_buffer);
#endif // PVA_KMD_FW_DEBUG_H

View File

@@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_limits.h"
#include "pva_kmd_utils.h"
#include "pva_api.h"
#include "pva_api_cmdbuf.h"
#include "pva_api_types.h"
#include "pva_bit.h"
#include "pva_fw.h"
#include "pva_kmd_cmdbuf.h"
#include "pva_kmd_device.h"
#include "pva_kmd_fw_debug_printf.h"
#include "pva_kmd_constants.h"
#include "pva_utils.h"
void pva_kmd_init_fw_print_buffer(struct pva_kmd_device *pva,
void *debug_buffer_va)
{
struct pva_kmd_fw_print_buffer *print_buffer = &pva->fw_print_buffer;
print_buffer->buffer_info = pva_offset_pointer(
debug_buffer_va,
FW_TRACE_BUFFER_SIZE + FW_CODE_COVERAGE_BUFFER_SIZE);
print_buffer->buffer_info->size =
(uint32_t)((uint32_t)FW_DEBUG_LOG_BUFFER_SIZE -
(uint32_t)sizeof(*print_buffer->buffer_info));
print_buffer->buffer_info->head = 0;
print_buffer->buffer_info->tail = 0;
print_buffer->buffer_info->flags = 0;
print_buffer->content = pva_offset_pointer(
print_buffer->buffer_info, sizeof(*print_buffer->buffer_info));
}
void pva_kmd_drain_fw_print(struct pva_kmd_device *pva)
{
struct pva_kmd_fw_print_buffer *print_buffer = &pva->fw_print_buffer;
struct pva_fw_print_buffer_header *buf_info = print_buffer->buffer_info;
uint32_t tail = buf_info->tail;
if (tail > buf_info->size) {
pva_kmd_log_err(
"Firmware print tail is out of bounds! Refusing to print\n");
return;
}
if (buf_info->head > buf_info->size) {
pva_kmd_log_err(
"Firmware print head is out of bounds! Refusing to print\n");
return;
}
while (buf_info->head != tail) {
uint32_t max_len;
uint32_t head = buf_info->head;
const char *str = print_buffer->content + head;
uint32_t print_size;
size_t strnlen_result;
if ((head + PVA_MAX_DEBUG_LOG_MSG_CHARACTERS) >
buf_info->size) {
buf_info->head = 0;
continue;
}
if (head < tail) {
max_len = tail - head;
} else {
max_len = buf_info->size - head;
}
strnlen_result = strnlen(str, max_len);
/* Validate strnlen result fits in uint32_t */
if (strnlen_result > U32_MAX) {
pva_kmd_log_err(
"FW debug print string length exceeds U32_MAX");
return;
}
/* CERT INT31-C: strnlen_result validated to fit in uint32_t, safe to cast */
print_size = (uint32_t)strnlen_result;
pva_kmd_log_err(str);
/* +1 for null terminator - use safe addition to prevent overflow */
head = safe_addu32(head, safe_addu32(print_size, 1U));
if (head >= buf_info->size) {
head = 0;
}
buf_info->head = head;
}
if ((print_buffer->buffer_info->flags &
PVA_FW_PRINT_BUFFER_OVERFLOWED) != 0U) {
pva_kmd_log_err("Firmware print buffer overflowed!");
}
if ((print_buffer->buffer_info->flags & PVA_FW_PRINT_FAILURE) != 0U) {
pva_kmd_log_err("Firmware print failed!");
}
}

View File

@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_FW_DEBUG_PRINTF_H
#define PVA_KMD_FW_DEBUG_PRINTF_H
#include "pva_api.h"
#include "pva_fw.h"
#include "pva_kmd_device.h"
/**
* @brief Structure for managing firmware print buffer access
*
* @details This structure provides access to the firmware's print/debug output
* buffer, which is used for collecting debug messages, trace information, and
* other diagnostic output from the firmware. The structure maintains pointers
* to both the buffer header (containing metadata) and the actual content data.
*/
struct pva_kmd_fw_print_buffer {
/**
* @brief Pointer to firmware print buffer header containing metadata
* Valid value: non-null when buffer is active
*/
struct pva_fw_print_buffer_header *buffer_info;
/**
* @brief Pointer to the actual print buffer content data
* Valid value: non-null when buffer is active
*/
char const *content;
};
/**
* @brief Drain and process firmware print buffer contents
*
* @details This function performs the following operations:
* - Reads new content from the firmware print buffer
* - Processes and formats the debug output for display or logging
* - Updates buffer read pointers to mark content as consumed
* - Handles buffer wraparound and overflow conditions
* - Outputs firmware messages to appropriate debug/log channels
* - Maintains proper synchronization with firmware buffer updates
*
* This function is typically called periodically or in response to firmware
* notifications to collect and display debug output from the firmware. The
* print buffer must be properly initialized before calling this function.
*
* @param[in, out] print_buffer Pointer to @ref pva_kmd_fw_print_buffer structure
* Valid value: non-null, must be initialized
*/
void pva_kmd_drain_fw_print(struct pva_kmd_device *pva);
void pva_kmd_init_fw_print_buffer(struct pva_kmd_device *pva,
void *debug_buffer_va);
#endif // PVA_KMD_FW_DEBUG_PRINTF_H

View File

@@ -60,7 +60,8 @@ static const char *priv_cmd_names[PVA_CMD_PRIV_OPCODE_COUNT] = {
CMD(ENABLE_FW_PROFILING), CMD(ENABLE_FW_PROFILING),
CMD(DISABLE_FW_PROFILING), CMD(DISABLE_FW_PROFILING),
CMD(SUSPEND_FW), CMD(SUSPEND_FW),
CMD(RESUME_FW) CMD(RESUME_FW),
CMD(SET_PFSD_CMD_BUFFER_SIZE),
}; };
static inline const char *pva_fw_get_cmd_name(uint32_t opcode) static inline const char *pva_fw_get_cmd_name(uint32_t opcode)
@@ -91,13 +92,13 @@ static inline const char *pva_fw_get_cmd_name(uint32_t opcode)
void pva_kmd_device_init_profiler(struct pva_kmd_device *pva) void pva_kmd_device_init_profiler(struct pva_kmd_device *pva)
{ {
pva->debugfs_context.g_fw_profiling_config.enabled = false; pva->debugfs_context.g_fw_profiling_config.enabled = (uint8_t) false;
pva->debugfs_context.g_fw_profiling_config.filter = 0x0; pva->debugfs_context.g_fw_profiling_config.filter = 0x0;
} }
void pva_kmd_device_deinit_profiler(struct pva_kmd_device *pva) void pva_kmd_device_deinit_profiler(struct pva_kmd_device *pva)
{ {
pva->debugfs_context.g_fw_profiling_config.enabled = false; pva->debugfs_context.g_fw_profiling_config.enabled = (uint8_t) false;
} }
enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva) enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva)
@@ -105,8 +106,11 @@ enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva)
struct pva_kmd_submitter *dev_submitter = &pva->submitter; struct pva_kmd_submitter *dev_submitter = &pva->submitter;
struct pva_cmd_enable_fw_profiling cmd = { 0 }; struct pva_cmd_enable_fw_profiling cmd = { 0 };
uint32_t filter = 0U; uint32_t filter = 0U;
uint8_t timestamp_type = TIMESTAMP_TYPE_CYCLE_COUNT; uint8_t timestamp_type = (uint8_t)TIMESTAMP_TYPE_CYCLE_COUNT;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
enum pva_fw_timestamp_t tse_type = TIMESTAMP_TYPE_TSE;
uint8_t size_8 = (uint8_t)8U;
uint8_t size_4 = (uint8_t)4U;
struct pva_kmd_shared_buffer *profiling_buffer = struct pva_kmd_shared_buffer *profiling_buffer =
&pva->kmd_fw_buffers[PVA_PRIV_CCQ_ID]; &pva->kmd_fw_buffers[PVA_PRIV_CCQ_ID];
@@ -124,7 +128,8 @@ enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva)
pva_kmd_set_cmd_enable_fw_profiling(&cmd, filter, timestamp_type); pva_kmd_set_cmd_enable_fw_profiling(&cmd, filter, timestamp_type);
err = pva_kmd_submit_cmd_sync(dev_submitter, &cmd, sizeof(cmd), err = pva_kmd_submit_cmd_sync(dev_submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -132,15 +137,19 @@ enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva)
goto out; goto out;
} }
pva->debugfs_context.g_fw_profiling_config.enabled = true; pva->debugfs_context.g_fw_profiling_config.enabled = (uint8_t) true;
pva->debugfs_context.g_fw_profiling_config.filter = filter; pva->debugfs_context.g_fw_profiling_config.filter = filter;
pva->debugfs_context.g_fw_profiling_config.timestamp_type = pva->debugfs_context.g_fw_profiling_config.timestamp_type =
timestamp_type; timestamp_type;
pva->debugfs_context.g_fw_profiling_config.timestamp_size =
(pva->debugfs_context.g_fw_profiling_config.timestamp_type == if (pva->debugfs_context.g_fw_profiling_config.timestamp_type ==
TIMESTAMP_TYPE_TSE) ? tse_type) {
8 : pva->debugfs_context.g_fw_profiling_config.timestamp_size =
4; size_8;
} else {
pva->debugfs_context.g_fw_profiling_config.timestamp_size =
size_4;
}
out: out:
return err; return err;
@@ -161,7 +170,7 @@ enum pva_error pva_kmd_notify_fw_disable_profiling(struct pva_kmd_device *pva)
goto err_out; goto err_out;
} }
pva->debugfs_context.g_fw_profiling_config.enabled = false; pva->debugfs_context.g_fw_profiling_config.enabled = (uint8_t) false;
pva->debugfs_context.g_fw_profiling_config.filter = 0x0; pva->debugfs_context.g_fw_profiling_config.filter = 0x0;
return PVA_SUCCESS; return PVA_SUCCESS;
@@ -173,36 +182,54 @@ err_out:
static void decode_and_print_event(unsigned long walltime, static void decode_and_print_event(unsigned long walltime,
unsigned long relative_time, unsigned long relative_time,
struct pva_fw_event_message message, struct pva_fw_event_message message,
char *msg_string) char *msg_string, size_t msg_size)
{ {
int ret;
switch (PVA_BIT(message.event)) { switch (PVA_BIT(message.event)) {
case PVA_FW_EVENT_DO_CMD: { case PVA_FW_EVENT_DO_CMD: {
sprintf(msg_string, ret = snprintf(
msg_string, msg_size,
"pva_fw@%lu: [%8lu] event=%-12s type=%-7s slot=%u idx=%-5u opcode=%s", "pva_fw@%lu: [%8lu] event=%-12s type=%-7s slot=%u idx=%-5u opcode=%s",
walltime, relative_time, "DO_CMD", walltime, relative_time, "DO_CMD",
event_type_to_string(message.type), message.arg2, event_type_to_string(message.type), message.arg2,
message.arg3, pva_fw_get_cmd_name(message.arg1)); message.arg3, pva_fw_get_cmd_name(message.arg1));
if (ret < 0 || (size_t)ret >= msg_size) {
pva_kmd_log_err("snprintf failed or truncated");
}
} break; } break;
case PVA_FW_EVENT_SCAN_QUEUES: { case PVA_FW_EVENT_SCAN_QUEUES: {
sprintf(msg_string, ret = snprintf(
msg_string, msg_size,
"pva_fw@%lu: [%8lu] event=%-12s type=%-7s found=%u ccq_id=%-5u queue_id=%u", "pva_fw@%lu: [%8lu] event=%-12s type=%-7s found=%u ccq_id=%-5u queue_id=%u",
walltime, relative_time, "SCAN_QUEUES", walltime, relative_time, "SCAN_QUEUES",
event_type_to_string(message.type), message.arg1, event_type_to_string(message.type), message.arg1,
message.arg2, message.arg3); message.arg2, message.arg3);
if (ret < 0 || (size_t)ret >= msg_size) {
pva_kmd_log_err("snprintf failed or truncated");
}
} break; } break;
case PVA_FW_EVENT_SCAN_SLOTS: { case PVA_FW_EVENT_SCAN_SLOTS: {
sprintf(msg_string, ret = snprintf(
msg_string, msg_size,
"pva_fw@%lu: [%8lu] event=%-12s type=%-7s state=%u slot=%u", "pva_fw@%lu: [%8lu] event=%-12s type=%-7s state=%u slot=%u",
walltime, relative_time, "SCAN_SLOTS", walltime, relative_time, "SCAN_SLOTS",
event_type_to_string(message.type), message.arg1, event_type_to_string(message.type), message.arg1,
message.arg2); message.arg2);
if (ret < 0 || (size_t)ret >= msg_size) {
pva_kmd_log_err("snprintf failed or truncated");
}
} break; } break;
case PVA_FW_EVENT_RUN_VPU: { case PVA_FW_EVENT_RUN_VPU: {
sprintf(msg_string, ret = snprintf(
msg_string, msg_size,
"pva_fw@%lu: [%8lu] event=%-12s type=%-7s slot=%u idx=%-5u opcode=%s", "pva_fw@%lu: [%8lu] event=%-12s type=%-7s slot=%u idx=%-5u opcode=%s",
walltime, relative_time, "RUN_VPU", walltime, relative_time, "RUN_VPU",
event_type_to_string(message.type), message.arg2, event_type_to_string(message.type),
message.arg3, pva_fw_get_cmd_name(message.arg1)); (unsigned int)message.arg2, (unsigned int)message.arg3,
pva_fw_get_cmd_name(message.arg1));
if (ret < 0 || (size_t)ret >= msg_size) {
pva_kmd_log_err("snprintf failed or truncated");
}
} break; } break;
default: default:
pva_dbg_printf("Unknown event type\n"); pva_dbg_printf("Unknown event type\n");
@@ -210,8 +237,8 @@ static void decode_and_print_event(unsigned long walltime,
} }
} }
enum pva_error pva_kmd_process_fw_event(struct pva_kmd_device *pva, static enum pva_error process_fw_event(struct pva_kmd_device *pva,
uint8_t *data, uint32_t data_size) uint8_t *data, uint32_t data_size)
{ {
uint64_t timestamp = 0; uint64_t timestamp = 0;
char msg_string[200] = { '\0' }; char msg_string[200] = { '\0' };
@@ -247,27 +274,28 @@ enum pva_error pva_kmd_process_fw_event(struct pva_kmd_device *pva,
0U : 0U :
safe_subu64(walltime, prev_walltime); safe_subu64(walltime, prev_walltime);
decode_and_print_event(walltime, relative_time, event_header, decode_and_print_event(walltime, relative_time, event_header,
&msg_string[0]); &msg_string[0], sizeof(msg_string));
pva_kmd_print_str(msg_string); pva_kmd_log_info(msg_string);
prev_walltime = walltime; prev_walltime = walltime;
return PVA_SUCCESS; return PVA_SUCCESS;
} }
void pva_kmd_process_fw_tracepoint(struct pva_kmd_device *pva, void pva_kmd_process_fw_event(struct pva_kmd_device *pva, uint8_t *msg_body,
struct pva_fw_tracepoint *tp) uint32_t msg_size)
{ {
char msg_string[200] = { '\0' }; enum pva_error err = PVA_SUCCESS;
snprintf( // TODO: This must be updated once profiler config is exposed through debugfs.
msg_string, sizeof(msg_string), // KMD must use the same timestamp size as the FW. It is possible that the user
"pva fw tracepoint: type=%s flags=%s slot=%s ccq=%u queue=%u engine=%u arg1=0x%x arg2=0x%x", // changes the timestamp size through debugfs after FW logged the event.
pva_fw_tracepoint_type_to_string(PVA_BIT(tp->type)), // FW must log the type of timestamp it used to capture the event.
pva_fw_tracepoint_flags_to_string(tp->flags), ASSERT(msg_size == sizeof(struct pva_fw_event_message) +
pva_fw_tracepoint_slot_id_to_string(tp->slot_id), pva->debugfs_context.g_fw_profiling_config
(uint32_t)tp->ccq_id, (uint32_t)tp->queue_id, .timestamp_size);
(uint32_t)tp->engine_id, (uint32_t)tp->arg1,
(uint32_t)tp->arg2);
pva_kmd_print_str(msg_string); err = process_fw_event(pva, msg_body, msg_size);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to process FW event");
}
} }

View File

@@ -5,26 +5,217 @@
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#include "pva_kmd_shared_buffer.h" #include "pva_kmd_shared_buffer.h"
/**
* @brief Number of elements in firmware profiling buffer
*
* @details Number of elements allocated for the firmware profiling buffer.
* This constant defines the total capacity of the profiling buffer used
* to store firmware profiling events and tracepoints.
* Value: 409,600 (4096 * 100)
*/
#define PVA_KMD_FW_PROFILING_BUF_NUM_ELEMENTS (4096 * 100) #define PVA_KMD_FW_PROFILING_BUF_NUM_ELEMENTS (4096 * 100)
/**
* @brief Configuration structure for firmware profiling
*
* @details This structure contains the configuration parameters for firmware
* profiling including filtering criteria, timestamp format, and enable state.
* It controls how profiling data is collected and formatted by the firmware
* for analysis and debugging purposes.
*/
struct pva_kmd_fw_profiling_config { struct pva_kmd_fw_profiling_config {
/**
* @brief Filter mask for profiling events
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t filter; uint32_t filter;
/**
* @brief Type of timestamp to use for profiling events
* Valid values: @ref pva_fw_timestamp_t enumeration values
*/
enum pva_fw_timestamp_t timestamp_type; enum pva_fw_timestamp_t timestamp_type;
/**
* @brief Size of timestamp data in bytes
* Valid range: [1 .. 16]
*/
uint8_t timestamp_size; uint8_t timestamp_size;
/**
* @brief Enable flag for profiling
* Valid values: 0 (disabled), 1 (enabled)
*/
uint8_t enabled; uint8_t enabled;
}; };
#if PVA_ENABLE_FW_PROFILING == 1
/**
* @brief Initialize firmware profiler for a PVA device
*
* @details This function performs the following operations:
* - Sets up profiling buffer infrastructure for firmware events
* - Initializes shared buffer communication for profiling data
* - Configures profiling event filtering and formatting parameters
* - Prepares the profiler for collecting firmware execution data
* - Establishes communication channels between firmware and KMD
* - Allocates necessary memory resources for profiling operations
*
* The profiler enables collection of detailed firmware execution information
* including timing data, event sequences, and performance metrics that are
* essential for debugging and optimization.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*/
void pva_kmd_device_init_profiler(struct pva_kmd_device *pva); void pva_kmd_device_init_profiler(struct pva_kmd_device *pva);
/**
* @brief Deinitialize firmware profiler and clean up resources
*
* @details This function performs the following operations:
* - Disables firmware profiling if currently active
* - Releases shared buffer resources used for profiling data
* - Frees memory allocated for profiling buffer management
* - Cleans up profiling event processing infrastructure
* - Ensures proper cleanup of all profiler-related resources
* - Invalidates profiler state for the device
*
* This function should be called during device shutdown to ensure
* proper cleanup of all profiling resources and prevent memory leaks.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must have been initialized with profiler
*/
void pva_kmd_device_deinit_profiler(struct pva_kmd_device *pva); void pva_kmd_device_deinit_profiler(struct pva_kmd_device *pva);
enum pva_error pva_kmd_process_fw_event(struct pva_kmd_device *pva, /**
uint8_t *data, uint32_t data_size); * @brief Process firmware profiling event data
*
void pva_kmd_process_fw_tracepoint(struct pva_kmd_device *pva, * @details This function performs the following operations:
struct pva_fw_tracepoint *tp); * - Validates incoming firmware event data format and size
* - Parses event data to extract profiling information
* - Processes different types of firmware events and tracepoints
* - Updates profiling statistics and event counters
* - Stores processed events in appropriate data structures
* - Handles event filtering based on configuration settings
* - Provides event data to profiling analysis tools
*
* This function is called when firmware sends profiling event data
* through the shared buffer communication mechanism, enabling real-time
* processing of firmware execution information.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] data Pointer to firmware event data buffer
* Valid value: non-null
* @param[in] data_size Size of event data in bytes
* Valid range: [1 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Event processed successfully
* @retval PVA_INVAL Invalid or corrupted event data
* @retval PVA_ENOSPC Profiling buffer is full
* @retval PVA_BAD_PARAMETER_ERROR Invalid parameters provided
*/
void pva_kmd_process_fw_event(struct pva_kmd_device *pva, uint8_t *data,
uint32_t data_size);
/**
* @brief Notify firmware to enable profiling
*
* @details This function performs the following operations:
* - Sends enable profiling command to firmware
* - Configures firmware profiling parameters and filters
* - Activates profiling data collection in firmware
* - Sets up profiling buffer management in firmware
* - Establishes profiling event reporting mechanisms
* - Validates firmware acknowledgment of profiling enable
*
* After successful completion, firmware will begin collecting and
* reporting profiling events according to the configured parameters.
* The profiling data will be available through the shared buffer
* communication interface.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS Profiling enabled successfully
* @retval PVA_TIMEDOUT Failed to communicate with firmware
* @retval PVA_ERR_FW_ABORTED Firmware did not respond within timeout
* @retval PVA_INTERNAL Firmware in invalid state for profiling
*/
enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva); enum pva_error pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva);
/**
* @brief Notify firmware to disable profiling
*
* @details This function performs the following operations:
* - Sends disable profiling command to firmware
* - Stops firmware profiling data collection
* - Flushes any remaining profiling events from firmware buffers
* - Deactivates profiling event reporting mechanisms
* - Cleans up firmware profiling state and resources
* - Validates firmware acknowledgment of profiling disable
*
* After successful completion, firmware will stop collecting profiling
* events and the profiling overhead will be eliminated. Any remaining
* profiling data in buffers will be processed before disabling.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS Profiling disabled successfully
* @retval PVA_TIMEDOUT Failed to communicate with firmware
* @retval PVA_ERR_FW_ABORTED Firmware did not respond within timeout
* @retval PVA_INTERNAL Firmware in invalid state for profiling
*/
enum pva_error pva_kmd_notify_fw_disable_profiling(struct pva_kmd_device *pva); enum pva_error pva_kmd_notify_fw_disable_profiling(struct pva_kmd_device *pva);
#else
static inline void pva_kmd_device_init_profiler(struct pva_kmd_device *pva)
{
(void)pva;
}
static inline void pva_kmd_device_deinit_profiler(struct pva_kmd_device *pva)
{
(void)pva;
}
static inline void pva_kmd_process_fw_event(struct pva_kmd_device *pva,
uint8_t *data, uint32_t data_size)
{
(void)pva;
(void)data;
(void)data_size;
}
static inline enum pva_error
pva_kmd_notify_fw_enable_profiling(struct pva_kmd_device *pva)
{
(void)pva;
return PVA_SUCCESS;
}
static inline enum pva_error
pva_kmd_notify_fw_disable_profiling(struct pva_kmd_device *pva)
{
(void)pva;
return PVA_SUCCESS;
}
#endif /* PVA_ENABLE_FW_PROFILING == 1 */
#if PVA_ENABLE_NSYS_PROFILING == 1
enum pva_error pva_kmd_notify_fw_set_profiling_level(struct pva_kmd_device *pva,
uint32_t level);
#else
static inline enum pva_error
pva_kmd_notify_fw_set_profiling_level(struct pva_kmd_device *pva,
uint32_t level)
{
(void)pva;
(void)level;
return PVA_SUCCESS;
}
#endif /* PVA_ENABLE_NSYS_PROFILING == 1 */
#endif #endif

View File

@@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_api_types.h"
#include "pva_fw.h"
#include "pva_kmd_cmdbuf.h"
#include "pva_kmd_device.h"
#include "pva_kmd_constants.h"
#include "pva_kmd_fw_tracepoints.h"
static int64_t update_fw_trace_level(struct pva_kmd_device *pva,
void *file_data, const uint8_t *in_buffer,
uint64_t offset, uint64_t size)
{
uint32_t trace_level;
unsigned long retval;
size_t copy_size;
uint32_t base = 10;
char strbuf[11]; // 10 bytes for the highest 32bit value and another 1 byte for the Null character
strbuf[10] = '\0';
if (size == 0U) {
pva_kmd_log_err("Write failed, no data provided");
return -1;
}
/* Copy minimum of buffer size and input size */
copy_size =
(size < (sizeof(strbuf) - 1U)) ? size : (sizeof(strbuf) - 1U);
retval = pva_kmd_copy_data_from_user(strbuf, in_buffer + offset,
copy_size);
if (retval != 0UL) {
pva_kmd_log_err("Failed to copy write buffer from user");
return -1;
}
trace_level = (uint32_t)pva_kmd_strtol(strbuf, base);
pva->fw_trace_level = trace_level;
/* If device is on, busy the device and set the debug log level */
if (pva_kmd_device_maybe_on(pva) == true) {
enum pva_error err;
err = pva_kmd_device_busy(pva);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"pva_kmd_device_busy failed when submitting set debug log level cmd");
goto err_end;
}
err = pva_kmd_notify_fw_set_trace_level(pva, trace_level);
pva_kmd_device_idle(pva);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Failed to notify FW about debug log level change");
}
}
err_end:
return (int64_t)copy_size;
}
static int64_t get_fw_trace_level(struct pva_kmd_device *dev, void *file_data,
uint8_t *out_buffer, uint64_t offset,
uint64_t size)
{
char print_buffer[64];
int formatted_len;
formatted_len = snprintf(print_buffer, sizeof(print_buffer), "%u\n",
dev->fw_trace_level);
if (formatted_len <= 0) {
return -1;
}
return pva_kmd_read_from_buffer_to_user(out_buffer, size, offset,
print_buffer,
(uint64_t)formatted_len);
}
enum pva_error pva_kmd_fw_tracepoints_init_debugfs(struct pva_kmd_device *pva)
{
enum pva_error err;
pva->debugfs_context.fw_trace_level_fops.write = &update_fw_trace_level;
pva->debugfs_context.fw_trace_level_fops.read = &get_fw_trace_level;
pva->debugfs_context.fw_trace_level_fops.pdev = pva;
err = pva_kmd_debugfs_create_file(
pva, "fw_trace_level",
&pva->debugfs_context.fw_trace_level_fops);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to create fw_trace_level debugfs file");
return err;
}
return PVA_SUCCESS;
}
enum pva_error pva_kmd_notify_fw_set_trace_level(struct pva_kmd_device *pva,
uint32_t trace_level)
{
struct pva_cmd_set_trace_level cmd = { 0 };
pva_kmd_set_cmd_set_trace_level(&cmd, trace_level);
return pva_kmd_submit_cmd_sync(&pva->submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
}
void pva_kmd_process_fw_tracepoint(struct pva_kmd_device *pva,
struct pva_fw_tracepoint *tp)
{
char msg_string[200] = { '\0' };
snprintf(
msg_string, sizeof(msg_string),
"pva fw tracepoint: type=%s flags=%s slot=%s ccq=%u queue=%u engine=%u arg1=0x%x arg2=0x%x",
pva_fw_tracepoint_type_to_string(PVA_BIT(tp->type)),
pva_fw_tracepoint_flags_to_string(tp->flags),
pva_fw_tracepoint_slot_id_to_string(tp->slot_id),
(uint32_t)tp->ccq_id, (uint32_t)tp->queue_id,
(uint32_t)tp->engine_id, (uint32_t)tp->arg1,
(uint32_t)tp->arg2);
pva_kmd_print_str(msg_string);
}

View File

@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_FW_TRACEPOINTS_H
#define PVA_KMD_FW_TRACEPOINTS_H
#include "pva_fw.h"
#include "pva_kmd_device.h"
#if PVA_ENABLE_FW_TRACEPOINTS == 1
enum pva_error pva_kmd_fw_tracepoints_init_debugfs(struct pva_kmd_device *pva);
enum pva_error pva_kmd_notify_fw_set_trace_level(struct pva_kmd_device *pva,
uint32_t trace_level);
void pva_kmd_process_fw_tracepoint(struct pva_kmd_device *pva,
struct pva_fw_tracepoint *tp);
#else
static inline enum pva_error
pva_kmd_fw_tracepoints_init_debugfs(struct pva_kmd_device *pva)
{
(void)pva;
return PVA_SUCCESS;
}
static inline enum pva_error
pva_kmd_notify_fw_set_trace_level(struct pva_kmd_device *pva,
uint32_t trace_level)
{
(void)pva;
(void)trace_level;
return PVA_SUCCESS;
}
static inline void pva_kmd_process_fw_tracepoint(struct pva_kmd_device *pva,
struct pva_fw_tracepoint *tp)
{
(void)pva;
(void)tp;
}
#endif
#endif // PVA_KMD_FW_TRACEPOINTS_H

View File

@@ -73,12 +73,12 @@ static inline uint8_t get_head_desc_did(struct pva_hwseq_priv const *hwseq)
return hwseq->dma_descs[0].did; return hwseq->dma_descs[0].did;
} }
static inline enum pva_error check_adv_params(int32_t adv1, int32_t adv2, static inline enum pva_error check_adv_params(uint32_t adv1, uint32_t adv2,
int32_t adv3, uint8_t rpt1, uint32_t adv3, uint8_t rpt1,
uint8_t rpt2, uint8_t rpt3, uint8_t rpt2, uint8_t rpt3,
bool has_dim3) bool has_dim3)
{ {
if (!has_dim3 && ((adv1 != 0) || (adv2 != 0) || (adv3 != 0) || if (!has_dim3 && ((adv1 != 0U) || (adv2 != 0U) || (adv3 != 0U) ||
((rpt1 + rpt2 + rpt3) != 0U))) { ((rpt1 + rpt2 + rpt3) != 0U))) {
return PVA_INVAL; return PVA_INVAL;
} }
@@ -114,13 +114,10 @@ validate_adv_params(struct pva_dma_transfer_attr const *attr, bool has_dim3)
pva_kmd_log_err("descriptor source tile looping not allowed"); pva_kmd_log_err("descriptor source tile looping not allowed");
return err; return err;
} }
if (attr->adv1 < 0) {
pva_kmd_log_err(
"source advance amount on dim1 can not be negative");
return PVA_INVAL;
}
if ((attr->adv1 * ((int32_t)(attr->rpt1) + 1)) != attr->adv2) { /* Use 64-bit arithmetic to avoid overflow in multiplication */
if (((uint64_t)attr->adv1 * ((uint64_t)attr->rpt1 + 1ULL)) !=
(uint64_t)attr->adv2) {
pva_kmd_log_err( pva_kmd_log_err(
"Invalid source advance amount on dim1 or dim2"); "Invalid source advance amount on dim1 or dim2");
return PVA_INVAL; return PVA_INVAL;
@@ -260,7 +257,7 @@ check_vmem_setup(struct pva_dma_transfer_attr const *attr,
uint32_t vmem_tile_count, bool has_dim3) uint32_t vmem_tile_count, bool has_dim3)
{ {
if ((!has_dim3) && (vmem_tile_count > 1U) && if ((!has_dim3) && (vmem_tile_count > 1U) &&
((attr->adv1 != 0) || (attr->adv2 != 0) || (attr->adv3 != 0))) { ((attr->adv1 != 0U) || (attr->adv2 != 0U) || (attr->adv3 != 0U))) {
return PVA_INVAL; return PVA_INVAL;
} }
return PVA_SUCCESS; return PVA_SUCCESS;
@@ -426,11 +423,6 @@ static enum pva_error validate_dst_vmem(struct pva_hwseq_priv *hwseq,
return PVA_INVAL; return PVA_INVAL;
} }
if (head_desc->src.adv1 < 0) {
pva_kmd_log_err("Source adv1 can not be negative");
return PVA_INVAL;
}
tx = maxu32(head_desc->tx, tail_desc->tx); tx = maxu32(head_desc->tx, tail_desc->tx);
ty = maxu32(head_desc->ty, tail_desc->ty); ty = maxu32(head_desc->ty, tail_desc->ty);
end_addr = end_addr =
@@ -438,9 +430,10 @@ static enum pva_error validate_dst_vmem(struct pva_hwseq_priv *hwseq,
subs64((int64_t)ty, 1LL, &math_err), &math_err); subs64((int64_t)ty, 1LL, &math_err), &math_err);
end_addr = adds64(end_addr, (int64_t)tx, &math_err); end_addr = adds64(end_addr, (int64_t)tx, &math_err);
end_addr = adds64(muls64((int64_t)head_desc->src.rpt1, end_addr =
head_desc->dst.adv1, &math_err), adds64(muls64((int64_t)head_desc->src.rpt1,
end_addr, &math_err); (int64_t)head_desc->dst.adv1, &math_err),
end_addr, &math_err);
end_addr = adds64(muls64(end_addr, num_bytes, &math_err), end_addr = adds64(muls64(end_addr, num_bytes, &math_err),
offset, &math_err); offset, &math_err);
@@ -573,9 +566,10 @@ static enum pva_error validate_src_vmem(struct pva_hwseq_priv *hwseq,
return PVA_INVAL; return PVA_INVAL;
} }
end_addr = adds64(muls64((int64_t)head_desc->dst.rpt1, end_addr =
head_desc->src.adv1, &math_err), adds64(muls64((int64_t)head_desc->dst.rpt1,
end_addr, &math_err); (int64_t)head_desc->src.adv1, &math_err),
end_addr, &math_err);
end_addr = adds64(muls64(end_addr, num_bytes, &math_err), end_addr = adds64(muls64(end_addr, num_bytes, &math_err),
offset, &math_err); offset, &math_err);
@@ -986,9 +980,12 @@ validate_frame_buffer_addr(struct pva_hwseq_priv *hwseq,
uint8_t head_desc_id = get_head_desc_did(hwseq); uint8_t head_desc_id = get_head_desc_did(hwseq);
const struct pva_dma_descriptor *head_desc = hwseq->head_desc; const struct pva_dma_descriptor *head_desc = hwseq->head_desc;
pva_math_error math_err = MATH_OP_SUCCESS; pva_math_error math_err = MATH_OP_SUCCESS;
uint32_t adv_value =
frame_plane_size =
sequencing_to_vmem ? head_desc->src.adv1 : head_desc->dst.adv1; sequencing_to_vmem ? head_desc->src.adv1 : head_desc->dst.adv1;
/* adv1 is uint32_t but limited to 24-bit range (max 0xFFFFFF < INT32_MAX) */
ASSERT(adv_value <= 0x7FFFFFFFU);
frame_plane_size = (int32_t)adv_value;
frame_buffer_start = frame_buffer_start =
adds64(muls64(frame_info->start_y, (int64_t)frame_line_pitch, adds64(muls64(frame_info->start_y, (int64_t)frame_line_pitch,
&math_err), &math_err),
@@ -1061,12 +1058,12 @@ static void get_sequencing_and_dim3(struct pva_hwseq_priv *hwseq,
*has_dim3 = ((head_desc->src.rpt1 == head_desc->dst.rpt1) && *has_dim3 = ((head_desc->src.rpt1 == head_desc->dst.rpt1) &&
(head_desc->src.rpt2 == head_desc->dst.rpt2)); (head_desc->src.rpt2 == head_desc->dst.rpt2));
*has_dim3 = *has_dim3 && *has_dim3 = *has_dim3 &&
((*sequencing_to_vmem) ? ((head_desc->src.adv1 > 0) && ((*sequencing_to_vmem) ? ((head_desc->src.adv1 > 0U) &&
(head_desc->src.adv2 > 0) && (head_desc->src.adv2 > 0U) &&
(head_desc->dst.adv1 > 0)) : (head_desc->dst.adv1 > 0U)) :
((head_desc->dst.adv1 > 0) && ((head_desc->dst.adv1 > 0U) &&
(head_desc->dst.adv2 > 0) && (head_desc->dst.adv2 > 0U) &&
(head_desc->src.adv1 > 0))); (head_desc->src.adv1 > 0U)));
} }
/** /**
@@ -1147,6 +1144,48 @@ validate_dma_boundaries(struct pva_hwseq_priv *hwseq,
return err; return err;
} }
static enum pva_error
process_frame_descriptors(struct pva_hwseq_priv *hwseq_info,
struct pva_dma_hwseq_desc_entry *desc_entries,
uint32_t num_descs, uint64_t *hw_dma_descs_mask)
{
enum pva_error err = PVA_SUCCESS;
const struct pva_dma_hwseq_desc_entry *desc_entry = NULL;
uint32_t i;
for (i = 0; i < num_descs; i++) {
desc_entry = (const struct pva_dma_hwseq_desc_entry
*)(read_hwseq_blob(
&hwseq_info->blob,
(uint32_t)sizeof(struct pva_dma_hwseq_desc_entry)));
if (validate_desc_entry(
desc_entry,
safe_addu8(hwseq_info->dma_config->header
.base_descriptor,
hwseq_info->dma_config->header
.num_descriptors)) !=
PVA_SUCCESS) {
pva_kmd_log_err("Invalid DMA Descriptor Entry");
err = PVA_INVAL;
goto out;
}
desc_entries[i].did = desc_entry->did - 1U;
//TODO enable nv_array_index_no_speculate later
// desc_entries[i].did = (uint8_t) nv_array_index_no_speculate_u32(
// desc_entries[i].did, max_num_descs);
desc_entries[i].dr = desc_entry->dr;
hw_dma_descs_mask[(desc_entries[i].did / 64ULL)] |=
1ULL << (desc_entries[i].did & MAX_DESC_ID);
hwseq_info->tiles_per_packet += ((uint32_t)desc_entry->dr + 1U);
}
out:
return err;
}
/** /**
* \brief Validates the HW Sequener when it is in Frame Addressing Mode * \brief Validates the HW Sequener when it is in Frame Addressing Mode
* *
@@ -1184,10 +1223,8 @@ validate_dma_boundaries(struct pva_hwseq_priv *hwseq,
static enum pva_error validate_frame_mode(struct pva_hwseq_priv *hwseq_info, static enum pva_error validate_frame_mode(struct pva_hwseq_priv *hwseq_info,
uint64_t *hw_dma_descs_mask) uint64_t *hw_dma_descs_mask)
{ {
struct pva_dma_hwseq_desc_entry *desc_entry = NULL;
struct pva_dma_hwseq_desc_entry *desc_entries = hwseq_info->dma_descs; struct pva_dma_hwseq_desc_entry *desc_entries = hwseq_info->dma_descs;
uint32_t num_descs = 0U; uint32_t num_descs = 0U;
uint32_t i = 0U;
uint32_t num_cr = 0U; uint32_t num_cr = 0U;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
struct pva_hwseq_per_frame_info fr_info = { 0 }; struct pva_hwseq_per_frame_info fr_info = { 0 };
@@ -1197,21 +1234,22 @@ static enum pva_error validate_frame_mode(struct pva_hwseq_priv *hwseq_info,
pva_kmd_log_err_u64( pva_kmd_log_err_u64(
"Cannot have more than 1 col/row header in GEN2", "Cannot have more than 1 col/row header in GEN2",
hwseq_info->hdr->nocr); hwseq_info->hdr->nocr);
return PVA_INVAL; err = PVA_INVAL;
goto out;
} }
for (num_cr = 0; num_cr <= hwseq_info->hdr->nocr; num_cr++) { for (num_cr = 0; num_cr <= hwseq_info->hdr->nocr; num_cr++) {
hwseq_info->tiles_per_packet = 0; hwseq_info->tiles_per_packet = 0;
hwseq_info->colrow = hwseq_info->colrow = (const struct pva_dma_hwseq_colrow_hdr
(struct pva_dma_hwseq_colrow_hdr *)(read_hwseq_blob( *)(read_hwseq_blob(
&hwseq_info->blob, &hwseq_info->blob,
(uint32_t)sizeof( (uint32_t)sizeof(struct pva_dma_hwseq_colrow_hdr)));
struct pva_dma_hwseq_colrow_hdr)));
if (hwseq_info->colrow == NULL) { if (hwseq_info->colrow == NULL) {
pva_kmd_log_err( pva_kmd_log_err(
"Cannot read HW sequencer col/row header"); "Cannot read HW sequencer col/row header");
return PVA_INVAL; err = PVA_INVAL;
goto out;
} }
num_descs = hwseq_info->colrow->dec + (uint32_t)1U; num_descs = hwseq_info->colrow->dec + (uint32_t)1U;
@@ -1219,39 +1257,17 @@ static enum pva_error validate_frame_mode(struct pva_hwseq_priv *hwseq_info,
if (num_descs > 2U) { if (num_descs > 2U) {
pva_kmd_log_err( pva_kmd_log_err(
"Cannot have more than 2 descriptors in HW Sequencer"); "Cannot have more than 2 descriptors in HW Sequencer");
return PVA_INVAL; err = PVA_INVAL;
goto out;
} }
for (i = 0; i < num_descs; i++) { err = process_frame_descriptors(hwseq_info, desc_entries,
desc_entry = (struct pva_dma_hwseq_desc_entry num_descs, hw_dma_descs_mask);
*)(read_hwseq_blob( if (err != PVA_SUCCESS) {
&hwseq_info->blob, goto out;
(uint32_t)sizeof(
struct pva_dma_hwseq_desc_entry)));
if (validate_desc_entry(
desc_entry,
safe_addu8(hwseq_info->dma_config->header
.base_descriptor,
hwseq_info->dma_config->header
.num_descriptors)) !=
PVA_SUCCESS) {
pva_kmd_log_err("Invalid DMA Descriptor Entry");
return PVA_INVAL;
}
desc_entries[i].did = desc_entry->did - 1U;
//TODO enable nv_array_index_no_speculate later
// desc_entries[i].did = (uint8_t) nv_array_index_no_speculate_u32(
// desc_entries[i].did, max_num_descs);
desc_entries[i].dr = desc_entry->dr;
hw_dma_descs_mask[(desc_entries[i].did / 64ULL)] |=
1ULL << (desc_entries[i].did & MAX_DESC_ID);
hwseq_info->tiles_per_packet +=
((uint32_t)desc_entry->dr + 1U);
} }
if ((i == num_descs) && ((i % 2U) != 0U)) {
if ((num_descs % 2U) != 0U) {
(void)read_hwseq_blob( (void)read_hwseq_blob(
&hwseq_info->blob, &hwseq_info->blob,
(uint32_t)sizeof( (uint32_t)sizeof(
@@ -1275,17 +1291,18 @@ static enum pva_error validate_frame_mode(struct pva_hwseq_priv *hwseq_info,
err = validate_dma_boundaries(hwseq_info, &fr_info, num_cr); err = validate_dma_boundaries(hwseq_info, &fr_info, num_cr);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
return err; goto out;
} }
} }
out:
return err; return err;
} }
static enum pva_error validate_rra_mode(struct pva_hwseq_priv *hwseq_info, static enum pva_error validate_rra_mode(struct pva_hwseq_priv *hwseq_info,
uint64_t *hw_dma_descs_mask) uint64_t *hw_dma_descs_mask)
{ {
const uint8_t *column = 0U; const uint8_t *column = NULL;
uint32_t i = 0U; uint32_t i = 0U;
uint32_t num_columns = 0U; uint32_t num_columns = 0U;
uint32_t end = hwseq_info->entry.ch->hwseq_end; uint32_t end = hwseq_info->entry.ch->hwseq_end;
@@ -1306,24 +1323,31 @@ static enum pva_error validate_rra_mode(struct pva_hwseq_priv *hwseq_info,
return PVA_INVAL; return PVA_INVAL;
} }
if (hwseq_info->hdr->fr != 0) { if (hwseq_info->hdr->fr != 0U) {
pva_kmd_log_err("Invalid HWSEQ repetition factor"); pva_kmd_log_err("Invalid HWSEQ repetition factor");
return PVA_INVAL; return PVA_INVAL;
} }
num_columns = hwseq_info->hdr->nocr + 1U; num_columns = (uint32_t)hwseq_info->hdr->nocr + 1U;
column = hwseq_info->blob.data + sizeof(struct pva_dma_hwseq_hdr); column = hwseq_info->blob.data + sizeof(struct pva_dma_hwseq_hdr);
// Ensure there are sufficient CRO and Desc ID entries in the HWSEQ blob // Ensure there are sufficient CRO and Desc ID entries in the HWSEQ blob
if (((blob_end - column) / column_entry_size) < num_columns) { {
pva_kmd_log_err("HWSEQ Program does not have enough columns"); ptrdiff_t blob_diff = blob_end - column;
return PVA_INVAL; size_t blob_size = (blob_diff >= 0) ? (size_t)blob_diff : 0U;
if ((blob_end < column) ||
((blob_size / (size_t)column_entry_size) < num_columns)) {
pva_kmd_log_err(
"HWSEQ Program does not have enough columns");
return PVA_INVAL;
}
} }
for (i = 0U; i < num_columns; i++) { for (i = 0U; i < num_columns; i++) {
struct pva_dma_hwseq_desc_entry desc_entry; struct pva_dma_hwseq_desc_entry desc_entry;
uint32_t *desc_read_data = (uint32_t *)(read_hwseq_blob( const uint32_t *desc_read_data =
&hwseq_info->blob, column_entry_size)); (const uint32_t *)(read_hwseq_blob(&hwseq_info->blob,
column_entry_size));
if (desc_read_data == NULL) { if (desc_read_data == NULL) {
pva_kmd_log_err( pva_kmd_log_err(
"Failed to read descriptor data from HWSEQ blob"); "Failed to read descriptor data from HWSEQ blob");
@@ -1335,9 +1359,13 @@ static enum pva_error validate_rra_mode(struct pva_hwseq_priv *hwseq_info,
// In RRA mode, each HWSEQ column has only 1 descriptor // In RRA mode, each HWSEQ column has only 1 descriptor
// Hence, we validate the first descriptor and ignore the second // Hence, we validate the first descriptor and ignore the second
// descriptor in each column // descriptor in each column
desc_entry.did = (desc_read_data[1U] & 0x000000FFU); desc_entry.did = (uint8_t)(desc_read_data[1U] & 0x000000FFU);
desc_entry.dr = ((desc_read_data[1U] & 0x0000FF00U) >> 8U); desc_entry.dr =
if (validate_desc_entry(&desc_entry, PVA_MAX_NUM_DMA_DESC) != (uint8_t)((desc_read_data[1U] & 0x0000FF00U) >> 8U);
/* CERT INT31-C: PVA_MAX_NUM_DMA_DESC is compile-time constant <= 96,
* always fits in uint8_t, safe to cast */
if (validate_desc_entry(&desc_entry,
(uint8_t)PVA_MAX_NUM_DMA_DESC) !=
PVA_SUCCESS) { PVA_SUCCESS) {
pva_kmd_log_err( pva_kmd_log_err(
"Invalid Descriptor ID found in HW Sequencer"); "Invalid Descriptor ID found in HW Sequencer");
@@ -1348,7 +1376,7 @@ static enum pva_error validate_rra_mode(struct pva_hwseq_priv *hwseq_info,
1ULL << (desc_entry.did & MAX_DESC_ID); 1ULL << (desc_entry.did & MAX_DESC_ID);
} }
return 0; return PVA_SUCCESS;
} }
/** /**
@@ -1436,21 +1464,27 @@ check_for_valid_hwseq_type(struct pva_hwseq_priv *hwseq_info,
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
//Populate hwseq_info header //Populate hwseq_info header
hwseq_info->hdr = (struct pva_dma_hwseq_hdr *)(read_hwseq_blob( hwseq_info->hdr = (const struct pva_dma_hwseq_hdr *)(read_hwseq_blob(
&hwseq_info->blob, (uint32_t)sizeof(struct pva_dma_hwseq_hdr))); &hwseq_info->blob, (uint32_t)sizeof(struct pva_dma_hwseq_hdr)));
if (hwseq_info->hdr == NULL) { if (hwseq_info->hdr == NULL) {
pva_kmd_log_err("HW sequencer buffer does not contain header"); pva_kmd_log_err("HW sequencer buffer does not contain header");
return PVA_INVAL; return PVA_INVAL;
} }
if ((hwseq_info->hdr->fr != 0U) || (hwseq_info->hdr->fo != 0U)) { if ((hwseq_info->hdr->fr != 0U) || (hwseq_info->hdr->fo != 0)) {
return PVA_INVAL; return PVA_INVAL;
} }
if (hwseq_info->hdr->fid == (uint16_t)PVA_DMA_HWSEQ_DESC_MODE) { if (hwseq_info->hdr->fid == (uint16_t)PVA_DMA_HWSEQ_DESC_MODE) {
err = validate_desc_mode(hwseq_info); err = validate_desc_mode(hwseq_info);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Descriptor mode validation failed");
}
} else if (hwseq_info->hdr->fid == (uint16_t)PVA_DMA_HWSEQ_FRAME_MODE) { } else if (hwseq_info->hdr->fid == (uint16_t)PVA_DMA_HWSEQ_FRAME_MODE) {
err = validate_frame_mode(hwseq_info, hw_dma_descs_mask); err = validate_frame_mode(hwseq_info, hw_dma_descs_mask);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Frame mode validation failed");
}
} else if (hwseq_info->hdr->fid == (uint16_t)PVA_DMA_HWSEQ_RRA_MODE) { } else if (hwseq_info->hdr->fid == (uint16_t)PVA_DMA_HWSEQ_RRA_MODE) {
if (hwseq_info->hw_gen < PVA_HW_GEN3) { if (hwseq_info->hw_gen < PVA_HW_GEN3) {
pva_kmd_log_err( pva_kmd_log_err(
@@ -1458,6 +1492,9 @@ check_for_valid_hwseq_type(struct pva_hwseq_priv *hwseq_info,
return PVA_INVAL; return PVA_INVAL;
} }
err = validate_rra_mode(hwseq_info, hw_dma_descs_mask); err = validate_rra_mode(hwseq_info, hw_dma_descs_mask);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("RRA mode validation failed");
}
} else { } else {
pva_kmd_log_err("Invalid Header in HW Sequencer Blob"); pva_kmd_log_err("Invalid Header in HW Sequencer Blob");
return PVA_INVAL; return PVA_INVAL;
@@ -1517,7 +1554,7 @@ validate_channel_accesses(const struct pva_dma_channel *ch,
entry->hwseq_end = ch->hwseq_end; entry->hwseq_end = ch->hwseq_end;
entry->num_frames = 1U; entry->num_frames = 1U;
if (hw_gen == PVA_HW_GEN3) { if (hw_gen == PVA_HW_GEN3) {
entry->num_frames = ch->hwseq_frame_count + 1U; entry->num_frames = (uint32_t)ch->hwseq_frame_count + 1U;
} }
entry->ch = ch; entry->ch = ch;
return PVA_SUCCESS; return PVA_SUCCESS;
@@ -1542,7 +1579,7 @@ enum pva_error validate_hwseq(struct pva_dma_config const *dma_config,
for (i = 0U; i < num_channels; i++) { for (i = 0U; i < num_channels; i++) {
ch = &dma_config->channels[i]; ch = &dma_config->channels[i];
if (ch->hwseq_enable == 1) { if (ch->hwseq_enable == 1U) {
err = validate_channel_accesses(ch, &dma_config->header, err = validate_channel_accesses(ch, &dma_config->header,
hwseq_info.hw_gen, hwseq_info.hw_gen,
&entries[num_hwseqs]); &entries[num_hwseqs]);
@@ -1555,13 +1592,15 @@ enum pva_error validate_hwseq(struct pva_dma_config const *dma_config,
for (i = 0U; i < num_hwseqs; i++) { for (i = 0U; i < num_hwseqs; i++) {
uint32_t start_index = entries[i].hwseq_start; uint32_t start_index = entries[i].hwseq_start;
uint32_t end_index = entries[i].hwseq_end + 1U; uint32_t end_index = (uint32_t)entries[i].hwseq_end + 1U;
uint32_t curr_offset = start_index << 2U; uint32_t curr_offset = start_index << 2U;
uint32_t len = 0U; uint32_t len = 0U;
const uint8_t *base;
//Populate hwseq blob //Populate hwseq blob
hwseq_info.blob.data = /* Use byte pointer arithmetic for offset calculation */
(uint8_t *)((uintptr_t)(dma_config->hwseq_words) + base = (const uint8_t *)dma_config->hwseq_words;
(curr_offset)); hwseq_info.blob.data = base + curr_offset;
len = safe_subu32(end_index, start_index); len = safe_subu32(end_index, start_index);
hwseq_info.blob.bytes_left = (len << 2U); hwseq_info.blob.bytes_left = (len << 2U);

View File

@@ -6,320 +6,536 @@
#include "pva_api_dma.h" #include "pva_api_dma.h"
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
/**
* @brief Maximum number of column/row descriptors in RRA mode
*
* @details Maximum allowed value for Number of Column/Row descriptors
* in RRA (Rectangular Region Access) addressing mode.
* This constant defines the upper bound for column/row descriptor
* validation in hardware sequencer configurations.
*/
#define PVA_HWSEQ_RRA_MAX_NOCR 31U #define PVA_HWSEQ_RRA_MAX_NOCR 31U
/**
* @brief Maximum frame count in hardware sequencer
*
* @details Maximum allowed frame count for hardware sequencer operations.
* This limits the number of frames that can be processed in a single
* hardware sequencer configuration to ensure proper resource management
* and validation.
*/
#define PVA_HWSEQ_RRA_MAX_FRAME_COUNT 63U #define PVA_HWSEQ_RRA_MAX_FRAME_COUNT 63U
/** /**
* List of valid Addressing Modes in HW Sequencer Header * @brief Enumeration of hardware sequencer addressing modes
*
* @details This enumeration defines the valid addressing modes supported
* by the hardware sequencer for DMA operations. Each mode uses a specific
* Frame ID (FID) value to identify the addressing type in the hardware
* sequencer header. The addressing mode determines how the hardware
* sequencer processes and organizes DMA operations.
*/ */
enum pva_dma_hwseq_fid { enum pva_dma_hwseq_fid {
PVA_DMA_HWSEQ_RRA_MODE = 0xC0DA, /*!< RRA addressing */ /** @brief RRA (Rectangular Region Access) addressing mode */
PVA_DMA_HWSEQ_FRAME_MODE = 0xC0DE, /*!< frame addressing */ PVA_DMA_HWSEQ_RRA_MODE = 0xC0DA,
PVA_DMA_HWSEQ_DESC_MODE = 0xDEAD /*!< descriptor addressing */ /** @brief Frame-based addressing mode */
PVA_DMA_HWSEQ_FRAME_MODE = 0xC0DE,
/** @brief Descriptor-based addressing mode */
PVA_DMA_HWSEQ_DESC_MODE = 0xDEAD
}; };
/** /**
* Combine three headers common in HW Sequencer * @brief Hardware sequencer header structure
* *
* ---------------------------------------------------------------------------- * @details This structure contains the header information for hardware
* | | byte 3 | byte 2 | byte 1 | byte 0 | * sequencer configurations. The header defines addressing type, repetition
* |--------|---------------|--------------|-----------------|----------------| * factors, offsets, and padding values that control DMA operation patterns.
* | Head 1 | NOCR | FR | FID1 | FID0 | * The structure provides the necessary metadata for hardware sequencer
* | Head 2 | FO in LP 15:8 | FO in LP 7:0 | TO in P/LP 15:8 | TO in P/LP 7:0 | * operation configuration and validation.
* | Head 3 | padB | padL | padT | padR | */
* ----------------------------------------------------------------------------
**/
struct pva_dma_hwseq_hdr { struct pva_dma_hwseq_hdr {
//hdr_1 /**
uint16_t fid; /*!< addressing type: frame or descriptor */ * @brief Frame ID indicating addressing type
uint8_t fr; /*!< frame repetition factor */ * Valid values: @ref pva_dma_hwseq_fid enumeration values
uint8_t nocr; /*!< number of descriptor column/row */ */
//hdr_2 uint16_t fid;
int16_t to; /*!< tile offset in pixel/Line Pitch */
int16_t fo; /*!< frame offset in Line Pitch */ /**
//hdr_3 * @brief Frame repetition factor
uint8_t padr; /*!< pad right */ * Valid range: [1 .. 255]
uint8_t padt; /*!< pad top */ */
uint8_t padl; /*!< pad left */ uint8_t fr;
uint8_t padb; /*!< pad bottom */
/**
* @brief Number of descriptor columns/rows
* Valid range: [0 .. PVA_HWSEQ_RRA_MAX_NOCR]
*/
uint8_t nocr;
/**
* @brief Tile offset in pixels or line pitch
* Valid range: [INT16_MIN .. INT16_MAX]
*/
int16_t to;
/**
* @brief Frame offset in line pitch
* Valid range: [INT16_MIN .. INT16_MAX]
*/
int16_t fo;
/**
* @brief Padding for right edge
* Valid range: [0 .. 255]
*/
uint8_t padr;
/**
* @brief Padding for top edge
* Valid range: [0 .. 255]
*/
uint8_t padt;
/**
* @brief Padding for left edge
* Valid range: [0 .. 255]
*/
uint8_t padl;
/**
* @brief Padding for bottom edge
* Valid range: [0 .. 255]
*/
uint8_t padb;
}; };
/** /**
* A struct which represents Column/Row Header in HW Sequencer * @brief Hardware sequencer column/row header structure
*
* @details This structure represents the column/row header information
* in hardware sequencer configurations. It controls descriptor entry
* counts, repetition factors, and offset values for column/row operations
* within the hardware sequencer processing pipeline.
*/ */
struct pva_dma_hwseq_colrow_hdr { struct pva_dma_hwseq_colrow_hdr {
uint8_t dec; /*!< descriptor entry count */ /**
uint8_t crr; /*!< col/row repetition factor */ * @brief Descriptor entry count
int16_t cro; /*!< col/row ofst in pixel/line pitch */ * Valid range: [1 .. 255]
*/
uint8_t dec;
/**
* @brief Column/row repetition factor
* Valid range: [1 .. 255]
*/
uint8_t crr;
/**
* @brief Column/row offset in pixels or line pitch
* Valid range: [INT16_MIN .. INT16_MAX]
*/
int16_t cro;
}; };
/** /**
* A struct which represents a DMA Descriptor Header in HW Sequencer * @brief Hardware sequencer DMA descriptor entry
*
* @details This structure represents a single DMA descriptor entry
* in the hardware sequencer. It contains the descriptor ID and its
* repetition count for the DMA operation, enabling efficient
* descriptor reuse and pattern-based DMA processing.
*/ */
struct pva_dma_hwseq_desc_entry { struct pva_dma_hwseq_desc_entry {
uint8_t did; /*!< desc id */ /**
uint8_t dr; /*!< desc repetition */ * @brief Descriptor ID referencing a DMA descriptor
* Valid range: [0 .. MAX_DESC_ID]
*/
uint8_t did;
/**
* @brief Descriptor repetition count
* Valid range: [1 .. 255]
*/
uint8_t dr;
}; };
/** /**
* A struct which represents a Column/Row Header Entry in HW Sequencer * @brief Hardware sequencer column/row entry header
*
* @details This structure wraps the column/row header to represent
* a complete column/row entry in the hardware sequencer configuration.
* It provides structural organization for column/row operations
* within the hardware sequencer processing pipeline.
*/ */
struct pva_dma_hwseq_colrow_entry_hdr { struct pva_dma_hwseq_colrow_entry_hdr {
struct pva_dma_hwseq_colrow_hdr hdr; /*!< Col/Row Header */ /** @brief Column/row header information */
struct pva_dma_hwseq_colrow_hdr hdr;
}; };
/** /**
* A struct representing Grid Information * @brief Hardware sequencer grid information structure
*
* @details This structure contains comprehensive grid information for
* hardware sequencer operations. It includes tile coordinates, padding
* values, grid dimensions, and processing modes. The interpretation
* of coordinates varies between different processing modes to support
* various data layout patterns and access patterns.
*/ */
struct pva_hwseq_grid_info { struct pva_hwseq_grid_info {
/** /**
* tile co-ordinates * @brief Tile X-coordinates for first and last tiles
* In Raster Mode: *
* - tile_x[0] = Tile width of the first tile in HW Seq DMA Transfer * @details Interpretation varies by processing mode:
* - tile_x[1] = Tile width of the last tile in HW Seq DMA Transfer * - Raster Mode: tile_x[0] = first tile width, tile_x[1] = last tile width
* In Vertical Mining Mode: * - Vertical Mining Mode: tile_x[0] = first tile height, tile_x[1] = last tile height
* - tile_x[0] = Tile height of the first tile in HW Seq DMA Transfer * Valid range for each element: [INT32_MIN .. INT32_MAX]
* - tile_x[1] = Tile height of the last tile in HW Seq DMA Transfer
*/ */
int32_t tile_x[2]; int32_t tile_x[2];
/** /**
* tile co-ordinates * @brief Tile Y-coordinates for first and last tiles
* In Raster Mode: *
* - tile_y[0] = Tile height of the first tile in HW Seq DMA Transfer * @details Interpretation varies by processing mode:
* - tile_y[1] = Tile height of the last tile in HW Seq DMA Transfer * - Raster Mode: tile_y[0] = first tile height, tile_y[1] = last tile height
* In Vertical Mining Mode: * - Vertical Mining Mode: tile_y[0] = first tile width, tile_y[1] = last tile width
* - tile_y[0] = Tile width of the first tile in HW Seq DMA Transfer * Valid range for each element: [INT32_MIN .. INT32_MAX]
* - tile_y[1] = Tile width of the last tile in HW Seq DMA Transfer
*/ */
int32_t tile_y[2]; int32_t tile_y[2];
/** /**
* tile co-ordinates * @brief Tile Z-coordinate for Tensor Data Flow Mode
* In Tensor Data Flow Mode: * Valid range: [INT32_MIN .. INT32_MAX]
*/ */
int32_t tile_z; int32_t tile_z;
/** /**
* Padding values * @brief X-direction padding values
* In Raster Mode: *
* - pad_x[0] = Left Padding * @details Interpretation varies by processing mode:
* - pad_x[1] = Right Padding * - Raster Mode: pad_x[0] = left padding, pad_x[1] = right padding
* In Vertical Mining Mode: * - Vertical Mining Mode: pad_x[0] = top padding, pad_x[1] = bottom padding
* - pad_x[0] = Top Padding * Valid range for each element: [0 .. INT32_MAX]
* - pad_x[1] = Bottom Padding
*/ */
int32_t pad_x[2]; int32_t pad_x[2];
/** /**
* Padding values * @brief Y-direction padding values
* In Raster Mode: *
* - pad_y[0] = Top Padding * @details Interpretation varies by processing mode:
* - pad_y[1] = Bottom Padding * - Raster Mode: pad_y[0] = top padding, pad_y[1] = bottom padding
* In Vertical Mining Mode: * - Vertical Mining Mode: pad_y[0] = left padding, pad_y[1] = right padding
* - pad_y[0] = Left Padding * Valid range for each element: [0 .. INT32_MAX]
* - pad_y[1] = Right Padding
*/ */
int32_t pad_y[2]; int32_t pad_y[2];
/** /**
* Tiles per packet. Grid size in X dimension * @brief Grid size in X dimension (tiles per packet)
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t grid_size_x; uint32_t grid_size_x;
/** /**
* Repeat Count * @brief Grid size in Y dimension (repeat count)
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t grid_size_y; uint32_t grid_size_y;
/** /**
* Grid Size in Z dimension for Tensor Data Flow * @brief Grid size in Z dimension for Tensor Data Flow
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t grid_size_z; uint32_t grid_size_z;
/** /**
* Tile Offset as specified in the HW Sequencer Header * @brief Tile offset as specified in hardware sequencer header
* Valid range: [INT32_MIN .. INT32_MAX]
*/ */
int32_t grid_step_x; int32_t grid_step_x;
/** /**
* Col/Row Offset as specified in the HW Sequencer Col/Row Header * @brief Column/row offset as specified in hardware sequencer header
* Valid range: [INT32_MIN .. INT32_MAX]
*/ */
int32_t grid_step_y; int32_t grid_step_y;
/** /**
* Repetition factor for Head Descriptor in HW Sequencer Blob * @brief Repetition factor for head descriptor in hardware sequencer
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t head_tile_count; uint32_t head_tile_count;
/** /**
* Boolean value to indicate if HW Sequencer has split padding * @brief Flag indicating if hardware sequencer has split padding
* Valid values: true (has split padding), false (no split padding)
*/ */
bool is_split_padding; bool is_split_padding;
}; };
/** /**
* A struct representing a valid Frame Information * @brief Hardware sequencer frame information structure
*
* @details This structure represents the valid frame information including
* start and end coordinates in three-dimensional space. It defines the
* bounding box of the frame being processed by the hardware sequencer,
* enabling proper frame boundary validation and processing.
*/ */
struct pva_hwseq_frame_info { struct pva_hwseq_frame_info {
/** /**
* X co-ordinate of start of Frame * @brief X-coordinate of frame start
* Valid range: [INT64_MIN .. INT64_MAX]
*/ */
int64_t start_x; int64_t start_x;
/** /**
* Y co-ordinate of start of Frame * @brief Y-coordinate of frame start
* Valid range: [INT64_MIN .. INT64_MAX]
*/ */
int64_t start_y; int64_t start_y;
/** /**
* Z co-ordinates of starte of Frame * @brief Z-coordinate of frame start
* Valid range: [INT64_MIN .. INT64_MAX]
*/ */
int64_t start_z; int64_t start_z;
/** /**
* X co-ordinate of end of Frame * @brief X-coordinate of frame end
* Valid range: [start_x .. INT64_MAX]
*/ */
int64_t end_x; int64_t end_x;
/** /**
* Y co-ordinate of end of Frame * @brief Y-coordinate of frame end
* Valid range: [start_y .. INT64_MAX]
*/ */
int64_t end_y; int64_t end_y;
/** /**
* Z co-ordinate of end of Frame * @brief Z-coordinate of frame end
* Valid range: [start_z .. INT64_MAX]
*/ */
int64_t end_z; int64_t end_z;
}; };
/** /**
* Struct which holds the HW Sequencer Buffer as received from User Space * @brief Hardware sequencer buffer structure
*
* @details This structure holds the hardware sequencer buffer data
* as received from user space. It provides access to the raw sequencer
* blob data and tracks the remaining bytes to be processed during
* hardware sequencer parsing and validation operations.
*/ */
struct pva_hwseq_buffer { struct pva_hwseq_buffer {
/** /**
* Pointer to HW Sequencer Blob in Buffer * @brief Pointer to hardware sequencer blob data
* Valid value: non-null if bytes_left > 0
*/ */
const uint8_t *data; const uint8_t *data;
/** /**
* Number of bytes left to be read from the data buffer * @brief Number of bytes remaining in the buffer
* Valid range: [0 .. UINT32_MAX]
*/ */
uint32_t bytes_left; uint32_t bytes_left;
}; };
/** /**
* @struct hw_seq_blob_entry * @brief Hardware sequence blob entry information structure
* @brief Structure to hold information about a hardware sequence blob entry.
* *
* This structure is used to store the details of a DMA channel and the range of hardware sequencer * @details This structure stores information about a hardware sequence blob entry,
* associated with it, along with the number of frames involved. * including the associated DMA channel, hardware sequencer range, and frame count.
* It provides the necessary context for processing hardware sequencer operations
* within a specific DMA channel configuration.
*/ */
struct hw_seq_blob_entry { struct hw_seq_blob_entry {
/** /**
* Pointer to a const \ref pva_dma_channel which holds the current DMA Channel Information * @brief Pointer to DMA channel containing this hardware sequencer blob
* in which current HW Sequencer Blob is present
*/ */
struct pva_dma_channel const *ch; struct pva_dma_channel const *ch;
/** /**
* The starting index of the hardware sequencer. * @brief Starting index of the hardware sequencer range
* Valid range: [0 .. UINT16_MAX]
*/ */
uint16_t hwseq_start; uint16_t hwseq_start;
/** /**
* The ending index of the hardware sequencer. * @brief Ending index of the hardware sequencer range
* Valid range: [hwseq_start .. UINT16_MAX]
*/ */
uint16_t hwseq_end; uint16_t hwseq_end;
/** /**
* The number of frames associated with the hardware sequencer. * @brief Number of frames associated with the hardware sequencer
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t num_frames; uint32_t num_frames;
}; };
/** /**
* TODO: Separate out pva_hwseq_priv to be more modular * @brief Hardware sequencer private data structure
* *
* Items in pva_hwseq_main * @details This structure holds comprehensive private data for hardware sequencer
* - dma_config * blob parsing and validation. It contains descriptor counts, tile information,
* - hw_gen * blob entry details, parsing state, mode flags, and references to related
* - blob * DMA configuration data. This structure enables thorough validation and
* - num_hwseq_words * processing of hardware sequencer operations while maintaining proper
* Items per segment of main i.e. pva_hwseq_segment * abstraction from hardware-specific implementation details.
* - hwseq_start, hwseq_end
* - channel id
* - hwseq_header,
* - desc_count
* - num_frames
* - head_desc, tail_desc
* - is_split_padding
* - is_raster_scan
*/
/**
* A struct holding private data to HW Sequencer Blob being parsed
*/ */
struct pva_hwseq_priv { struct pva_hwseq_priv {
/** /**
* Number of descriptors in the HW Sequencer Blob * @brief Number of descriptors in the hardware sequencer blob
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t desc_count; uint32_t desc_count;
/** /**
* Number of tiles in the packet * @brief Total number of tiles in the packet
* This is the sum total of descriptor repetition factors *
* present in the HW Sequencer Blob * @details Sum total of descriptor repetition factors present in the
* hardware sequencer blob, representing the total tile processing load.
* Valid range: [1 .. UINT32_MAX]
*/ */
uint32_t tiles_per_packet; uint32_t tiles_per_packet;
/**
* @brief Maximum tile X coordinate
* Valid range: [INT32_MIN .. INT32_MAX]
*/
int32_t max_tx; int32_t max_tx;
/**
* @brief Maximum tile Y coordinate
* Valid range: [INT32_MIN .. INT32_MAX]
*/
int32_t max_ty; int32_t max_ty;
/** /**
* Struct that holds the entry info of HW Sequencer Blob * @brief Hardware sequencer blob entry information
*/ */
struct hw_seq_blob_entry entry; struct hw_seq_blob_entry entry;
/** /**
* Struct that holds HW Sequencer Blob to be read * @brief Hardware sequencer buffer for blob parsing
*/ */
struct pva_hwseq_buffer blob; struct pva_hwseq_buffer blob;
/** /**
* Boolean to indicate if split padding is present in the HW Sequener Blob * @brief Flag indicating presence of split padding
* Valid values: true (split padding present), false (no split padding)
*/ */
bool is_split_padding; bool is_split_padding;
/** /**
* Bool to indicate if HW Sequencer uses raster scan or Vertical mining * @brief Flag indicating scan mode type
* TRUE: Raster Scan *
* FALSE: Vertical Mining * @details Indicates hardware sequencer scan mode:
* - true: Raster scan mode
* - false: Vertical mining mode
*/ */
bool is_raster_scan; bool is_raster_scan;
/** /**
* @brief Indicates the generation of PVA HW. * @brief PVA hardware generation
* Allowed values: 0 (GEN 1), 1 (GEN 2), 2 (GEN 3) *
* @details Hardware generation identifier for platform-specific
* behavior adaptation
* Valid values: @ref pva_hw_gen enumeration values
*/ */
enum pva_hw_gen hw_gen; enum pva_hw_gen hw_gen;
/** /**
* @brief Pointer to the DMA configuration header. * @brief Pointer to DMA configuration header
*/ */
const struct pva_dma_config *dma_config; const struct pva_dma_config *dma_config;
/** /**
* Pointer to \ref pva_dma_hwseq_hdr_t which holds the HW Sequencer Header * @brief Pointer to hardware sequencer header
*/ */
const struct pva_dma_hwseq_hdr *hdr; const struct pva_dma_hwseq_hdr *hdr;
/** /**
* Pointer to \ref pva_dma_hwseq_colrow_hdr_t which holds the Header of the * @brief Pointer to column/row header in hardware sequencer
* Col/Row inside HW Sequencer
*/ */
const struct pva_dma_hwseq_colrow_hdr *colrow; const struct pva_dma_hwseq_colrow_hdr *colrow;
/** /**
* Pointer to the Head Descriptor of type \ref nvpva_dma_descriptor in the HW Sequencer * @brief Pointer to head descriptor in the hardware sequencer
*/ */
const struct pva_dma_descriptor *head_desc; const struct pva_dma_descriptor *head_desc;
/** /**
* Pointer to the Tail Descriptor of type \ref nvpva_dma_descriptor in the HW Sequencer * @brief Pointer to tail descriptor in the hardware sequencer
*/ */
const struct pva_dma_descriptor *tail_desc; const struct pva_dma_descriptor *tail_desc;
/** /**
* DMA Descriptor information obtained from HW Sequencer Blob of type * @brief Array of DMA descriptor entries from hardware sequencer blob
* \ref pva_dma_hwseq_desc_entry_t
*/ */
struct pva_dma_hwseq_desc_entry dma_descs[2]; struct pva_dma_hwseq_desc_entry dma_descs[2];
/** /**
* Access Sizes are calculated and stored here from HW Sequencer Blob * @brief Pointer to calculated access sizes from hardware sequencer blob
*/ */
struct pva_kmd_dma_access *access_sizes; struct pva_kmd_dma_access *access_sizes;
}; };
/**
* @brief Per-frame information for hardware sequencer processing
*
* @details This structure contains frame-specific information for hardware
* sequencer operations, including sequence tile counts and VMEM tile
* requirements per frame. It enables proper resource allocation and
* validation for frame-based processing operations.
*/
struct pva_hwseq_per_frame_info { struct pva_hwseq_per_frame_info {
/**
* @brief Number of tiles in the sequence for this frame
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t seq_tile_count; uint32_t seq_tile_count;
/**
* @brief Number of VMEM tiles required per frame
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t vmem_tiles_per_frame; uint32_t vmem_tiles_per_frame;
}; };
/**
* @brief Validate hardware sequencer configuration
*
* @details This function performs comprehensive validation of hardware sequencer
* configurations including:
* - Parsing and validating hardware sequencer blob structure
* - Checking descriptor references and repetition factors
* - Validating frame boundaries and addressing modes
* - Computing memory access patterns and requirements
* - Ensuring hardware constraints are satisfied
* - Building descriptor usage masks for resource tracking
* - Verifying grid parameters and tile arrangements
*
* The validation ensures that the hardware sequencer configuration is
* safe for execution and will not violate hardware constraints or
* memory protection boundaries. The function provides platform-agnostic
* validation that can be adapted to different hardware implementations.
*
* @param[in] dma_config Pointer to DMA configuration containing hardware sequencer
* Valid value: non-null
* @param[in] hw_consts Pointer to hardware constants for validation
* Valid value: non-null
* @param[out] access_sizes Array to store computed access size information
* Valid value: non-null, min size PVA_MAX_NUM_DMA_DESC
* @param[out] hw_dma_descs_mask Bitmask for tracking hardware descriptor usage
* Valid value: non-null
*
* @retval PVA_SUCCESS Hardware sequencer blob validated successfully
* @retval PVA_ERR_HWSEQ_INVALID Invalid hardware sequencer configuration
* @retval PVA_ERANGE Hardware sequencer configuration exceeds bounds or limits
* @retval PVA_INVAL Invalid descriptor reference in hardware sequencer
* @retval PVA_BAD_PARAMETER_ERROR Invalid grid parameters in hardware sequencer
* @retval PVA_INVALID_RESOURCE Invalid input parameters
*/
enum pva_error validate_hwseq(struct pva_dma_config const *dma_config, enum pva_error validate_hwseq(struct pva_dma_config const *dma_config,
struct pva_kmd_hw_constants const *hw_consts, struct pva_kmd_hw_constants const *hw_consts,
struct pva_kmd_dma_access *access_sizes, struct pva_kmd_dma_access *access_sizes,

View File

@@ -0,0 +1,70 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/**
* @file pva_kmd_limits.h
* @brief Platform-independent type limit definitions
*
* @details This header provides portable definitions for integer type limits
* that work across different platforms (Linux kernel, QNX, Native x86, Simulation).
*
* Linux kernel does not have <stdint.h> but provides its own limit macros.
* Other platforms (QNX, Native, SIM) use standard <stdint.h> definitions.
*
* This header abstracts these platform differences, allowing common code to use
* consistent macro names across all platforms.
*/
#ifndef PVA_KMD_LIMITS_H
#define PVA_KMD_LIMITS_H
#ifdef __KERNEL__
/* Linux kernel build - use kernel-provided limit macros */
#include <linux/kernel.h>
/*
* Linux kernel provides:
* U8_MAX, U16_MAX, U32_MAX, U64_MAX for unsigned types
* S8_MAX, S8_MIN, S16_MAX, S16_MIN, S32_MAX, S32_MIN, S64_MAX, S64_MIN for signed types
*/
#else
/* QNX/Native/SIM builds - use standard C definitions */
#include <stdint.h>
/* Map standard C names to kernel-style names for consistency */
#ifndef U8_MAX
#define U8_MAX UINT8_MAX
#endif
#ifndef U16_MAX
#define U16_MAX UINT16_MAX
#endif
#ifndef U32_MAX
#define U32_MAX UINT32_MAX
#endif
#ifndef U64_MAX
#define U64_MAX UINT64_MAX
#endif
#ifndef S8_MAX
#define S8_MAX INT8_MAX
#endif
#ifndef S8_MIN
#define S8_MIN INT8_MIN
#endif
#ifndef S16_MAX
#define S16_MAX INT16_MAX
#endif
#ifndef S16_MIN
#define S16_MIN INT16_MIN
#endif
#ifndef S32_MAX
#define S32_MAX INT32_MAX
#endif
#ifndef S32_MIN
#define S32_MIN INT32_MIN
#endif
#ifndef S64_MAX
#define S64_MAX INT64_MAX
#endif
#ifndef S64_MIN
#define S64_MIN INT64_MIN
#endif
#endif /* __KERNEL__ */
#endif /* PVA_KMD_LIMITS_H */

View File

@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_msg.h" #include "pva_kmd_msg.h"
#include "pva_api_types.h"
#include "pva_fw.h" #include "pva_fw.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_kmd_thread_sema.h" #include "pva_kmd_thread_sema.h"
@@ -11,8 +12,8 @@
static uint8_t get_msg_type(uint32_t hdr) static uint8_t get_msg_type(uint32_t hdr)
{ {
return PVA_EXTRACT(hdr, PVA_FW_MSG_TYPE_MSB, PVA_FW_MSG_TYPE_LSB, return (uint8_t)PVA_EXTRACT(hdr, PVA_FW_MSG_TYPE_MSB,
uint32_t); PVA_FW_MSG_TYPE_LSB, uint32_t);
} }
void pva_kmd_handle_hyp_msg(void *pva_dev, uint32_t const *data, uint8_t len) void pva_kmd_handle_hyp_msg(void *pva_dev, uint32_t const *data, uint8_t len)
@@ -31,32 +32,42 @@ void pva_kmd_handle_hyp_msg(void *pva_dev, uint32_t const *data, uint8_t len)
pack64(data[PVA_FW_MSG_R5_READY_TIME_HI_IDX], pack64(data[PVA_FW_MSG_R5_READY_TIME_HI_IDX],
data[PVA_FW_MSG_R5_READY_TIME_LO_IDX]); data[PVA_FW_MSG_R5_READY_TIME_LO_IDX]);
pva_kmd_log_err("Firmware boot completes"); pva_kmd_log_info("Firmware boot completes");
pva_kmd_log_err_u64("R5 start time (us)", pva_kmd_log_info_u64("R5 start time (us)",
pva_kmd_tsc_to_us(pva, r5_start_time)); pva_kmd_tsc_to_us(pva, r5_start_time));
pva_kmd_log_err_u64("R5 ready time (us)", pva_kmd_log_info_u64("R5 ready time (us)",
pva_kmd_tsc_to_us(pva, r5_ready_time)); pva_kmd_tsc_to_us(pva, r5_ready_time));
pva_kmd_sema_post(&pva->fw_boot_sema); pva_kmd_sema_post(&pva->fw_boot_sema);
} break; } break;
case PVA_FW_MSG_TYPE_ABORT: { case PVA_FW_MSG_TYPE_ABORT: {
char abort_msg[PVA_FW_MSG_ABORT_STR_MAX_LEN + 1]; char abort_msg[PVA_FW_MSG_ABORT_STR_MAX_LEN + 1];
pva_kmd_drain_fw_print(&pva->fw_print_buffer); pva_kmd_drain_fw_print(pva);
pva_kmd_log_err("Firmware aborted! The abort message is: "); pva_kmd_log_err("Firmware aborted! The abort message is: ");
abort_msg[0] = PVA_EXTRACT(data[0], 7, 0, uint32_t); /* CERT INT31-C: PVA_EXTRACT returns 8-bit value, safe to cast to char */
abort_msg[1] = PVA_EXTRACT(data[0], 15, 8, uint32_t); abort_msg[0] = (char)PVA_EXTRACT(data[0], 7, 0, uint32_t);
memcpy(abort_msg + 2, &data[1], size); abort_msg[1] = (char)PVA_EXTRACT(data[0], 15, 8, uint32_t);
(void)memcpy((void *)(abort_msg + 2), (const void *)&data[1],
(size_t)size);
abort_msg[PVA_FW_MSG_ABORT_STR_MAX_LEN] = '\0'; abort_msg[PVA_FW_MSG_ABORT_STR_MAX_LEN] = '\0';
pva_kmd_log_err(abort_msg); pva_kmd_log_err(abort_msg);
pva_kmd_abort_fw(pva, PVA_ERR_FW_ABORTED); pva_kmd_abort_fw(pva, PVA_ERR_FW_ABORTED);
} break; } break;
case PVA_FW_MSG_TYPE_FLUSH_PRINT: case PVA_FW_MSG_TYPE_FLUSH_PRINT:
pva_kmd_drain_fw_print(&pva->fw_print_buffer); pva_kmd_drain_fw_print(pva);
break;
case PVA_FW_MSG_TYPE_FAST_RESET_FAILURE:
pva_kmd_log_err("Fast reset failure");
pva_kmd_report_error_fsi(pva,
(uint32_t)PVA_ERR_FAST_RESET_FAILURE);
pva->recovery = true;
break; break;
default: default:
FAULT("Unknown message type from firmware"); FAULT("Unknown message type from firmware");
/* MISRA Rule 16.3 requires break; Rule 2.1: break is unreachable but required by MISRA 16.3 */
break;
} }
} }

View File

@@ -9,15 +9,51 @@
/** /**
* @brief Handle messages from FW to hypervisor. * @brief Handle messages from FW to hypervisor.
* *
* @details This function performs the following operations:
* - Receives message data from firmware intended for hypervisor processing
* - Validates the message format and length for correctness
* - Routes the message to appropriate hypervisor handling mechanisms
* - Processes mailbox-based communication from firmware
* - Handles future hypervisor support infrastructure
* - Ensures proper message acknowledgment back to firmware
*
* This is just a provision for future hypervisor support. For now, this just * This is just a provision for future hypervisor support. For now, this just
* handles all messages from mailboxes. * handles all messages from mailboxes. The function provides a foundation
* for hypervisor communication that can be extended when full hypervisor
* support is implemented in the system.
*
* @param[in] pva_dev Pointer to PVA device structure
* Valid value: non-null
* @param[in] data Pointer to message data array received from firmware
* Valid value: non-null
* @param[in] len Length of the message data in 32-bit words
* Valid range: [1 .. 255]
*/ */
void pva_kmd_handle_hyp_msg(void *pva_dev, uint32_t const *data, uint8_t len); void pva_kmd_handle_hyp_msg(void *pva_dev, uint32_t const *data, uint8_t len);
/** /**
* @brief Handle messages from FW to KMD. * @brief Handle messages from FW to KMD.
* *
* These messages come from CCQ0 statues registers. * @details This function performs the following operations:
* - Receives message data from firmware via CCQ0 status registers
* - Parses the message header to determine message type and routing
* - Dispatches messages to appropriate KMD subsystem handlers
* - Processes firmware status updates, error notifications, and responses
* - Handles resource management messages and completion notifications
* - Updates internal KMD state based on firmware messages
* - Manages communication flow control with firmware
*
* These messages come from CCQ0 status registers and represent the primary
* communication channel between firmware and KMD for system-level operations.
* The function ensures proper message processing and maintains synchronization
* between firmware and KMD state.
*
* @param[in] pva_dev Pointer to PVA device structure
* Valid value: non-null
* @param[in] data Pointer to message data array received from firmware
* Valid value: non-null
* @param[in] len Length of the message data in 32-bit words
* Valid range: [1 .. 255]
*/ */
void pva_kmd_handle_msg(void *pva_dev, uint32_t const *data, uint8_t len); void pva_kmd_handle_msg(void *pva_dev, uint32_t const *data, uint8_t len);
#endif // PVA_KMD_MSG_H #endif // PVA_KMD_MSG_H

View File

@@ -9,19 +9,113 @@
#if defined(__KERNEL__) /* For Linux */ #if defined(__KERNEL__) /* For Linux */
#include <linux/mutex.h> #include <linux/mutex.h>
/**
* @brief Mutex type alias for Linux kernel space
*
* @details Platform-specific mutex implementation that maps to the Linux
* kernel mutex structure. This provides cross-platform abstraction for
* mutex operations in the PVA KMD, allowing the same code to work across
* different operating system environments.
*/
typedef struct mutex pva_kmd_mutex_t; typedef struct mutex pva_kmd_mutex_t;
#else /* For user space code, including QNX KMD */ #else /* For user space code, including QNX KMD */
#include <pthread.h> #include <pthread.h>
/* Mutex */ /**
* @brief Mutex type alias for user space (QNX and other platforms)
*
* @details Platform-specific mutex implementation that maps to POSIX
* pthread mutex for user space environments including QNX KMD. This
* provides cross-platform abstraction for mutex operations, enabling
* consistent synchronization primitives across different platforms.
*/
typedef pthread_mutex_t pva_kmd_mutex_t; typedef pthread_mutex_t pva_kmd_mutex_t;
#endif #endif
/**
* @brief Initialize a PVA KMD mutex
*
* @details This function performs the following operations:
* - Initializes the platform-specific mutex structure
* - Sets up appropriate mutex attributes for the target platform
* - Configures the mutex for proper operation in kernel or user space
* - Ensures the mutex is ready for lock/unlock operations
* - Handles platform-specific initialization requirements
*
* The mutex must be initialized before it can be used for synchronization.
* After successful initialization, the mutex can be used with
* @ref pva_kmd_mutex_lock() and @ref pva_kmd_mutex_unlock(). The mutex
* should be deinitialized using @ref pva_kmd_mutex_deinit() when no
* longer needed.
*
* @param[in, out] m Pointer to @ref pva_kmd_mutex_t structure to initialize
* Valid value: non-null
*
* @retval PVA_SUCCESS Mutex initialized successfully
* @retval PVA_INTERNAL Platform-specific mutex initialization failed
*/
enum pva_error pva_kmd_mutex_init(pva_kmd_mutex_t *m); enum pva_error pva_kmd_mutex_init(pva_kmd_mutex_t *m);
/**
* @brief Acquire a lock on the PVA KMD mutex
*
* @details This function performs the following operations:
* - Attempts to acquire an exclusive lock on the specified mutex
* - Blocks the calling thread if the mutex is already locked by another thread
* - Provides mutual exclusion for critical sections of code
* - Uses platform-appropriate locking mechanisms (kernel or user space)
* - Ensures atomic access to shared resources protected by the mutex
*
* The calling thread will block until the mutex becomes available. Once
* acquired, the thread has exclusive access to resources protected by this
* mutex until @ref pva_kmd_mutex_unlock() is called. The mutex must be
* initialized using @ref pva_kmd_mutex_init() before calling this function.
*
* @param[in, out] m Pointer to @ref pva_kmd_mutex_t structure to lock
* Valid value: non-null, must be initialized
*/
void pva_kmd_mutex_lock(pva_kmd_mutex_t *m); void pva_kmd_mutex_lock(pva_kmd_mutex_t *m);
/**
* @brief Release a lock on the PVA KMD mutex
*
* @details This function performs the following operations:
* - Releases the exclusive lock on the specified mutex
* - Allows other waiting threads to acquire the mutex
* - Signals completion of the critical section protected by the mutex
* - Uses platform-appropriate unlocking mechanisms
* - Maintains proper synchronization state for subsequent operations
*
* This function must only be called by the thread that currently holds
* the mutex lock. After unlocking, other threads waiting on the mutex
* may acquire the lock. The mutex must have been previously locked using
* @ref pva_kmd_mutex_lock() before calling this function.
*
* @param[in, out] m Pointer to @ref pva_kmd_mutex_t structure to unlock
* Valid value: non-null, must be currently locked by calling thread
*/
void pva_kmd_mutex_unlock(pva_kmd_mutex_t *m); void pva_kmd_mutex_unlock(pva_kmd_mutex_t *m);
/**
* @brief Deinitialize a PVA KMD mutex and free resources
*
* @details This function performs the following operations:
* - Deinitializes the platform-specific mutex structure
* - Frees any resources allocated during mutex initialization
* - Ensures proper cleanup of platform-specific mutex state
* - Marks the mutex as invalid for future use
* - Handles platform-specific deinitialization requirements
*
* The mutex must not be locked when this function is called, and no
* threads should be waiting on the mutex. After deinitialization, the
* mutex cannot be used for synchronization until it is reinitialized
* using @ref pva_kmd_mutex_init().
*
* @param[in, out] m Pointer to @ref pva_kmd_mutex_t structure to deinitialize
* Valid value: non-null, must be initialized and unlocked
*/
void pva_kmd_mutex_deinit(pva_kmd_mutex_t *m); void pva_kmd_mutex_deinit(pva_kmd_mutex_t *m);
#endif // PVA_KMD_MUTEX_H #endif // PVA_KMD_MUTEX_H

View File

File diff suppressed because it is too large Load Diff

View File

@@ -8,32 +8,65 @@
#include "pva_fw.h" #include "pva_fw.h"
#include "pva_kmd.h" #include "pva_kmd.h"
/** @brief Handler for PVA KMD operations. /**
* * @brief Handler for PVA KMD operations.
* This function implements the only runtime interface with UMD. Shim layers *
* receive the input data from UMD and call this function to execute the * @details This function performs the following operations:
* operations. Then, shim layers send the response back to UMD. * - Receives operation requests from UMD through platform-specific shim layers
* * - Validates the operation buffer format and size for correctness
* @param ctx The KMD context. * - Parses the operations buffer to extract individual operation commands
* @param ops Pointer to the input buffer containing the operations to be * - Executes the requested operations using the provided KMD context
* executed. The common layer assumes that this buffer is private to * - Manages submission mode (synchronous or asynchronous) based on parameters
* KMD and will dereference it directly without making a copy. * - Handles postfence configuration for operation completion signaling
* Specifically on Linux, this parameter should point to a private * - Generates appropriate response data for successful operations
* kernel space buffer instead of the user space buffer. * - Handles error conditions and generates error responses
* @param ops_size Size of the input buffer. * - Ensures proper resource cleanup in case of operation failures
* @param response Pointer to the buffer where the response will be written. * - Maintains operation isolation and security within the context
* @param response_buffer_size Size of the response buffer. *
* @param out_response_size Pointer to a variable where the actual size of the * This function implements the only runtime interface with UMD. Shim layers
* response will be written. * receive the input data from UMD and call this function to execute the
* * operations. Then, shim layers send the response back to UMD. The function
* @return pva_error indicating the success or failure of the operation. * assumes that the operations buffer is private to KMD and will dereference
* * it directly without making a copy. On Linux platforms, the operations
* @Note that the input buffer and output buffer should never alias. * buffer should point to a private kernel space buffer rather than user
*/ * space to ensure memory safety and security.
enum pva_error *
pva_kmd_ops_handler(struct pva_kmd_context *ctx, enum pva_ops_submit_mode mode, * @param[in] ctx Pointer to @ref pva_kmd_context structure
struct pva_fw_postfence *postfence, void const *ops_buffer, * Valid value: non-null, must be initialized
uint32_t ops_size, void *response, * @param[in] mode Submission mode for operation execution
uint32_t response_buffer_size, uint32_t *out_response_size); * Valid values: @ref pva_ops_submit_mode enumeration values
* @param[in, out] postfence Pointer to @ref pva_fw_postfence structure for
* completion signaling
* Valid value: can be null if no postfence required
* @param[in] ops_buffer Pointer to operations buffer containing commands to execute
* Valid value: non-null, must point to KMD-private buffer
* @param[in] ops_size Size of the operations buffer in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[out] response Pointer to buffer where response will be written
* Valid value: non-null, must not alias ops_buffer
* @param[in] response_buffer_size Size of the response buffer in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[out] out_response_size Pointer to variable for actual response size
* Valid value: non-null
* @param[in] priv Flag indicating privileged operation mode
* Valid values: true for privileged operations, false otherwise
*
* @retval PVA_SUCCESS Operations executed successfully
* @retval PVA_INVAL Invalid parameter values or buffer pointers
* @retval PVA_ENOSPC Response buffer too small for result data
* @retval PVA_NOT_IMPL Invalid or unsupported operation in buffer
* @retval PVA_INTERNAL Context not properly initialized
* @retval PVA_TIMEDOUT Communication with firmware failed
* @retval PVA_AGAIN Required resources are not available
*
* @note The input buffer and output buffer should never alias.
*/
enum pva_error pva_kmd_ops_handler(struct pva_kmd_context *ctx,
enum pva_ops_submit_mode mode,
struct pva_fw_postfence *postfence,
void const *ops_buffer, uint32_t ops_size,
void *response,
uint32_t response_buffer_size,
uint32_t *out_response_size, bool priv);
#endif // PVA_KMD_OP_HANDLER_H #endif // PVA_KMD_OP_HANDLER_H

View File

@@ -0,0 +1,875 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_pfsd.h"
#include "pva_kmd_op_handler.h"
#include "pva_kmd_device_memory.h"
#include "pva_kmd_device.h"
#include "pva_kmd_utils.h"
#include "pva_kmd_context.h"
#include "pva_kmd_cmdbuf.h"
#include "pva_kmd_constants.h"
#include "pva_utils.h"
#include "pva_kmd.h"
#include "pva_api_types.h"
#include "pva_api_ops.h"
#include "pva_kmd_submitter.h"
#include "pva_kmd_resource_table.h"
// Helper structure to pass multiple source buffers
struct pva_buffer_source {
const void *data_ptr;
uint64_t size;
};
// Helper function to register a buffer from multiple sources
static enum pva_error pva_kmd_pfsd_register_buffer(
struct pva_kmd_context *ctx, const struct pva_buffer_source *sources,
uint32_t num_sources, enum pva_memory_segment segment,
uint32_t *resource_id_out)
{
enum pva_error err = PVA_SUCCESS;
struct pva_kmd_device_memory *mem = NULL;
struct pva_cmd_update_resource_table update_cmd = { 0 };
struct pva_resource_entry entry = { 0 };
uint32_t resource_id = 0;
uint8_t smmu_ctx_id;
struct pva_kmd_submitter *dev_submitter;
uint64_t total_size = 0;
uint64_t offset = 0;
uint32_t i;
for (i = 0; i < num_sources; i++) {
total_size = safe_addu64(total_size, sources[i].size);
}
if (segment == PVA_MEMORY_SEGMENT_R5) {
smmu_ctx_id = PVA_R5_SMMU_CONTEXT_ID;
} else {
smmu_ctx_id = ctx->smmu_ctx_id;
}
mem = pva_kmd_device_memory_alloc_map(total_size, ctx->pva,
PVA_ACCESS_RO, smmu_ctx_id);
if (mem == NULL) {
pva_kmd_log_err(
"Failed to allocate and map device memory for buffer");
err = PVA_NOMEM;
goto out;
}
for (i = 0; i < num_sources; i++) {
(void)memcpy((void *)((uint8_t *)mem->va + offset),
(const void *)sources[i].data_ptr,
sources[i].size);
offset = safe_addu64(offset, sources[i].size);
}
err = pva_kmd_add_dram_buffer_resource(&ctx->ctx_resource_table, mem,
&resource_id, true);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to add buffer to resource table");
goto free_memory;
}
err = pva_kmd_make_resource_entry(&ctx->ctx_resource_table, resource_id,
&entry);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to make resource entry");
goto free_dram_buffer_resource;
}
pva_kmd_set_cmd_update_resource_table(
&update_cmd, ctx->resource_table_id, resource_id, &entry, NULL);
dev_submitter = &ctx->pva->submitter;
err = pva_kmd_submit_cmd_sync(dev_submitter, &update_cmd,
(uint32_t)sizeof(update_cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("PFSD buffer memory registration to FW failed");
goto free_dram_buffer_resource;
}
*resource_id_out = resource_id;
return PVA_SUCCESS;
free_dram_buffer_resource:
pva_kmd_drop_resource(&ctx->ctx_resource_table, resource_id);
free_memory:
pva_kmd_device_memory_free(mem);
out:
return err;
}
enum pva_error pva_kmd_pfsd_register_input_buffers(struct pva_kmd_context *ctx)
{
enum pva_error err = PVA_SUCCESS;
struct pva_buffer_source sources[4];
// Register in1 buffer
sources[0].data_ptr = in1;
sources[0].size = sizeof(in1);
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 1, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.in1_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register in2 buffer
sources[0].data_ptr = in2;
sources[0].size = sizeof(in2);
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 1, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.in2_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register in3 buffer
sources[0].data_ptr = in3;
sources[0].size = sizeof(in3);
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 1, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.in3_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register hist_a buffer (hist_short_a followed by hist_int_a)
sources[0].data_ptr = hist_short_a;
sources[0].size = sizeof(hist_short_a);
sources[1].data_ptr = hist_int_a;
sources[1].size = sizeof(hist_int_a);
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 2, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.hist_a_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register hist_b buffer (hist_short_b followed by hist_int_b)
sources[0].data_ptr = hist_short_b;
sources[0].size = sizeof(hist_short_b);
sources[1].data_ptr = hist_int_b;
sources[1].size = sizeof(hist_int_b);
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 2, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.hist_b_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register hist_c buffer (hist_short_c followed by hist_int_c)
sources[0].data_ptr = hist_short_c;
sources[0].size = sizeof(hist_short_c);
sources[1].data_ptr = hist_int_c;
sources[1].size = sizeof(hist_int_c);
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 2, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.hist_c_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register dlut_tbl_buf (all 4 DLUT tables combined)
sources[0].data_ptr = pva_pfsd_data_dlut_tbl0;
sources[0].size = PVA_PFSD_DLUT_TBL0_SIZE;
sources[1].data_ptr = pva_pfsd_data_dlut_tbl1;
sources[1].size = PVA_PFSD_DLUT_TBL1_SIZE;
sources[2].data_ptr = pva_pfsd_data_dlut_tbl2;
sources[2].size = PVA_PFSD_DLUT_TBL2_SIZE;
sources[3].data_ptr = pva_pfsd_data_dlut_tbl3;
sources[3].size = PVA_PFSD_DLUT_TBL3_SIZE;
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 4, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.dlut_tbl_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
// Register dlut_indices_buf (all 4 DLUT indices combined)
sources[0].data_ptr = pva_pfsd_data_dlut_indices0;
sources[0].size = PVA_PFSD_DLUT_INDICES0_SIZE;
sources[1].data_ptr = pva_pfsd_data_dlut_indices1;
sources[1].size = PVA_PFSD_DLUT_INDICES1_SIZE;
sources[2].data_ptr = pva_pfsd_data_dlut_indices2;
sources[2].size = PVA_PFSD_DLUT_INDICES2_SIZE;
sources[3].data_ptr = pva_pfsd_data_dlut_indices3;
sources[3].size = PVA_PFSD_DLUT_INDICES3_SIZE;
err = pva_kmd_pfsd_register_buffer(
ctx, sources, 4, PVA_MEMORY_SEGMENT_DMA,
&ctx->pfsd_resource_ids.dlut_indices_resource_id);
if (err != PVA_SUCCESS) {
return err;
}
return PVA_SUCCESS;
}
enum pva_error pva_kmd_pfsd_register_elf(struct pva_kmd_context *ctx)
{
enum pva_error err = PVA_SUCCESS;
struct pva_ops_executable_register exec_register = { 0 };
struct pva_ops_response_executable_register response = { 0 };
uint32_t response_size = 0;
uint32_t total_size = 0;
uint8_t *vpu_exec_buffer = NULL;
const uint8_t *vpu_elf_data = NULL;
uint32_t vpu_elf_size = 0;
uint8_t *ppe_exec_buffer = NULL;
const uint8_t *ppe_elf_data = NULL;
uint32_t ppe_elf_size = 0;
vpu_elf_data = ctx->pva->pfsd_info.vpu_elf_data;
vpu_elf_size = ctx->pva->pfsd_info.vpu_elf_size;
ppe_elf_data = ctx->pva->pfsd_info.ppe_elf_data;
ppe_elf_size = ctx->pva->pfsd_info.ppe_elf_size;
total_size = safe_addu32(
(uint32_t)sizeof(struct pva_ops_executable_register),
vpu_elf_size);
// Align total size to 8 bytes as required by PVA operation handler
total_size = safe_pow2_roundup_u32(total_size, 8U);
vpu_exec_buffer = pva_kmd_zalloc(total_size);
if (vpu_exec_buffer == NULL) {
pva_kmd_log_err(
"Failed to allocate buffer for PFSD ELF registration");
err = PVA_NOMEM;
goto out;
}
exec_register.header.opcode = PVA_OPS_OPCODE_EXECUTABLE_REGISTER;
exec_register.header.size = total_size;
exec_register.exec_size = vpu_elf_size;
(void)memcpy((void *)vpu_exec_buffer, (const void *)&exec_register,
sizeof(exec_register));
(void)memcpy((void *)(vpu_exec_buffer + sizeof(exec_register)),
(const void *)vpu_elf_data, vpu_elf_size);
err = pva_kmd_ops_handler(ctx, PVA_OPS_SUBMIT_MODE_SYNC, NULL,
vpu_exec_buffer, total_size, &response,
(uint32_t)sizeof(response), &response_size,
true);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("PFSD ELF executable registration failed");
goto free_vpu_buffer;
}
if (response.error != PVA_SUCCESS) {
pva_kmd_log_err("PFSD ELF executable registration failed");
err = response.error;
goto free_vpu_buffer;
}
ctx->pfsd_resource_ids.vpu_elf_resource_id = response.resource_id;
if (ppe_elf_data != NULL) {
total_size = safe_addu32(
(uint32_t)sizeof(struct pva_ops_executable_register),
ppe_elf_size);
// Align total size to 8 bytes as required by PVA operation handler
total_size = safe_pow2_roundup_u32(total_size, 8U);
ppe_exec_buffer = pva_kmd_zalloc(total_size);
if (ppe_exec_buffer == NULL) {
pva_kmd_log_err(
"Failed to allocate buffer for PFSD PPE ELF registration");
err = PVA_NOMEM;
goto free_ppe_buffer;
}
exec_register.header.opcode =
PVA_OPS_OPCODE_EXECUTABLE_REGISTER;
exec_register.header.size = total_size;
exec_register.exec_size = ppe_elf_size;
(void)memcpy((void *)ppe_exec_buffer,
(const void *)&exec_register,
sizeof(exec_register));
(void)memcpy((void *)(ppe_exec_buffer + sizeof(exec_register)),
(const void *)ppe_elf_data, ppe_elf_size);
err = pva_kmd_ops_handler(ctx, PVA_OPS_SUBMIT_MODE_SYNC, NULL,
ppe_exec_buffer, total_size,
&response, (uint32_t)sizeof(response),
&response_size, true);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"PFSD PPE ELF executable registration failed");
goto free_ppe_buffer;
}
if (response.error != PVA_SUCCESS) {
pva_kmd_log_err(
"PFSD PPE ELF executable registration failed");
err = response.error;
goto free_ppe_buffer;
}
ctx->pfsd_resource_ids.ppe_elf_resource_id =
response.resource_id;
}
free_ppe_buffer:
pva_kmd_free(ppe_exec_buffer);
free_vpu_buffer:
pva_kmd_free(vpu_exec_buffer);
out:
return err;
}
enum pva_error pva_kmd_pfsd_register_dma_config(struct pva_kmd_context *ctx)
{
enum pva_error err = PVA_SUCCESS;
struct pva_ops_response_register response = { 0 };
uint32_t response_size = 0;
uint32_t total_size = 0;
uint8_t *dma_buffer = NULL;
uint32_t offset = 0;
uint32_t i;
struct pva_dma_config pfsd_dma_cfg = { 0 };
struct pva_dma_static_binding static_bindings[8];
struct pva_ops_dma_config_register dma_register = { 0 };
pfsd_dma_cfg = ctx->pva->pfsd_info.pfsd_dma_cfg;
total_size = (uint32_t)sizeof(struct pva_ops_dma_config_register);
total_size = safe_pow2_roundup_u32(total_size, 8U);
total_size = safe_addu32(
total_size,
safe_mulu32((uint32_t)pfsd_dma_cfg.header.num_channels,
(uint32_t)sizeof(struct pva_dma_channel)));
total_size = safe_pow2_roundup_u32(total_size, 8U);
total_size = safe_addu32(
total_size,
safe_mulu32((uint32_t)pfsd_dma_cfg.header.num_descriptors,
(uint32_t)sizeof(struct pva_dma_descriptor)));
total_size = safe_pow2_roundup_u32(total_size, 8U);
total_size = safe_addu32(
total_size,
safe_mulu32((uint32_t)pfsd_dma_cfg.header.num_hwseq_words,
(uint32_t)sizeof(uint32_t)));
total_size = safe_pow2_roundup_u32(total_size, 8U);
total_size = safe_addu32(
total_size,
safe_mulu32((uint32_t)pfsd_dma_cfg.header.num_static_slots,
(uint32_t)sizeof(struct pva_dma_static_binding)));
total_size = safe_pow2_roundup_u32(total_size, 8U);
dma_buffer = pva_kmd_zalloc(total_size);
if (dma_buffer == NULL) {
pva_kmd_log_err(
"Failed to allocate buffer for PFSD DMA config registration");
err = PVA_NOMEM;
goto out;
}
pfsd_dma_cfg.header.vpu_exec_resource_id =
ctx->pfsd_resource_ids.vpu_elf_resource_id;
// Build dma_register structure locally and copy to buffer
dma_register.header.opcode = PVA_OPS_OPCODE_DMA_CONFIG_REGISTER;
dma_register.header.size = total_size;
dma_register.dma_config_header = pfsd_dma_cfg.header;
offset = (uint32_t)sizeof(struct pva_ops_dma_config_register);
offset = safe_pow2_roundup_u32(offset, 8U);
dma_register.channels_offset = offset;
(void)memcpy((void *)(dma_buffer + offset),
(const void *)pfsd_dma_cfg.channels,
pfsd_dma_cfg.header.num_channels *
sizeof(struct pva_dma_channel));
offset = safe_addu32(
offset, safe_mulu32(pfsd_dma_cfg.header.num_channels,
(uint32_t)sizeof(struct pva_dma_channel)));
offset = safe_pow2_roundup_u32(offset, 8U);
dma_register.descriptors_offset = offset;
(void)memcpy((void *)(dma_buffer + offset),
(const void *)pfsd_dma_cfg.descriptors,
pfsd_dma_cfg.header.num_descriptors *
sizeof(struct pva_dma_descriptor));
offset = safe_addu32(
offset,
safe_mulu32(pfsd_dma_cfg.header.num_descriptors,
(uint32_t)sizeof(struct pva_dma_descriptor)));
offset = safe_pow2_roundup_u32(offset, 8U);
dma_register.hwseq_words_offset = offset;
if (pfsd_dma_cfg.header.num_hwseq_words > 0U &&
pfsd_dma_cfg.hwseq_words != NULL) {
(void)memcpy((void *)(dma_buffer + offset),
(const void *)pfsd_dma_cfg.hwseq_words,
pfsd_dma_cfg.header.num_hwseq_words *
sizeof(uint32_t));
}
offset = safe_addu32(offset,
safe_mulu32(pfsd_dma_cfg.header.num_hwseq_words,
(uint32_t)sizeof(uint32_t)));
for (i = 0U; i < pfsd_dma_cfg.header.num_static_slots && i < 8U; i++) {
(void)memcpy(&static_bindings[i],
&pfsd_dma_cfg.static_bindings[i],
sizeof(struct pva_dma_static_binding));
}
static_bindings[0].dram.resource_id =
ctx->pfsd_resource_ids.in1_resource_id;
static_bindings[1].dram.resource_id =
ctx->pfsd_resource_ids.in2_resource_id;
static_bindings[2].dram.resource_id =
ctx->pfsd_resource_ids.in3_resource_id;
static_bindings[3].dram.resource_id =
ctx->pfsd_resource_ids.hist_a_resource_id;
static_bindings[4].dram.resource_id =
ctx->pfsd_resource_ids.hist_b_resource_id;
static_bindings[5].dram.resource_id =
ctx->pfsd_resource_ids.hist_c_resource_id;
static_bindings[6].dram.resource_id =
ctx->pfsd_resource_ids.dlut_tbl_resource_id;
static_bindings[7].dram.resource_id =
ctx->pfsd_resource_ids.dlut_indices_resource_id;
offset = safe_pow2_roundup_u32(offset, 8U);
dma_register.static_bindings_offset = offset;
(void)memcpy((void *)(dma_buffer + offset),
(const void *)static_bindings,
pfsd_dma_cfg.header.num_static_slots *
sizeof(struct pva_dma_static_binding));
(void)memcpy((void *)dma_buffer, (const void *)&dma_register,
sizeof(dma_register));
/*
* MISRA C-2023 Directive 4.14: Validate values from external sources
* Note: dma_buffer is constructed internally from pfsd_dma_cfg which has
* been validated during PFSD initialization. All resource IDs are from
* internal driver state (ctx->pfsd_resource_ids), not direct user input.
* The buffer size and structure are validated by pva_kmd_ops_handler.
*/
err = pva_kmd_ops_handler(ctx, PVA_OPS_SUBMIT_MODE_SYNC, NULL,
dma_buffer, total_size, &response,
(uint32_t)sizeof(response), &response_size,
true);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("PFSD DMA config registration failed");
goto free_buffer;
}
if (response.error != PVA_SUCCESS) {
pva_kmd_log_err("PFSD DMA config registration failed");
err = response.error;
goto free_buffer;
}
ctx->pfsd_resource_ids.dma_config_resource_id = response.resource_id;
free_buffer:
pva_kmd_free(dma_buffer);
out:
return err;
}
enum pva_error pva_kmd_pfsd_t23x_register_cmdbuf(struct pva_kmd_context *ctx)
{
enum pva_error err = PVA_SUCCESS;
uint8_t *cmd_buffer = NULL;
uint32_t cmd_buffer_size = 0;
uint32_t offset = 0;
struct pva_buffer_source cmd_source;
struct pva_cmd_acquire_engine acquire_cmd = { 0 };
struct pva_cmd_set_vpu_executable set_vpu_exec_cmd = { 0 };
struct pva_cmd_prefetch_vpu_code prefetch_cmd = { 0 };
struct pva_cmd_fetch_dma_configuration fetch_dma_cmd = { 0 };
struct pva_cmd_init_vpu_executable init_vpu_cmd = { 0 };
struct pva_cmd_set_vpu_instance_parameter set_vpu_param_cmd = { 0 };
struct pva_cmd_setup_misr setup_misr_cmd = { 0 };
struct pva_cmd_setup_dma setup_dma_cmd = { 0 };
struct pva_cmd_run_dma run_dma_cmd = { 0 };
struct pva_cmd_run_vpu run_vpu_cmd = { 0 };
struct pva_cmd_release_engine release_cmd = { 0 };
// Calculate command buffer size
cmd_buffer_size =
(uint32_t)(sizeof(struct pva_cmd_acquire_engine) +
sizeof(struct pva_cmd_set_vpu_executable) +
sizeof(struct pva_cmd_prefetch_vpu_code) +
sizeof(struct pva_cmd_fetch_dma_configuration) +
sizeof(struct pva_cmd_init_vpu_executable) +
sizeof(struct pva_cmd_set_vpu_instance_parameter) +
sizeof(struct pva_cmd_setup_misr) +
sizeof(struct pva_cmd_setup_dma) +
sizeof(struct pva_cmd_run_dma) +
sizeof(struct pva_cmd_run_vpu) +
sizeof(struct pva_cmd_release_engine));
// Allocate command buffer
cmd_buffer = pva_kmd_zalloc(cmd_buffer_size);
if (cmd_buffer == NULL) {
pva_kmd_log_err("Failed to allocate command buffer");
err = PVA_NOMEM;
goto out;
}
// Build command sequence
// 1. pva_cmd_acquire_engine
acquire_cmd.header.opcode = PVA_CMD_OPCODE_ACQUIRE_ENGINE;
acquire_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_acquire_engine) /
sizeof(uint32_t));
acquire_cmd.engine_count = 1;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&acquire_cmd,
sizeof(acquire_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_acquire_engine);
// 2. pva_cmd_set_vpu_executable
set_vpu_exec_cmd.header.opcode = PVA_CMD_OPCODE_SET_VPU_EXECUTABLE;
set_vpu_exec_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_set_vpu_executable) /
sizeof(uint32_t));
set_vpu_exec_cmd.vpu_exec_resource_id =
ctx->pfsd_resource_ids.vpu_elf_resource_id;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&set_vpu_exec_cmd, sizeof(set_vpu_exec_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_set_vpu_executable);
// 3. pva_cmd_prefetch_vpu_code
prefetch_cmd.header.opcode = PVA_CMD_OPCODE_PREFETCH_VPU_CODE;
prefetch_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_prefetch_vpu_code) /
sizeof(uint32_t));
prefetch_cmd.entry_point_index = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&prefetch_cmd,
sizeof(prefetch_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_prefetch_vpu_code);
// 4. pva_cmd_fetch_dma_configuration
fetch_dma_cmd.header.opcode = PVA_CMD_OPCODE_FETCH_DMA_CONFIGURATION;
fetch_dma_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_fetch_dma_configuration) /
sizeof(uint32_t));
fetch_dma_cmd.dma_set_id = 0;
fetch_dma_cmd.resource_id =
ctx->pfsd_resource_ids.dma_config_resource_id;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&fetch_dma_cmd, sizeof(fetch_dma_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_fetch_dma_configuration);
// 5. pva_cmd_init_vpu_executable
init_vpu_cmd.header.opcode = PVA_CMD_OPCODE_INIT_VPU_EXECUTABLE;
init_vpu_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_init_vpu_executable) /
sizeof(uint32_t));
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&init_vpu_cmd,
sizeof(init_vpu_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_init_vpu_executable);
// 6. pva_cmd_set_vpu_instance_parameter
set_vpu_param_cmd.header.opcode =
PVA_CMD_OPCODE_SET_VPU_INSTANCE_PARAMETER;
set_vpu_param_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_set_vpu_instance_parameter) /
sizeof(uint32_t));
set_vpu_param_cmd.symbol_id = 0x40U;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&set_vpu_param_cmd,
sizeof(set_vpu_param_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_set_vpu_instance_parameter);
// 7. pva_cmd_setup_misr
setup_misr_cmd.header.opcode = PVA_CMD_OPCODE_SETUP_MISR;
setup_misr_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_setup_misr) / sizeof(uint32_t));
setup_misr_cmd.misr_params.slot_mask_low0 = 0xFFFFFFFFU;
setup_misr_cmd.misr_params.slot_mask_low1 = 0x000007FFU;
setup_misr_cmd.misr_params.slot_mask_high = 0;
setup_misr_cmd.misr_params.misr_config.seed_crc0 = MISR_SEED_0_T23X;
setup_misr_cmd.misr_params.misr_config.seed_crc1 = MISR_SEED_1_T23X;
setup_misr_cmd.misr_params.misr_config.ref_addr = MISR_REF_0_T23X;
setup_misr_cmd.misr_params.misr_config.ref_data_1 = MISR_REF_1_T23X;
setup_misr_cmd.misr_params.misr_config.ref_data_2 = MISR_REF_2_T23X;
setup_misr_cmd.misr_params.misr_config.misr_timeout = MISR_TIMEOUT_T23X;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&setup_misr_cmd, sizeof(setup_misr_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_setup_misr);
// 8. pva_cmd_setup_dma
setup_dma_cmd.header.opcode = PVA_CMD_OPCODE_SETUP_DMA;
setup_dma_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_setup_dma) / sizeof(uint32_t));
setup_dma_cmd.dma_set_id = 0;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&setup_dma_cmd, sizeof(setup_dma_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_setup_dma);
// 9. pva_cmd_run_dma
run_dma_cmd.header.opcode = PVA_CMD_OPCODE_RUN_DMA;
run_dma_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_run_dma) / sizeof(uint32_t));
run_dma_cmd.dma_set_id = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&run_dma_cmd,
sizeof(run_dma_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_run_dma);
// 10. pva_cmd_run_vpu
run_vpu_cmd.header.opcode = PVA_CMD_OPCODE_RUN_VPU;
run_vpu_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_run_vpu) / sizeof(uint32_t));
run_vpu_cmd.entry_point_index = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&run_vpu_cmd,
sizeof(run_vpu_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_run_vpu);
// 11. pva_cmd_release_engine
release_cmd.header.opcode = PVA_CMD_OPCODE_RELEASE_ENGINE;
release_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_release_engine) /
sizeof(uint32_t));
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&release_cmd,
sizeof(release_cmd));
// Register the command buffer with R5 segment so firmware can access it
cmd_source.data_ptr = cmd_buffer;
cmd_source.size = cmd_buffer_size;
err = pva_kmd_pfsd_register_buffer(
ctx, &cmd_source, 1, PVA_MEMORY_SEGMENT_R5,
&ctx->pfsd_resource_ids.cmd_buffer_resource_id);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to register PFSD command buffer");
goto free_buffer;
}
// Store the command buffer size in the global structure
ctx->pfsd_resource_ids.cmd_buffer_size = cmd_buffer_size;
free_buffer:
pva_kmd_free(cmd_buffer);
out:
return err;
}
enum pva_error pva_kmd_pfsd_t26x_register_cmdbuf(struct pva_kmd_context *ctx)
{
enum pva_error err = PVA_SUCCESS;
uint8_t *cmd_buffer = NULL;
uint32_t cmd_buffer_size = 0;
uint32_t offset = 0;
struct pva_buffer_source cmd_source;
struct pva_cmd_acquire_engine acquire_cmd = { 0 };
struct pva_cmd_set_vpu_executable set_vpu_exec_cmd = { 0 };
struct pva_cmd_set_ppe_executable set_ppe_exec_cmd = { 0 };
struct pva_cmd_prefetch_vpu_code prefetch_cmd = { 0 };
struct pva_cmd_fetch_dma_configuration fetch_dma_cmd = { 0 };
struct pva_cmd_init_vpu_executable init_vpu_cmd = { 0 };
struct pva_cmd_init_ppe_executable init_ppe_cmd = { 0 };
struct pva_cmd_set_vpu_instance_parameter set_vpu_param_cmd = { 0 };
struct pva_cmd_setup_misr setup_misr_cmd = { 0 };
struct pva_cmd_setup_dma setup_dma_cmd = { 0 };
struct pva_cmd_run_dma run_dma_cmd = { 0 };
struct pva_cmd_run_vpu run_vpu_cmd = { 0 };
struct pva_cmd_run_ppe run_ppe_cmd = { 0 };
struct pva_cmd_release_engine release_cmd = { 0 };
// Calculate command buffer size
cmd_buffer_size =
(uint32_t)(sizeof(struct pva_cmd_acquire_engine) +
sizeof(struct pva_cmd_set_vpu_executable) +
sizeof(struct pva_cmd_set_ppe_executable) +
sizeof(struct pva_cmd_prefetch_vpu_code) +
sizeof(struct pva_cmd_fetch_dma_configuration) +
sizeof(struct pva_cmd_init_vpu_executable) +
sizeof(struct pva_cmd_init_ppe_executable) +
sizeof(struct pva_cmd_set_vpu_instance_parameter) +
sizeof(struct pva_cmd_setup_misr) +
sizeof(struct pva_cmd_setup_dma) +
sizeof(struct pva_cmd_run_dma) +
sizeof(struct pva_cmd_run_vpu) +
sizeof(struct pva_cmd_run_ppe) +
sizeof(struct pva_cmd_release_engine));
// Allocate command buffer
cmd_buffer = pva_kmd_zalloc(cmd_buffer_size);
if (cmd_buffer == NULL) {
pva_kmd_log_err("Failed to allocate command buffer");
err = PVA_NOMEM;
goto out;
}
// Build command sequence
// 1. pva_cmd_acquire_engine
acquire_cmd.header.opcode = PVA_CMD_OPCODE_ACQUIRE_ENGINE;
acquire_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_acquire_engine) /
sizeof(uint32_t));
acquire_cmd.engine_count = 1;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&acquire_cmd,
sizeof(acquire_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_acquire_engine);
// 2. pva_cmd_set_vpu_executable
set_vpu_exec_cmd.header.opcode = PVA_CMD_OPCODE_SET_VPU_EXECUTABLE;
set_vpu_exec_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_set_vpu_executable) /
sizeof(uint32_t));
set_vpu_exec_cmd.vpu_exec_resource_id =
ctx->pfsd_resource_ids.vpu_elf_resource_id;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&set_vpu_exec_cmd, sizeof(set_vpu_exec_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_set_vpu_executable);
// 3. pva_cmd_set_ppe_executable
set_ppe_exec_cmd.header.opcode = PVA_CMD_OPCODE_SET_PPE_EXECUTABLE;
set_ppe_exec_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_set_ppe_executable) /
sizeof(uint32_t));
set_ppe_exec_cmd.ppe_exec_resource_id =
ctx->pfsd_resource_ids.ppe_elf_resource_id;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&set_ppe_exec_cmd, sizeof(set_ppe_exec_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_set_ppe_executable);
// 4. pva_cmd_prefetch_vpu_code
prefetch_cmd.header.opcode = PVA_CMD_OPCODE_PREFETCH_VPU_CODE;
prefetch_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_prefetch_vpu_code) /
sizeof(uint32_t));
prefetch_cmd.entry_point_index = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&prefetch_cmd,
sizeof(prefetch_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_prefetch_vpu_code);
// 5. pva_cmd_fetch_dma_configuration
fetch_dma_cmd.header.opcode = PVA_CMD_OPCODE_FETCH_DMA_CONFIGURATION;
fetch_dma_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_fetch_dma_configuration) /
sizeof(uint32_t));
fetch_dma_cmd.dma_set_id = 0;
fetch_dma_cmd.resource_id =
ctx->pfsd_resource_ids.dma_config_resource_id;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&fetch_dma_cmd, sizeof(fetch_dma_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_fetch_dma_configuration);
// 6. pva_cmd_init_vpu_executable
init_vpu_cmd.header.opcode = PVA_CMD_OPCODE_INIT_VPU_EXECUTABLE;
init_vpu_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_init_vpu_executable) /
sizeof(uint32_t));
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&init_vpu_cmd,
sizeof(init_vpu_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_init_vpu_executable);
// 7. pva_cmd_init_ppe_executable
init_ppe_cmd.header.opcode = PVA_CMD_OPCODE_INIT_PPE_EXECUTABLE;
init_ppe_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_init_ppe_executable) /
sizeof(uint32_t));
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&init_ppe_cmd,
sizeof(init_ppe_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_init_ppe_executable);
// 8. pva_cmd_set_vpu_instance_parameter
set_vpu_param_cmd.header.opcode =
PVA_CMD_OPCODE_SET_VPU_INSTANCE_PARAMETER;
set_vpu_param_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_set_vpu_instance_parameter) /
sizeof(uint32_t));
set_vpu_param_cmd.symbol_id = 0x40U;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&set_vpu_param_cmd,
sizeof(set_vpu_param_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_set_vpu_instance_parameter);
// 9. pva_cmd_setup_misr
setup_misr_cmd.header.opcode = PVA_CMD_OPCODE_SETUP_MISR;
setup_misr_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_setup_misr) / sizeof(uint32_t));
setup_misr_cmd.misr_params.slot_mask_low0 = 0xFFFFFFFFU;
setup_misr_cmd.misr_params.slot_mask_low1 = 0xFFFFFFFFU;
setup_misr_cmd.misr_params.slot_mask_high = 0x1FU;
setup_misr_cmd.misr_params.misr_config.seed_crc0 = MISR_SEED_0_T26X;
setup_misr_cmd.misr_params.misr_config.seed_crc1 = MISR_SEED_1_T26X;
setup_misr_cmd.misr_params.misr_config.ref_addr = MISR_REF_0_T26X;
setup_misr_cmd.misr_params.misr_config.ref_data_1 = MISR_REF_1_T26X;
setup_misr_cmd.misr_params.misr_config.ref_data_2 = MISR_REF_2_T26X;
setup_misr_cmd.misr_params.misr_config.misr_timeout = MISR_TIMEOUT_T26X;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&setup_misr_cmd, sizeof(setup_misr_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_setup_misr);
// 10. pva_cmd_setup_dma
setup_dma_cmd.header.opcode = PVA_CMD_OPCODE_SETUP_DMA;
setup_dma_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_setup_dma) / sizeof(uint32_t));
setup_dma_cmd.dma_set_id = 0;
(void)memcpy((void *)(cmd_buffer + offset),
(const void *)&setup_dma_cmd, sizeof(setup_dma_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_setup_dma);
// 11. pva_cmd_run_dma
run_dma_cmd.header.opcode = PVA_CMD_OPCODE_RUN_DMA;
run_dma_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_run_dma) / sizeof(uint32_t));
run_dma_cmd.dma_set_id = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&run_dma_cmd,
sizeof(run_dma_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_run_dma);
// 12. pva_cmd_run_vpu
run_vpu_cmd.header.opcode = PVA_CMD_OPCODE_RUN_VPU;
run_vpu_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_run_vpu) / sizeof(uint32_t));
run_vpu_cmd.entry_point_index = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&run_vpu_cmd,
sizeof(run_vpu_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_run_vpu);
// 13. pva_cmd_run_ppe
run_ppe_cmd.header.opcode = PVA_CMD_OPCODE_RUN_PPE;
run_ppe_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_run_ppe) / sizeof(uint32_t));
run_ppe_cmd.entry_point_index = 0;
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&run_ppe_cmd,
sizeof(run_ppe_cmd));
offset += (uint32_t)sizeof(struct pva_cmd_run_ppe);
// 14. pva_cmd_release_engine
release_cmd.header.opcode = PVA_CMD_OPCODE_RELEASE_ENGINE;
release_cmd.header.len =
(uint8_t)(sizeof(struct pva_cmd_release_engine) /
sizeof(uint32_t));
(void)memcpy((void *)(cmd_buffer + offset), (const void *)&release_cmd,
sizeof(release_cmd));
// Register the command buffer with R5 segment so firmware can access it
cmd_source.data_ptr = cmd_buffer;
cmd_source.size = cmd_buffer_size;
err = pva_kmd_pfsd_register_buffer(
ctx, &cmd_source, 1, PVA_MEMORY_SEGMENT_R5,
&ctx->pfsd_resource_ids.cmd_buffer_resource_id);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to register PFSD command buffer");
goto free_buffer;
}
// Store the command buffer size in the global structure
ctx->pfsd_resource_ids.cmd_buffer_size = cmd_buffer_size;
free_buffer:
pva_kmd_free(cmd_buffer);
out:
return err;
}

View File

@@ -0,0 +1,146 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_PFSD_H
#define PVA_KMD_PFSD_H
#include "pva_kmd_cmdbuf.h"
#include "pva_api_dma.h"
#include "pva_utils.h"
struct pva_kmd_context;
#define PVA_PFSD_DATA_ARRAY_IN_LEN (512U)
#define PVA_PFSD_DATA_ARRAY_HIST_SHORT_LEN (512U)
#define PVA_PFSD_DATA_ARRAY_HIST_INT_LEN (256U)
extern const uint32_t in1[PVA_PFSD_DATA_ARRAY_IN_LEN];
extern const uint32_t in2[PVA_PFSD_DATA_ARRAY_IN_LEN];
extern const uint32_t in3[PVA_PFSD_DATA_ARRAY_IN_LEN];
extern const uint16_t hist_short_a[PVA_PFSD_DATA_ARRAY_HIST_SHORT_LEN];
extern const uint16_t hist_short_b[PVA_PFSD_DATA_ARRAY_HIST_SHORT_LEN];
extern const uint16_t hist_short_c[PVA_PFSD_DATA_ARRAY_HIST_SHORT_LEN];
extern const uint32_t hist_int_a[PVA_PFSD_DATA_ARRAY_HIST_INT_LEN];
extern const uint32_t hist_int_b[PVA_PFSD_DATA_ARRAY_HIST_INT_LEN];
extern const uint32_t hist_int_c[PVA_PFSD_DATA_ARRAY_HIST_INT_LEN];
#define DLUT_TBL0_NUM_ENTRIES (256U)
#define DLUT_TBL1_NUM_ENTRIES (28672U)
#define DLUT_TBL2_NUM_ENTRIES (9114U)
#define DLUT_TBL3_NUM_ENTRIES (2048U)
#define PVA_PFSD_DLUT_TBL0_SIZE (DLUT_TBL0_NUM_ENTRIES * sizeof(int16_t))
#define PVA_PFSD_DLUT_TBL1_SIZE (DLUT_TBL1_NUM_ENTRIES * sizeof(uint16_t))
#define PVA_PFSD_DLUT_TBL2_SIZE \
PVA_ROUND_UP((DLUT_TBL2_NUM_ENTRIES * sizeof(uint16_t)), 64U)
#define PVA_PFSD_DLUT_TBL3_SIZE (DLUT_TBL3_NUM_ENTRIES * sizeof(uint8_t))
extern const int16_t pva_pfsd_data_dlut_tbl0[];
extern const uint16_t pva_pfsd_data_dlut_tbl1[];
extern const uint16_t pva_pfsd_data_dlut_tbl2[];
extern const uint8_t pva_pfsd_data_dlut_tbl3[];
#define DLUT_IDX0_NUM_ENTRIES (8192U)
#define DLUT_IDX1_NUM_ENTRIES (4096U)
#define DLUT_IDX2_NUM_ENTRIES (8192U)
#define DLUT_IDX3_NUM_ENTRIES (4096U)
#define PVA_PFSD_DLUT_INDICES0_SIZE (DLUT_IDX0_NUM_ENTRIES * sizeof(int16_t))
#define PVA_PFSD_DLUT_INDICES1_SIZE (DLUT_IDX1_NUM_ENTRIES * sizeof(int32_t))
#define PVA_PFSD_DLUT_INDICES2_SIZE (DLUT_IDX2_NUM_ENTRIES * sizeof(int32_t))
#define PVA_PFSD_DLUT_INDICES3_SIZE (DLUT_IDX3_NUM_ENTRIES * sizeof(int32_t))
extern const int16_t pva_pfsd_data_dlut_indices0[];
extern const int32_t pva_pfsd_data_dlut_indices1[];
extern const int32_t pva_pfsd_data_dlut_indices2[];
extern const int32_t pva_pfsd_data_dlut_indices3[];
#define MISR_SEED_0_T23X 0xA5A5A5A5U
#define MISR_SEED_1_T23X 0x5A5A5A5AU
#define MISR_REF_0_T23X 0xFF9DB35CU
#define MISR_REF_1_T23X 0x9840285EU
#define MISR_REF_2_T23X 0x2035EA07U
#define MISR_TIMEOUT_T23X 0x1C9C38U
#define MISR_SEED_0_T26X 0xA5A5A5A5U
#define MISR_SEED_1_T26X 0x5A5A5A5AU
#define MISR_REF_0_T26X 0x31E64312U
#define MISR_REF_1_T26X 0x585AAACDU
#define MISR_REF_2_T26X 0x065AFA90U
#define MISR_TIMEOUT_T26X 0x2DC6C0U
struct pva_pfsd_resource_ids {
// Input buffer resource IDs
uint32_t in1_resource_id;
uint32_t in2_resource_id;
uint32_t in3_resource_id;
uint32_t hist_a_resource_id;
uint32_t hist_b_resource_id;
uint32_t hist_c_resource_id;
uint32_t dlut_tbl_resource_id;
uint32_t dlut_indices_resource_id;
// VPU executable resource ID
uint32_t vpu_elf_resource_id;
// PPE executable resource ID
uint32_t ppe_elf_resource_id;
// DMA configuration resource ID
uint32_t dma_config_resource_id;
// Command buffer resource ID
uint32_t cmd_buffer_resource_id;
// Command buffer size
uint32_t cmd_buffer_size;
};
#define PVA_PFSD_VPU_ELF_SIZE_T23X (1259220U)
extern const uint8_t pva_pfsd_vpu_elf_t23x[];
#define PVA_PFSD_VPU_ELF_SIZE_T26X (1279424U)
extern const uint8_t pva_pfsd_vpu_elf_t26x[];
#define PVA_PFSD_PPE_ELF_SIZE_T26X (222468U)
extern const uint8_t pva_pfsd_ppe_elf_t26x[];
extern const struct pva_dma_config pfsd_dma_cfg_t23x;
extern const struct pva_dma_config pfsd_dma_cfg_t26x;
/**
* Register PFSD input buffers with the resource table
*
* @param ctx PVA KMD context
* @return PVA_SUCCESS on success, error code otherwise
*/
enum pva_error pva_kmd_pfsd_register_input_buffers(struct pva_kmd_context *ctx);
/**
* Register PFSD ELF executables with the resource table
*
* @param ctx PVA KMD context
* @param chip_id Chip ID to determine which ELF to register
* @return PVA_SUCCESS on success, error code otherwise
*/
enum pva_error pva_kmd_pfsd_register_elf(struct pva_kmd_context *ctx);
/**
* Register PFSD DMA configuration with the resource table
*
* @param ctx PVA KMD context
* @param chip_id Chip ID to determine which DMA config to register
* @return PVA_SUCCESS on success, error code otherwise
*/
enum pva_error pva_kmd_pfsd_register_dma_config(struct pva_kmd_context *ctx);
/**
* Register PFSD command buffer for T23X with the resource table
*
* @param ctx PVA KMD context
* @return PVA_SUCCESS on success, error code otherwise
*/
enum pva_error pva_kmd_pfsd_t23x_register_cmdbuf(struct pva_kmd_context *ctx);
/**
* Register PFSD command buffer for T26X with the resource table
*
* @param ctx PVA KMD context
* @return PVA_SUCCESS on success, error code otherwise
*/
enum pva_error pva_kmd_pfsd_t26x_register_cmdbuf(struct pva_kmd_context *ctx);
#endif

View File

@@ -0,0 +1,732 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_pfsd.h"
const uint32_t in1[] = {
0x03020100U, 0x07060504U, 0x0B0A0908U, 0x0F0E0D0CU, 0x13121110U,
0x17161514U, 0x1B1A1918U, 0x1F1E1D1CU, 0x23222120U, 0x27262524U,
0x2B2A2928U, 0x2F2E2D2CU, 0x33323130U, 0x37363534U, 0x3B3A3938U,
0x3F3E3D3CU, 0x43424140U, 0x47464544U, 0x4B4A4948U, 0x4F4E4D4CU,
0x53525150U, 0x57565554U, 0x5B5A5958U, 0x5F5E5D5CU, 0x63626160U,
0x67666564U, 0x6B6A6968U, 0x6F6E6D6CU, 0x73727170U, 0x77767574U,
0x7B7A7978U, 0x7F7E7D7CU, 0x83828180U, 0x87868584U, 0x8B8A8988U,
0x8F8E8D8CU, 0x93929190U, 0x97969594U, 0x9B9A9998U, 0x9F9E9D9CU,
0xA3A2A1A0U, 0xA7A6A5A4U, 0xABAAA9A8U, 0xAFAEADACU, 0xB3B2B1B0U,
0xB7B6B5B4U, 0xBBBAB9B8U, 0xBFBEBDBCU, 0xC3C2C1C0U, 0xC7C6C5C4U,
0xCBCAC9C8U, 0xCFCECDCCU, 0xD3D2D1D0U, 0xD7D6D5D4U, 0xDBDAD9D8U,
0xDFDEDDDCU, 0xE3E2E1E0U, 0xE7E6E5E4U, 0xEBEAE9E8U, 0xEFEEEDECU,
0xF3F2F1F0U, 0xF7F6F5F4U, 0xFBFAF9F8U, 0xFFFEFDFCU, 0x03020100U,
0x07060504U, 0x0B0A0908U, 0x0F0E0D0CU, 0x13121110U, 0x17161514U,
0x1B1A1918U, 0x1F1E1D1CU, 0x23222120U, 0x27262524U, 0x2B2A2928U,
0x2F2E2D2CU, 0x33323130U, 0x37363534U, 0x3B3A3938U, 0x3F3E3D3CU,
0x43424140U, 0x47464544U, 0x4B4A4948U, 0x4F4E4D4CU, 0x53525150U,
0x57565554U, 0x5B5A5958U, 0x5F5E5D5CU, 0x63626160U, 0x67666564U,
0x6B6A6968U, 0x6F6E6D6CU, 0x73727170U, 0x77767574U, 0x7B7A7978U,
0x7F7E7D7CU, 0x83828180U, 0x87868584U, 0x8B8A8988U, 0x8F8E8D8CU,
0x93929190U, 0x97969594U, 0x9B9A9998U, 0x9F9E9D9CU, 0xA3A2A1A0U,
0xA7A6A5A4U, 0xABAAA9A8U, 0xAFAEADACU, 0xB3B2B1B0U, 0xB7B6B5B4U,
0xBBBAB9B8U, 0xBFBEBDBCU, 0xC3C2C1C0U, 0xC7C6C5C4U, 0xCBCAC9C8U,
0xCFCECDCCU, 0xD3D2D1D0U, 0xD7D6D5D4U, 0xDBDAD9D8U, 0xDFDEDDDCU,
0xE3E2E1E0U, 0xE7E6E5E4U, 0xEBEAE9E8U, 0xEFEEEDECU, 0xF3F2F1F0U,
0xF7F6F5F4U, 0xFBFAF9F8U, 0xFFFEFDFCU, 0x00FF0000U, 0x02FD01FEU,
0x04FB03FCU, 0x06F905FAU, 0x08F707F8U, 0x0AF509F6U, 0x0CF30BF4U,
0x0EF10DF2U, 0x10EF0FF0U, 0x12ED11EEU, 0x14EB13ECU, 0x16E915EAU,
0x18E717E8U, 0x1AE519E6U, 0x1CE31BE4U, 0x1EE11DE2U, 0x20DF1FE0U,
0x22DD21DEU, 0x24DB23DCU, 0x26D925DAU, 0x28D727D8U, 0x2AD529D6U,
0x2CD32BD4U, 0x2ED12DD2U, 0x30CF2FD0U, 0x32CD31CEU, 0x34CB33CCU,
0x36C935CAU, 0x38C737C8U, 0x3AC539C6U, 0x3CC33BC4U, 0x3EC13DC2U,
0x40BF3FC0U, 0x42BD41BEU, 0x44BB43BCU, 0x46B945BAU, 0x48B747B8U,
0x4AB549B6U, 0x4CB34BB4U, 0x4EB14DB2U, 0x50AF4FB0U, 0x52AD51AEU,
0x54AB53ACU, 0x56A955AAU, 0x58A757A8U, 0x5AA559A6U, 0x5CA35BA4U,
0x5EA15DA2U, 0x609F5FA0U, 0x629D619EU, 0x649B639CU, 0x6699659AU,
0x68976798U, 0x6A956996U, 0x6C936B94U, 0x6E916D92U, 0x708F6F90U,
0x728D718EU, 0x748B738CU, 0x7689758AU, 0x78877788U, 0x7A857986U,
0x7C837B84U, 0x7E817D82U, 0x807F7F80U, 0x827D817EU, 0x847B837CU,
0x8679857AU, 0x88778778U, 0x8A758976U, 0x8C738B74U, 0x8E718D72U,
0x906F8F70U, 0x926D916EU, 0x946B936CU, 0x9669956AU, 0x98679768U,
0x9A659966U, 0x9C639B64U, 0x9E619D62U, 0xA05F9F60U, 0xA25DA15EU,
0xA45BA35CU, 0xA659A55AU, 0xA857A758U, 0xAA55A956U, 0xAC53AB54U,
0xAE51AD52U, 0xB04FAF50U, 0xB24DB14EU, 0xB44BB34CU, 0xB649B54AU,
0xB847B748U, 0xBA45B946U, 0xBC43BB44U, 0xBE41BD42U, 0xC03FBF40U,
0xC23DC13EU, 0xC43BC33CU, 0xC639C53AU, 0xC837C738U, 0xCA35C936U,
0xCC33CB34U, 0xCE31CD32U, 0xD02FCF30U, 0xD22DD12EU, 0xD42BD32CU,
0xD629D52AU, 0xD827D728U, 0xDA25D926U, 0xDC23DB24U, 0xDE21DD22U,
0xE01FDF20U, 0xE21DE11EU, 0xE41BE31CU, 0xE619E51AU, 0xE817E718U,
0xEA15E916U, 0xEC13EB14U, 0xEE11ED12U, 0xF00FEF10U, 0xF20DF10EU,
0xF40BF30CU, 0xF609F50AU, 0xF807F708U, 0xFA05F906U, 0xFC03FB04U,
0xFFFFFF00U, 0x00000000U, 0x0000000FU, 0x000000F0U, 0x000000FFU,
0x00000F00U, 0x00000F0FU, 0x00000FF0U, 0x00000FFFU, 0x0000F000U,
0x0000F00FU, 0x0000F0F0U, 0x0000F0FFU, 0x0000FF00U, 0x0000FF0FU,
0x0000FFF0U, 0x0000FFFFU, 0x000F0000U, 0x000F000FU, 0x000F00F0U,
0x000F00FFU, 0x000F0F00U, 0x000F0F0FU, 0x000F0FF0U, 0x000F0FFFU,
0x000FF000U, 0x000FF00FU, 0x000FF0F0U, 0x000FF0FFU, 0x000FFF00U,
0x000FFF0FU, 0x000FFFF0U, 0x000FFFFFU, 0x00F00000U, 0x00F0000FU,
0x00F000F0U, 0x00F000FFU, 0x00F00F00U, 0x00F00F0FU, 0x00F00FF0U,
0x00F00FFFU, 0x00F0F000U, 0x00F0F00FU, 0x00F0F0F0U, 0x00F0F0FFU,
0x00F0FF00U, 0x00F0FF0FU, 0x00F0FFF0U, 0x00F0FFFFU, 0x00FF0000U,
0x00FF000FU, 0x00FF00F0U, 0x00FF00FFU, 0x00FF0F00U, 0x00FF0F0FU,
0x00FF0FF0U, 0x00FF0FFFU, 0x00FFF000U, 0x00FFF00FU, 0x00FFF0F0U,
0x00FFF0FFU, 0x00FFFF00U, 0x00FFFF0FU, 0x00FFFFF0U, 0x00FFFFFFU,
0x0F000000U, 0x0F00000FU, 0x0F0000F0U, 0x0F0000FFU, 0x0F000F00U,
0x0F000F0FU, 0x0F000FF0U, 0x0F000FFFU, 0x0F00F000U, 0x0F00F00FU,
0x0F00F0F0U, 0x0F00F0FFU, 0x0F00FF00U, 0x0F00FF0FU, 0x0F00FFF0U,
0x0F00FFFFU, 0x0F0F0000U, 0x0F0F000FU, 0x0F0F00F0U, 0x0F0F00FFU,
0x0F0F0F00U, 0x0F0F0F0FU, 0x0F0F0FF0U, 0x0F0F0FFFU, 0x0F0FF000U,
0x0F0FF00FU, 0x0F0FF0F0U, 0x0F0FF0FFU, 0x0F0FFF00U, 0x0F0FFF0FU,
0x0F0FFFF0U, 0x0F0FFFFFU, 0x0FF00000U, 0x0FF0000FU, 0x0FF000F0U,
0x0FF000FFU, 0x0FF00F00U, 0x0FF00F0FU, 0x0FF00FF0U, 0x0FF00FFFU,
0x0FF0F000U, 0x0FF0F00FU, 0x0FF0F0F0U, 0x0FF0F0FFU, 0x0FF0FF00U,
0x0FF0FF0FU, 0x0FF0FFF0U, 0x0FF0FFFFU, 0x0FFF0000U, 0x0FFF000FU,
0x0FFF00F0U, 0x0FFF00FFU, 0x0FFF0F00U, 0x0FFF0F0FU, 0x0FFF0FF0U,
0x0FFF0FFFU, 0x0FFFF000U, 0x0FFFF00FU, 0x0FFFF0F0U, 0x0FFFF0FFU,
0x0FFFFF00U, 0x0FFFFF0FU, 0x0FFFFFF0U, 0x0FFFFFFFU, 0xF0000000U,
0xF000000FU, 0xF00000F0U, 0xF00000FFU, 0xF0000F00U, 0xF0000F0FU,
0xF0000FF0U, 0xF0000FFFU, 0xF000F000U, 0xF000F00FU, 0xF000F0F0U,
0xF000F0FFU, 0xF000FF00U, 0xF000FF0FU, 0xF000FFF0U, 0xF000FFFFU,
0xF00F0000U, 0xF00F000FU, 0xF00F00F0U, 0xF00F00FFU, 0xF00F0F00U,
0xF00F0F0FU, 0xF00F0FF0U, 0xF00F0FFFU, 0xF00FF000U, 0xF00FF00FU,
0xF00FF0F0U, 0xF00FF0FFU, 0xF00FFF00U, 0xF00FFF0FU, 0xF00FFFF0U,
0xF00FFFFFU, 0xF0F00000U, 0xF0F0000FU, 0xF0F000F0U, 0xF0F000FFU,
0xF0F00F00U, 0xF0F00F0FU, 0xF0F00FF0U, 0xF0F00FFFU, 0xF0F0F000U,
0xF0F0F00FU, 0xF0F0F0F0U, 0xF0F0F0FFU, 0xF0F0FF00U, 0xF0F0FF0FU,
0xF0F0FFF0U, 0xF0F0FFFFU, 0xF0FF0000U, 0xF0FF000FU, 0xF0FF00F0U,
0xF0FF00FFU, 0xF0FF0F00U, 0xF0FF0F0FU, 0xF0FF0FF0U, 0xF0FF0FFFU,
0xF0FFF000U, 0xF0FFF00FU, 0xF0FFF0F0U, 0xF0FFF0FFU, 0xF0FFFF00U,
0xF0FFFF0FU, 0xF0FFFFF0U, 0xF0FFFFFFU, 0xFF000000U, 0xFF00000FU,
0xFF0000F0U, 0xFF0000FFU, 0xFF000F00U, 0xFF000F0FU, 0xFF000FF0U,
0xFF000FFFU, 0xFF00F000U, 0xFF00F00FU, 0xFF00F0F0U, 0xFF00F0FFU,
0xFF00FF00U, 0xFF00FF0FU, 0xFF00FFF0U, 0xFF00FFFFU, 0xFF0F0000U,
0xFF0F000FU, 0xFF0F00F0U, 0xFF0F00FFU, 0xFF0F0F00U, 0xFF0F0F0FU,
0xFF0F0FF0U, 0xFF0F0FFFU, 0xFF0FF000U, 0xFF0FF00FU, 0xFF0FF0F0U,
0xFF0FF0FFU, 0xFF0FFF00U, 0xFF0FFF0FU, 0xFF0FFFF0U, 0xFF0FFFFFU,
0xFFF00000U, 0xFFF0000FU, 0xFFF000F0U, 0xFFF000FFU, 0xFFF00F00U,
0xFFF00F0FU, 0xFFF00FF0U, 0xFFF00FFFU, 0xFFF0F000U, 0xFFF0F00FU,
0xFFF0F0F0U, 0xFFF0F0FFU, 0xFFF0FF00U, 0xFFF0FF0FU, 0xFFF0FFF0U,
0xFFF0FFFFU, 0xFFFF0000U, 0xFFFF000FU, 0xFFFF00F0U, 0xFFFF00FFU,
0xFFFF0F00U, 0xFFFF0F0FU, 0xFFFF0FF0U, 0xFFFF0FFFU, 0xFFFFF000U,
0xFFFFF00FU, 0xFFFFF0F0U, 0xFFFFF0FFU, 0xFFFFFF00U, 0xFFFFFF0FU,
0xFFFFFFF0U, 0xFFFFFFFFU,
};
const uint32_t in2[] = {
0xC695AE95U, 0xF77A4EAAU, 0xBF48B982U, 0xC6BA8FCAU, 0xF835626CU,
0xE65ACA49U, 0xE835B2AEU, 0xCC187C90U, 0xD41F28CDU, 0xFF65FD16U,
0xF7C9FD68U, 0xA98A92BAU, 0xEFE95EACU, 0xCB697C7AU, 0xD1A27AA6U,
0xE13183F2U, 0xE34102B4U, 0xE5BF9DA8U, 0xA1A2ECCAU, 0xCD5C4899U,
0xBC3B72B2U, 0x955EC4C2U, 0xE5D2A137U, 0xEEBB1F2AU, 0xEFBF29CBU,
0xD50B8808U, 0xB4CC3ACFU, 0xCE556261U, 0xCC672FC9U, 0xD2A311C3U,
0xC4EF6B80U, 0x92FCDE5EU, 0xCA1D606EU, 0x84382503U, 0xD9B76E28U,
0xC252C2DAU, 0xEA92EF4CU, 0xC1ED20D7U, 0x8E6B3F6AU, 0xBEB21819U,
0xC1531DEDU, 0x86353CD2U, 0xE83CAAD3U, 0xB13C7C99U, 0xD19EB94CU,
0xB9DF2579U, 0x926E008BU, 0xB4DFBC00U, 0x9F9EC322U, 0xB410ED56U,
0x823C049AU, 0xDBDA35D4U, 0xC96FB218U, 0xE80EA5D1U, 0xCA9554FEU,
0xB92EDBE4U, 0xBD1A2DD9U, 0xFF618FCDU, 0x87843E45U, 0x89815DA3U,
0xD204A191U, 0xCC73A9C6U, 0x9C7E3C01U, 0x9C2201FFU, 0xD0ABCEC9U,
0xF635AA2AU, 0xDE74C4D9U, 0xBB3EBE15U, 0xB822CB01U, 0xECE00443U,
0xF9F0D62FU, 0xF975E8EEU, 0xF3154115U, 0xE22D8102U, 0xAAB26587U,
0xC4B3FA61U, 0x9C0CA67CU, 0xBD206613U, 0xF993B662U, 0xBBAB699EU,
0xF1315369U, 0xFBCFBAFCU, 0x97859F72U, 0xBAA10581U, 0xE3DE60CDU,
0xE21AF471U, 0xF3CFE165U, 0xA0F88EA6U, 0xE17C843EU, 0xFB541FABU,
0xAA79EC49U, 0xB38125CFU, 0xC7C7C971U, 0xC6F8284BU, 0xCFA327CEU,
0x9873983AU, 0xBD2DD275U, 0xAE17ECA7U, 0xD3B2564FU, 0xF5509D76U,
0x9AF7F0EAU, 0xCDA32C7EU, 0xEEC68664U, 0x8E0D31FFU, 0xAFD0AD81U,
0x9978EBEBU, 0xD2C12C61U, 0xCBDD53FDU, 0xD69951FEU, 0xCC54E2C3U,
0x8788BD9BU, 0xC7CAA567U, 0xC8249DBFU, 0x9F0E5D0DU, 0x826BAAE9U,
0xAC02FE8CU, 0x8129517EU, 0xF63B8C4EU, 0xCCFB8D32U, 0xE2A5D5BDU,
0xF18FABF9U, 0xF775797CU, 0x9626FB8CU, 0xB957756AU, 0xBE6DA1C7U,
0xE5CA235BU, 0xD1CB0DA4U, 0xFB9B743CU, 0x93E21002U, 0xA57D63F4U,
0xF0EC11B2U, 0xAEDA00EDU, 0xF3209072U, 0xDFB29816U, 0xBCE732ECU,
0xA2F13DF3U, 0xF92B8401U, 0x8FA85F4DU, 0xEECE91F0U, 0xCFC4D600U,
0xDBFD4210U, 0xF6574F8BU, 0x978F7B67U, 0xA421DFCFU, 0x9565AC99U,
0x99FB2650U, 0xD024DE5BU, 0x968EFE17U, 0x9036B29FU, 0x9D206B8EU,
0xF934D3D4U, 0x81C65E98U, 0x9495E50AU, 0x8F5BCF61U, 0xBB1DD403U,
0xD30386D1U, 0xF525F2BCU, 0x8CE8E1A7U, 0xCE9EFB0DU, 0x890802BEU,
0xB266459BU, 0xBF8B0CBFU, 0xB7E203ABU, 0xA586D60EU, 0x9F3DA4D5U,
0xF4C93698U, 0xC8781401U, 0x986928D6U, 0x847195E5U, 0xB746A5F2U,
0xE82DFED6U, 0xE06ED7F6U, 0xAD9DF57DU, 0xFFBD7A3EU, 0x8490B7C5U,
0xC303A216U, 0x99B8A08EU, 0xD4B59621U, 0xD992A02EU, 0xA9EF532DU,
0xF1D601AFU, 0xD2C77402U, 0xABB5B1C6U, 0x866BE6B9U, 0xE2234363U,
0xE6D385C9U, 0xD96F6D8AU, 0xD749361FU, 0xF3BC6770U, 0xA80E6897U,
0xE05138DEU, 0xA622AD0CU, 0xE7997556U, 0x98333C89U, 0xCBA9831AU,
0x86D71A2BU, 0x8CFC7321U, 0x9421971BU, 0x9F404301U, 0x916E0907U,
0xCB683D0DU, 0x876E41D8U, 0xF1DCE0FDU, 0xF906328BU, 0x872BBC16U,
0xF66D98C2U, 0xBC09D4A1U, 0xA0E45CA4U, 0xCB232EE3U, 0x959C74CFU,
0xCAD3AFD2U, 0xBCF93092U, 0xE863E8D2U, 0xF6896198U, 0xC365174BU,
0xCA872C35U, 0xDD5CE761U, 0x9CD484D5U, 0xA1D06255U, 0xD1194ED1U,
0xC4E2ED6CU, 0x82219B33U, 0xF73BFBDDU, 0xAC7C62C2U, 0x9A54D7BCU,
0xC2E57EF7U, 0xB3537CEDU, 0xA7514ADEU, 0xD7071613U, 0xD293BFEFU,
0xB8BF53E5U, 0xA26F5320U, 0xDA0201C7U, 0xAA9C34E2U, 0x9B7585ABU,
0xE12DBDDDU, 0xA109CDA4U, 0xD77F5A4DU, 0x82121A81U, 0xEC2CFC88U,
0xED1BCF1CU, 0xCCE5CA53U, 0xA9262D1AU, 0xD57FB7EEU, 0xC36F2BEBU,
0xEC8B4466U, 0xA006E424U, 0xA0CC134CU, 0x895FC93BU, 0xC1D74679U,
0xF1E5621EU, 0xCE42B6A8U, 0xC3F8E1ACU, 0xE9215DFBU, 0xFABF196AU,
0xDE4DB968U, 0xAC06DCF3U, 0xAE129658U, 0x859F0446U, 0x830DF306U,
0x80A65647U, 0xBE5E582BU, 0xA57D4626U, 0xDAA8580EU, 0xE8FA8D0DU,
0xC0F2CBD2U, 0xBBD615EBU, 0x8A045AB2U, 0x9872261FU, 0xBDE8306CU,
0xF631573AU, 0x858DF53BU, 0x8ACDFAC0U, 0x9F578454U, 0xDB0DAD2AU,
0xCE3D26ABU, 0x8BE2C8BAU, 0xFB14914EU, 0xEF0939F8U, 0x954291F6U,
0xBCEBD7C7U, 0xE0EE9C16U, 0xE385489EU, 0x80E4B973U, 0xCA0FFA11U,
0xDE446208U, 0xDF3272DBU, 0xF616D704U, 0x8C56F860U, 0xE4D17722U,
0xF924CA0AU, 0x8CFD4EA7U, 0xA32FCF4DU, 0x9EA21031U, 0xE7A5A6B5U,
0x8C2A5C5BU, 0xDF94DC03U, 0xA37BBCA0U, 0x962EB70DU, 0xF8070222U,
0xE163ED0DU, 0x8C600E47U, 0xFD94F75DU, 0xEC31E7CDU, 0xABB7929BU,
0xD8A2A487U, 0xBA6F0E78U, 0xB79A5B56U, 0xD3B735D5U, 0xA9784870U,
0xCCDCED4CU, 0x90A30D9CU, 0x8A66E486U, 0xB06235EAU, 0x9187C70FU,
0xD476DE98U, 0x8EA697F2U, 0xF0BA39EBU, 0xCA8DB59CU, 0x9AFD9053U,
0xD58BB10DU, 0xC3B27FA7U, 0xA7FADEFAU, 0xF8BB805AU, 0xE2548FD8U,
0x8FA085B0U, 0x84E5DCB5U, 0xC1E96BDBU, 0xB31C4250U, 0x9B1493C2U,
0xB9F06DFDU, 0x94802F5DU, 0xA774A209U, 0xB785655AU, 0x80B2172AU,
0xD32C34A5U, 0x902809E2U, 0xBB2125A3U, 0x8AC68FFBU, 0xE3DF3FB7U,
0xE4996E13U, 0xD7A37D47U, 0xF4824D54U, 0xEF00529AU, 0x8805B331U,
0x860A1463U, 0xC3773132U, 0x96AC4B23U, 0xF6C44E4EU, 0x8E04E6CEU,
0xB1A9DB76U, 0xCC4FFF5BU, 0xD1B76675U, 0xD9A4BA71U, 0xC50B7FB6U,
0xB40BF64DU, 0xE9454021U, 0xC9F15C6BU, 0xF5F56228U, 0x9C618271U,
0xE505F02EU, 0xAFE5D025U, 0xB0E1B1CFU, 0x8C7A9237U, 0xE76B3580U,
0xB193C8F9U, 0xDFA6C6DCU, 0xF7933F62U, 0xECB4EE9CU, 0xEA6D56D7U,
0xDB727F19U, 0xD14E5CB0U, 0xC210D41EU, 0xCFF4CC6DU, 0xC04EAF4AU,
0xCA16874FU, 0xD5FEE0D1U, 0x83C5E07CU, 0xE0C2D273U, 0xCCC32F1FU,
0x91CAC74AU, 0x926CADE9U, 0x99132E7BU, 0xE3822DC0U, 0xEC11685AU,
0xDE1EAE31U, 0x978E240DU, 0xD556A87BU, 0xA8100A9CU, 0x8D838636U,
0xF1B82AEDU, 0x8D15FACAU, 0xBD69565BU, 0xA299DCBCU, 0x99908D02U,
0xA4D48BDBU, 0xD42DA5B5U, 0xF93753DEU, 0x9C67CB3DU, 0xC0E29452U,
0xE3A4AAB6U, 0xF7DA4A57U, 0x9230F102U, 0xA5B57ED4U, 0xC7CF16C4U,
0xD27FA04CU, 0xEFCC0624U, 0x9DCDF795U, 0xD64580C8U, 0xD08ED897U,
0xEA9126B5U, 0xE8104812U, 0xE2FB8680U, 0x83A45530U, 0xCB9275D2U,
0xCF0CEEDBU, 0xE1C30361U, 0xE32099E0U, 0xA4639756U, 0x89D30DFDU,
0xF0A42016U, 0x961BC243U, 0x96E908C8U, 0xAE0D7671U, 0xB8B59EFFU,
0xB07995CAU, 0xD2E2024DU, 0x8CE344B5U, 0xA9B0E9A8U, 0xEF49CD8AU,
0xCDC5D907U, 0x8D55945EU, 0xE72417E1U, 0xDFF6CA09U, 0xB30B1333U,
0xAEF32EA6U, 0xB2766A55U, 0xA2D71957U, 0xCCC1263BU, 0x88BBEB1DU,
0xF365F1EEU, 0xB7524CF0U, 0xF0CC332FU, 0xD661786EU, 0xBAF6A220U,
0xBC5EA902U, 0xA56E6749U, 0x9CB9A581U, 0x9F7F42E2U, 0xC9D1FEA0U,
0xA68CB37FU, 0x902362F8U, 0xDFEDC0E3U, 0xBD75BC47U, 0xBE30D969U,
0x98A35FE3U, 0xEDEF5211U, 0x9112DBB6U, 0xA586A498U, 0x97A03BB9U,
0x805CA941U, 0xF34C7D9FU, 0xA4F5D018U, 0xE780C122U, 0xD34347A8U,
0xD800E34BU, 0x9673EFC8U, 0x85B9B1FDU, 0xFAD7FCA2U, 0xE3351604U,
0x8E759D1AU, 0xEE3DEE90U, 0x9A8762F4U, 0xFF41D049U, 0xC49F66FEU,
0xD57E0515U, 0xBBA0794BU, 0xEA0DCE48U, 0xF237AA96U, 0xDB1FBC2DU,
0xB3DFCCE8U, 0x98C45E15U, 0xEB431F25U, 0x93CD8DCBU, 0xD63A1A5CU,
0xA973F88FU, 0xAC70EDAEU, 0xC4296C6DU, 0xBA86D445U, 0xD1F79246U,
0xDBC9A827U, 0xBAE37D86U, 0xC5440FE5U, 0x80BF783FU, 0xA2643EA9U,
0x9887578DU, 0xD8C05B8AU, 0xB8D82E71U, 0x9E41098AU, 0xD398582CU,
0x9C0D4475U, 0xACB6A6A4U, 0xC1D646BCU, 0xB694A76AU, 0xABF876EEU,
0x8675ADBAU, 0x8C12AC7FU, 0xE798F039U, 0xF0837C02U, 0xFE4A5715U,
0xC2B8AC67U, 0xA46348EAU,
};
const uint32_t in3[] = {
0x970EB52BU, 0xADFBCB8CU, 0xB830D6B6U, 0xED48CF87U, 0xD76FC41BU,
0xE4A1C464U, 0xB1723BF5U, 0x91F69861U, 0xB69956ABU, 0x8D3BE41CU,
0xCCDA15E7U, 0xFBDD6690U, 0x8DFB5C5BU, 0xEF3E5490U, 0x9464BE1EU,
0xE6BBB7E5U, 0xA8168302U, 0xB2A5C7A8U, 0xBA541011U, 0xC423C777U,
0xDF5C6E4DU, 0xFC2A56CDU, 0xFAB86EE1U, 0x8B54E53BU, 0x82A00487U,
0x86CB1B60U, 0xF2EDD574U, 0xF323808AU, 0x85157276U, 0xB5A681DBU,
0x9786C974U, 0x9C2427A1U, 0xE3A24D68U, 0xCFB7A02AU, 0x896CF728U,
0xBB121183U, 0xB459648FU, 0xBADF331DU, 0xCD08A9E4U, 0xEAF2BB3AU,
0xC81B1739U, 0x99E2BFCCU, 0xE6D021CAU, 0xD6167394U, 0x8921145CU,
0xFB34DFE8U, 0xBCD22B79U, 0xB137975EU, 0xADDAA791U, 0xF7263B8AU,
0xF55B5ED6U, 0x8D3715DEU, 0xF3509257U, 0xF013CDB7U, 0x988BFB19U,
0xF5F096DFU, 0xF6DEE918U, 0x8B79D08DU, 0xE9141769U, 0xFBF45B8EU,
0xC1205269U, 0x809AE0DDU, 0x9818832FU, 0xA4C29FD1U, 0xD0528108U,
0xA1857A57U, 0xDFD4B154U, 0x84ABE597U, 0xDC64AD75U, 0xACDD5B39U,
0xEF9EA0D1U, 0xA47FC4AEU, 0xC6C01B05U, 0xD66EC29BU, 0xFA963843U,
0xCFE12F61U, 0xD1A3A284U, 0xB76863BCU, 0x8118C6C0U, 0xFF7E4A15U,
0xAE8E9F47U, 0xF6742596U, 0x8CB55FF3U, 0xA1DF319EU, 0xE687F34DU,
0xA5415B0CU, 0x97CFC87DU, 0xDD66DC65U, 0xB0BB2B99U, 0x80E3DFE6U,
0xD95B37F3U, 0xF1DB7E02U, 0x817EC0C4U, 0xF173BB22U, 0x969E1DD3U,
0xD1D141CCU, 0x92F9357AU, 0xF672CF28U, 0xD67D2763U, 0xEF5DE2EFU,
0xA3502A61U, 0xC61BC834U, 0x93DDA79DU, 0xEA104566U, 0x9C8A8ACFU,
0x8E73DFE0U, 0xB9F174C7U, 0xEE2E2D53U, 0xC5DC439DU, 0xBB0A3B87U,
0xEDAC7768U, 0xF46AE2E4U, 0xB17E611DU, 0xFA61D75BU, 0x964A1482U,
0x9806546BU, 0x9FA33267U, 0xAE19DD00U, 0xF56D30D0U, 0xD05E5E01U,
0xAEFDBCE6U, 0xCEC868C4U, 0xC239DC03U, 0xB07C7DAAU, 0xC03C23E6U,
0xD8D7F9D7U, 0x824DBF76U, 0xD3355960U, 0xCF4AC8FFU, 0xD8CAE6D9U,
0xC2933C4FU, 0xF29AF360U, 0x9EE6AF0DU, 0xD670E3EDU, 0xDCAB38C6U,
0xBB7139DDU, 0xE4E4C3CDU, 0x969CAD8DU, 0xA99F6730U, 0xAAC1076AU,
0xD1A6E915U, 0x974BDE99U, 0x9F2BEA4EU, 0x83254A32U, 0x91ADB5F4U,
0xB575FED1U, 0x9B2B9E9DU, 0xB150E85CU, 0xE38FDBD1U, 0x9098CF6EU,
0x81AF465DU, 0x928D98B7U, 0xDF613832U, 0xC3E92260U, 0xC30A1662U,
0x9F9D5C18U, 0x9CC11C37U, 0xC557D5D8U, 0xF2D2B579U, 0xEC0BE536U,
0x9E22BCB2U, 0xB565F1C8U, 0xDEA6D896U, 0xBD096BBFU, 0x8BD6D5B5U,
0xBB52115CU, 0xF87AA59CU, 0xF0BB9983U, 0xD1EEBEEAU, 0xA21A0CCDU,
0x9B7CA0EDU, 0xA395A7FFU, 0xB965EB66U, 0xBAA88B3CU, 0xA6BAF231U,
0xCB13A15AU, 0xF01E8A0DU, 0xC1E690CFU, 0xFC6489B6U, 0xD3AE65DEU,
0xD27F603DU, 0xFE13D013U, 0xE63BFE95U, 0xB1E0986FU, 0xC1FCF274U,
0xA94614F7U, 0xD17DF487U, 0xDEBE0EABU, 0xEE9DEAD0U, 0xC450AA00U,
0xCAC9F3E2U, 0x8CC0A782U, 0xF9B69BC9U, 0xA970CC78U, 0xC9CA1341U,
0x858D717EU, 0xE4C2DDD5U, 0xC244B8DEU, 0xF6490B01U, 0xB6B19CBFU,
0xE45EC5ABU, 0x91C5ABEFU, 0xDA4744BEU, 0x9DC4B111U, 0xCC6E372BU,
0x810236EFU, 0xE8D8526BU, 0xBC8CC138U, 0xC2E8C7BEU, 0xE53CDC22U,
0x903B2716U, 0x956827FBU, 0xE350AC35U, 0xF67725ABU, 0xC748C06AU,
0xA54D9EA9U, 0x9FBD3AA3U, 0x98C6B4F2U, 0x840BAD55U, 0x8E5B2573U,
0xDD175EF2U, 0xCED5A137U, 0x9B1BCCF5U, 0xD6CDFABBU, 0xF8466DAFU,
0xE4E5E036U, 0xDC5B6C3AU, 0xDD094B84U, 0xA72A9914U, 0xD2A4773BU,
0x93BAE843U, 0x8B895EBFU, 0xE46A232AU, 0xEE022D01U, 0xA94E0FD0U,
0xB0D85A55U, 0xEF0463F1U, 0x9226623CU, 0xED651B8DU, 0xB1ED2BAFU,
0xF7633E5EU, 0xFDA042A3U, 0xC75553ABU, 0xDAB3EA93U, 0xF417684FU,
0x8E9E1415U, 0x8001893DU, 0x93D4A2F2U, 0xA764C907U, 0x840D3692U,
0xA22FC865U, 0x847C27FAU, 0xD2E2D7C9U, 0xBD4B955AU, 0xDB4A22B5U,
0xCB294578U, 0xA2317590U, 0xB7A58EEFU, 0xA83290FDU, 0xC95C0EA5U,
0x8A4A062BU, 0xBBED7940U, 0xD4E56D64U, 0xEEB42955U, 0xA9EFA642U,
0xFE337D35U, 0x9F8C83ABU, 0x98F40A33U, 0x9059DF71U, 0x8CF19F38U,
0xCAE135E2U, 0x87BD1DCFU, 0x8A91E1DCU, 0x9236898DU, 0xE2710862U,
0xFEA94A2BU, 0xA0D49DA3U, 0xE272919FU, 0x927DED1DU, 0xC83966AAU,
0xE67FC831U, 0xB4ADB582U, 0xCCB58EA4U, 0xB9629FFAU, 0xF1F94ADCU,
0xA7FFB15AU, 0x848BE573U, 0x942AC06CU, 0xDFA54049U, 0xACBE7670U,
0xDD86CF11U, 0xE9EF4674U, 0xE8ABEFB0U, 0xB26C3C76U, 0xD8A36FCAU,
0x929B95F2U, 0xB09FB9ABU, 0xF82FF375U, 0xAB8FA025U, 0xC0F9991CU,
0x852192ADU, 0xF670D608U, 0xC8B6B6EBU, 0x8FB37489U, 0x88A75F95U,
0xAB27BF4DU, 0x8E5CBEB4U, 0xA97BFD38U, 0x8D9A50EDU, 0xA0DAABD1U,
0xF1B563E3U, 0xF41A191EU, 0xD5886153U, 0xBE6AF287U, 0xAD7CB919U,
0xC781AC2FU, 0xE66AA3E1U, 0xB2089E8CU, 0xDBAC6C9CU, 0xC60FE42BU,
0xDEC714FCU, 0xB9333BADU, 0xAFFF2A9FU, 0xC77304ACU, 0xEB9F7823U,
0x88A29A69U, 0xDA0E9A9FU, 0x9C3F31CEU, 0x80D28DDEU, 0x859E3AC4U,
0xDD38CAEAU, 0x85F4208CU, 0xFC0F10CCU, 0xA5EF81D5U, 0x95A79515U,
0x84B67062U, 0xD1174123U, 0xA40453CAU, 0xAE326D9AU, 0xDEB19210U,
0xC4DEFF9BU, 0x9FE7D17DU, 0xD2CBAB2EU, 0x9A6760EFU, 0xDE52C405U,
0x80486447U, 0xE1E90D1EU, 0xC4BD67E6U, 0xB25102D3U, 0xBD9579BAU,
0x8ACD4C11U, 0x911817CFU, 0xF6C8B568U, 0xBACC76B1U, 0xD88B1C7CU,
0xE2682D8BU, 0xC36F111AU, 0xB299B71BU, 0xFEA75F5AU, 0xC4419EF9U,
0xB837F1DFU, 0xDBE02A44U, 0xCA35BF85U, 0xB44702ACU, 0x81CFAC1AU,
0xDFDD549AU, 0xB8FD730EU, 0xD2E6ED3DU, 0x83E1A864U, 0xE72FE0A8U,
0xB1987F4DU, 0xC8C0A800U, 0x8717B226U, 0x84642A7BU, 0xE32808EFU,
0xE56A762BU, 0x84AC8EC3U, 0xC511160DU, 0xAA27DE11U, 0xB6FD9196U,
0x82A68FC8U, 0xB4F52A23U, 0xC815A966U, 0xF96F4530U, 0xEFC1A0D4U,
0xA0A0C5E2U, 0xDBD772BBU, 0xB330B1EEU, 0xD33A7CFDU, 0xDA7ED215U,
0xF77250E7U, 0x8B726EDCU, 0xB65EFC5AU, 0xC1A8106CU, 0xBFB97188U,
0xB82EA874U, 0xA1856507U, 0xF8B6E496U, 0x8B1595B1U, 0xA5670D6BU,
0xDFE6C53FU, 0xBCAE14FEU, 0xEE27B56BU, 0xE6FE7765U, 0xC1123F79U,
0xD14FBE5AU, 0xCC68ED90U, 0xC5BECE3CU, 0x9660D468U, 0xF690CBA1U,
0xFCBC5FD3U, 0x99076430U, 0xAB85F5C4U, 0xC4D20939U, 0x9276A960U,
0x9B479698U, 0xE572CF1BU, 0xEE4E1C1BU, 0xCE784887U, 0xB8AD4C18U,
0xC8CCEE31U, 0xC5EA996EU, 0xC41FBAF4U, 0xFF2BEA8BU, 0x8792A9DBU,
0x83D92C7DU, 0xB75A92FFU, 0xA9180EE2U, 0xFC901113U, 0xC27028B0U,
0xCE7F1C4DU, 0xDC76D652U, 0xFF1E3DAEU, 0xBCA6D1B9U, 0xC3754DB7U,
0xC0307D27U, 0x8DF69013U, 0x8FDE3B47U, 0x85EF4B64U, 0xA457647BU,
0x866F06E9U, 0x82ABAB37U, 0xBD5EC8ABU, 0xB1F4FCADU, 0xC77DB470U,
0xCFD5720BU, 0xCD3C9346U, 0xACF0838BU, 0xBE238E27U, 0x9BB4DBCDU,
0xE59DCFA3U, 0x86F07C58U, 0xE19F753BU, 0xA9BD8A97U, 0x861C66E3U,
0xE9321F16U, 0xAD96B714U, 0xBD76F9E2U, 0x924A2DF8U, 0xAA26C828U,
0xFFE72292U, 0xE0C94A46U, 0x869D9E7AU, 0xFF056040U, 0x9D701BFFU,
0xCA12EC32U, 0xBF35DD67U, 0xAB66AC12U, 0xD9F12779U, 0xC52528CBU,
0xCFBE108EU, 0xE0602E62U, 0xC7D0D402U, 0x8D1CD939U, 0x92552B10U,
0x8F4E8872U, 0xDCF24B45U, 0xDF91BE56U, 0xBC3F0BFDU, 0x9B15D96CU,
0xFB469A23U, 0xA1DCDBA0U, 0xA20655C4U, 0xDCE60F5EU, 0xCB9A6638U,
0xA822BCA7U, 0xC6182E75U, 0xF9311D4CU, 0xE599B689U, 0xD8625C6DU,
0xA357E574U, 0xE580D91BU, 0xB92BA6B3U, 0xA9F583EFU, 0xE486395BU,
0xD69BC2B2U, 0xF4087021U, 0xA3BC16C2U, 0x82026EC5U, 0xCDF9979AU,
0xE8E13F8EU, 0xD1C07F53U, 0xAE59C5FDU, 0xB0B21390U, 0xDEDD588CU,
0xC0AEF10DU, 0xC0009C03U, 0xBBCFA3D1U, 0xA040AF63U, 0xFC3FA800U,
0xD6E57D3DU, 0x9B874986U,
};
const uint16_t hist_short_a[] = {
0x4C7BU, 0xBF75U, 0xA1D6U, 0xE10FU, 0xB22CU, 0xD048U, 0x73DBU, 0xA572U,
0x2CFDU, 0xBB19U, 0xE622U, 0xA707U, 0xAB8CU, 0x91ACU, 0xD4C7U, 0xA486U,
0x92D3U, 0x9997U, 0x58BBU, 0xA0A6U, 0x7C90U, 0xC9CCU, 0x2CB0U, 0xE2F2U,
0x0C80U, 0x8CE4U, 0x6C56U, 0xCA22U, 0x6B48U, 0xBAEBU, 0x15ACU, 0xA49EU,
0x6D68U, 0x9109U, 0xA33FU, 0xEE92U, 0x792FU, 0xB314U, 0x323EU, 0xC44EU,
0xCC2DU, 0xCCBEU, 0x8C6EU, 0xBCC2U, 0xAF2DU, 0xE8CBU, 0xD84EU, 0x9094U,
0xF4ECU, 0xD29FU, 0x8AC2U, 0xF5A1U, 0x77E8U, 0xC5EBU, 0xE822U, 0xC69BU,
0xD516U, 0xE18EU, 0xDD6DU, 0xD869U, 0xE411U, 0x9826U, 0x2191U, 0xA104U,
0x7F44U, 0xB979U, 0x963DU, 0xE86FU, 0x956CU, 0xC676U, 0xAC41U, 0xF492U,
0x7C5FU, 0x8F77U, 0x40F8U, 0xD823U, 0x8108U, 0x9919U, 0x0F32U, 0xA90FU,
0x99B4U, 0xF8C9U, 0xFD99U, 0xE2E5U, 0x3BE2U, 0x8C01U, 0xA634U, 0x85ADU,
0x69EFU, 0xAD08U, 0xA72AU, 0xC6ECU, 0xBBE0U, 0xAA4BU, 0xD757U, 0xBE11U,
0x4A69U, 0xB57FU, 0x3510U, 0xDD60U, 0x0995U, 0x8260U, 0x1696U, 0x823EU,
0xC17EU, 0x9A22U, 0xB8C2U, 0xEB2BU, 0xEEE5U, 0x92D2U, 0xB66AU, 0xECC2U,
0x4385U, 0xE0CDU, 0x66CDU, 0xD8BEU, 0x9E8DU, 0xB35EU, 0x189BU, 0xC25CU,
0x443AU, 0xB128U, 0x829EU, 0xCB85U, 0x3A2CU, 0xE360U, 0xC37EU, 0xEAA1U,
0x18DBU, 0xB3F5U, 0xCF99U, 0xA9D6U, 0x6FC0U, 0xDF34U, 0x953AU, 0xC36CU,
0x1091U, 0x81FAU, 0xF0C8U, 0xF84DU, 0xA46CU, 0xEC7BU, 0xAA45U, 0xFAC3U,
0xEE61U, 0xDB33U, 0xE04FU, 0xF87CU, 0x5079U, 0x8071U, 0x5851U, 0x883CU,
0x8779U, 0xBF69U, 0x0C5AU, 0xAABDU, 0x2FA8U, 0xC64EU, 0xD1E3U, 0xF4E8U,
0x416AU, 0x881DU, 0x393EU, 0xC8AEU, 0xE879U, 0xF726U, 0x02E8U, 0xA240U,
0xF200U, 0xB3D9U, 0xD75EU, 0x89F9U, 0xB952U, 0x8F02U, 0x3585U, 0x94A7U,
0x3E2BU, 0xE2B8U, 0x57DFU, 0xC261U, 0x4E20U, 0xD703U, 0x8266U, 0x93E0U,
0xDA7DU, 0x8DE6U, 0x884DU, 0xBA63U, 0x45E4U, 0xFE82U, 0xF358U, 0xC1DBU,
0x57E6U, 0xE43AU, 0xB5A4U, 0xDDB6U, 0x8892U, 0x8548U, 0x6877U, 0xE634U,
0xA66DU, 0xD604U, 0x2CFFU, 0xF1C4U, 0x12BDU, 0xE0F8U, 0x94CEU, 0xB138U,
0x0D4EU, 0xEA41U, 0x6336U, 0xE169U, 0xED1FU, 0xB974U, 0x94C7U, 0xA9AAU,
0x6F90U, 0x8C26U, 0x1CC8U, 0xFFC3U, 0x66AAU, 0x9E93U, 0xB0FAU, 0x9443U,
0x5606U, 0xC871U, 0x4F24U, 0x95BAU, 0xB3E2U, 0xB683U, 0x4806U, 0xFC4BU,
0x2682U, 0x9FB4U, 0x6D35U, 0xC586U, 0x7D8CU, 0x90F2U, 0x64AEU, 0x826CU,
0xC514U, 0x87E7U, 0xCBACU, 0xE7F5U, 0xE714U, 0x964CU, 0x9F92U, 0x95CEU,
0x53F9U, 0xA259U, 0x2CF8U, 0x94CFU, 0x92EAU, 0xD7AAU, 0xABDFU, 0x8693U,
0xE29DU, 0xF285U, 0x1B7DU, 0xDCF3U, 0x1457U, 0xECC8U, 0x890AU, 0xC88AU,
0x487CU, 0xCEB7U, 0x2714U, 0xCDC0U, 0x1DD8U, 0xF9C3U, 0x55CAU, 0xB8F8U,
0x8A4AU, 0xAF29U, 0x0AF8U, 0xB338U, 0xEA91U, 0xE2A2U, 0xF9DBU, 0xBB4FU,
0x27C0U, 0xB2FBU, 0x513CU, 0x8136U, 0xAAD5U, 0xCF93U, 0x7DC6U, 0xFB6CU,
0xA060U, 0x96F0U, 0x5EB8U, 0x8617U, 0xC5CCU, 0xF7B7U, 0xC6E2U, 0xB6A4U,
0xCBEDU, 0xCB9DU, 0x4358U, 0x88AAU, 0x2B90U, 0xB911U, 0x9101U, 0xD385U,
0x0F05U, 0xF0A0U, 0x12A4U, 0xCF5EU, 0x3093U, 0xE954U, 0x62FEU, 0x92F9U,
0x3F9DU, 0xE42DU, 0xC37EU, 0xC0FEU, 0x0EDEU, 0x998DU, 0x223AU, 0xD6B3U,
0xDEFBU, 0x9DF1U, 0x2335U, 0x8655U, 0xAB44U, 0x9F3DU, 0x2777U, 0xECA9U,
0x4A49U, 0xD415U, 0xC91CU, 0x9900U, 0x7D41U, 0xA5A1U, 0xD493U, 0x833EU,
0xD414U, 0xCC38U, 0x67D2U, 0x8844U, 0xCE6EU, 0xBE8EU, 0xFBD4U, 0xFF33U,
0xB90EU, 0x897AU, 0x7944U, 0x8E22U, 0x799AU, 0xFAA0U, 0x596EU, 0xA06BU,
0xD7FCU, 0x9439U, 0x3F67U, 0xF258U, 0x2051U, 0xD710U, 0xA3E9U, 0xDFD7U,
0x82BFU, 0xFB02U, 0x4BE1U, 0x9021U, 0x34EAU, 0xB35DU, 0x91C4U, 0xEBA2U,
0x5E86U, 0xDF7FU, 0x657EU, 0x9CB1U, 0xF4C3U, 0xFE9BU, 0x9E23U, 0xC3ACU,
0x28FCU, 0xDDB0U, 0x03A1U, 0x9829U, 0xC05DU, 0x9A5FU, 0x07F7U, 0xFBA2U,
0x26D6U, 0x9E7EU, 0x6BA1U, 0xB99DU, 0x2F6EU, 0xE84BU, 0x711FU, 0xF293U,
0x34BDU, 0xD29EU, 0xACAFU, 0x8DECU, 0x45B2U, 0xF5D2U, 0x08D2U, 0x9ED7U,
0x1481U, 0x9631U, 0x1421U, 0xB461U, 0x04A6U, 0x9E0BU, 0xCD90U, 0x9FABU,
0x8D65U, 0xC283U, 0x7E41U, 0x98ABU, 0x26FEU, 0xC017U, 0x6561U, 0xD6BDU,
0xBDA8U, 0x8B03U, 0x474FU, 0x9727U, 0x094AU, 0xB695U, 0x4067U, 0x8606U,
0x9331U, 0xA748U, 0x3E34U, 0xE9F2U, 0xD22CU, 0xF1A8U, 0xF1B7U, 0x86C7U,
0xA3B2U, 0x86A3U, 0xC6EFU, 0xF044U, 0x8FDAU, 0xCA74U, 0xCCAEU, 0xE453U,
0xCA90U, 0x886DU, 0x5037U, 0xE4D4U, 0xD4A5U, 0xDFF5U, 0xF166U, 0xA6EBU,
0xBBD8U, 0x9E71U, 0x0413U, 0xC841U, 0x6285U, 0x997FU, 0xF095U, 0xF10FU,
0xB0C2U, 0xD62DU, 0xA837U, 0x8F51U, 0xF967U, 0x8FE6U, 0xC544U, 0xEC5EU,
0xBC58U, 0xC3B2U, 0xFE0EU, 0xADF1U, 0x92D4U, 0x8C0AU, 0x49BDU, 0x8636U,
0x7C4FU, 0xC69DU, 0xB9D2U, 0xCC21U, 0xAF1EU, 0xDCF3U, 0x39F7U, 0xD1A1U,
0x0122U, 0xE349U, 0xB868U, 0x9388U, 0x7A5EU, 0xD7A7U, 0x9453U, 0x8A91U,
0xF69DU, 0xFD7AU, 0x4C8AU, 0xC950U, 0x860AU, 0x9159U, 0x9A4FU, 0x841EU,
0x1379U, 0xB995U, 0x15E4U, 0xDBCEU, 0x66FEU, 0xE872U, 0xDE09U, 0xC202U,
0x661BU, 0xC0A2U, 0x3BA3U, 0xC868U, 0xCF6FU, 0xE8EEU, 0x21F3U, 0xDF14U,
};
const uint32_t hist_int_a[] = {
0x9E1C83A1U, 0xF8EBD301U, 0xF86D58E4U, 0xE9B6E9D9U, 0xA10E8FA8U,
0xBE858759U, 0xE2E80725U, 0x86A84631U, 0x96E7E3C7U, 0x863FEC9AU,
0xEC291F4CU, 0xD0138A7AU, 0xB0357089U, 0xD0AF58A7U, 0xA6AF4D2DU,
0xA43DE0AAU, 0xF46B6F6AU, 0xA8B1BBF2U, 0xF2377844U, 0xDD4CAEF8U,
0xFA723B45U, 0xA0913E41U, 0x8DFEC288U, 0xD94F93D1U, 0xE1402F4EU,
0xCDFF5E8BU, 0x951F37A3U, 0x8180DEB1U, 0xCA3F068CU, 0xEC04B4E0U,
0x9D082837U, 0xE85B8A2DU, 0xE4F087E2U, 0x9575811CU, 0xD2127406U,
0x85FF178AU, 0xD3FB0875U, 0xB4FA7B2BU, 0x8CA75DBCU, 0xEAE2EC3CU,
0xBB3A67C5U, 0xF8D07D08U, 0xBAF676B7U, 0xEB6FD84EU, 0xC97FD5B0U,
0xE1A5C3E4U, 0x8FADB8F8U, 0xBDEB451AU, 0x8A577FD6U, 0x81E5313DU,
0x9B37F412U, 0x84C9BB1BU, 0xA2766F7EU, 0xA936B69AU, 0xDE194EECU,
0x83B69ECDU, 0xF7361526U, 0xF338868FU, 0x85377D7EU, 0xC1751BB2U,
0xDF3D3B70U, 0xA23FA5B6U, 0xA9D0A5DFU, 0xC42DC352U, 0xB7B526D2U,
0xFBE319E5U, 0xCA2CDADCU, 0x8BB02F47U, 0xB0DD9510U, 0xD6D43898U,
0xF6931B84U, 0xEC17FCD6U, 0xCFA4B5A1U, 0xB189923BU, 0xD787D524U,
0x99248B51U, 0x932F561FU, 0xE7358E1DU, 0xD70FD06BU, 0x9D86D5F5U,
0xE91ABF5AU, 0xF247C47DU, 0xA2509110U, 0x8B912ED8U, 0x9B7E7B17U,
0x8069DFFCU, 0x8F47CDA5U, 0x92B4903DU, 0xF3A2668CU, 0x947F4B24U,
0xD429ABEFU, 0xD2DFA1FCU, 0xB6BEF0DAU, 0xFDFA51CEU, 0x970D654EU,
0xEE7417ACU, 0xF9DD6BB3U, 0xE13A402AU, 0xFA2446F3U, 0xAABB00C4U,
0xB80E78C3U, 0xF0B76277U, 0x96D2FD9AU, 0x87B32E64U, 0xA240F4B2U,
0xEE5AD2BEU, 0xA0D7B9B5U, 0xB5704AD1U, 0xD59060DBU, 0xF7E78A20U,
0xD2F720C6U, 0xBEAB2035U, 0xEA2F4E9DU, 0xF547B1D6U, 0xCA3C4F0EU,
0x85ADC9B4U, 0xF5B191D3U, 0xD9841CB3U, 0x986259F2U, 0xE953F85FU,
0xEE0367D7U, 0xEC8C05E1U, 0xBC339A5BU, 0xA4C258B1U, 0xEA8657B0U,
0xD340FFA9U, 0x9336705DU, 0xE463C363U, 0xB47B3FD3U, 0x8D5AB751U,
0x8F1EC427U, 0xEC89B896U, 0xFE1219C8U, 0xA5F1C1C1U, 0xF43CE6FAU,
0xA0530E7BU, 0x944C9480U, 0x9514A0AFU, 0xD5C3594CU, 0xE9DCF55BU,
0x8CFC2ACFU, 0xA8BA7A13U, 0xA8881591U, 0xF72B796CU, 0x9E022BE9U,
0xF2C4649FU, 0xFCD94321U, 0x93B3BDBCU, 0xCC488152U, 0x953B9D13U,
0xFD07B61BU, 0xBA4BE92AU, 0x81C7A2F4U, 0xB93B5076U, 0xDF0E41DBU,
0xEC4DFAA4U, 0x8C7C501FU, 0xF244B239U, 0xD0B1BE08U, 0xC0F78FF3U,
0xFF9F698AU, 0xDFD0822FU, 0xAD814889U, 0xFDB18352U, 0x85C243F1U,
0xA1BE2F84U, 0x9E0491CDU, 0x9A0ED871U, 0xB6D2D033U, 0xF3C7EB1AU,
0x83EBCDCCU, 0xC3CEFB03U, 0x9C82652DU, 0xAC73E35DU, 0xBAFA746FU,
0xBA849116U, 0x9F3847FCU, 0xB7D3B790U, 0xCE384ED3U, 0xEB80C94FU,
0xCD0F54A3U, 0xCB4004EEU, 0xA5CCB279U, 0xCED6F798U, 0x847B5565U,
0x84DAF454U, 0xBB24F23CU, 0x90F7A584U, 0xF71FA68DU, 0x8BD6B044U,
0xD1EF3577U, 0xF6BF1017U, 0xEBA73274U, 0xFF707E01U, 0xF470936AU,
0xF1697665U, 0xA12EAD85U, 0x92752537U, 0x8B784ED6U, 0xD8017DB8U,
0x863D1051U, 0x8F641CA2U, 0x9BD078BBU, 0xA2BF757EU, 0xBBD80000U,
0xD6CAED2BU, 0xDD440695U, 0xDB1047FCU, 0x8E9EA4BBU, 0xAB7C5568U,
0xC691114BU, 0xDBADF95FU, 0xF6BC5A56U, 0xEC5DC3C4U, 0xAA84F0F7U,
0xFB37AFBBU, 0xF138B819U, 0xE5A9E333U, 0x8C2F5540U, 0xE8585EA6U,
0xF1809378U, 0xDE1E8AB7U, 0xDF176EBEU, 0xDD27C5ECU, 0xDD8F08B8U,
0xD3880228U, 0xCE913C51U, 0xFEBDB63DU, 0xE5FD275FU, 0xDA098B27U,
0xD6BF33F6U, 0xEC3A37B1U, 0xE96DA7C9U, 0xF28FACB1U, 0x8EF9AD2FU,
0xA545A7C9U, 0xC95A99DCU, 0xEC3DB3C4U, 0x8055EFC6U, 0xD7F93E98U,
0x97BA092CU, 0xC6E70111U, 0xB3A737F7U, 0x8E766383U, 0xB344C4D6U,
0xDE2C28EEU, 0x89AE133EU, 0xA47D7CEFU, 0xC3D60C21U, 0x95DD687EU,
0x8CD5DB95U, 0xB5569F99U, 0xF3FBF336U, 0xEBED4A53U, 0x927E6585U,
0xD18AFBEEU,
};
const uint16_t hist_short_b[] = {
0x0ECAU, 0x9213U, 0x170CU, 0xB702U, 0xFDE4U, 0x9FE7U, 0xB8CEU, 0xDAFBU,
0xFF02U, 0xC818U, 0x778DU, 0xC795U, 0x17A9U, 0xBEE0U, 0x1A40U, 0x999FU,
0x6C62U, 0xE1EDU, 0x53F5U, 0xACEAU, 0x1193U, 0x8797U, 0xB8FFU, 0xDCA6U,
0xBE42U, 0xA956U, 0x7F08U, 0xEC6BU, 0x872EU, 0xA4ECU, 0x07C9U, 0xEEA6U,
0xBFDBU, 0xB59AU, 0x7E76U, 0xF87CU, 0x6605U, 0xFF8BU, 0x81DBU, 0xAB12U,
0xC4B7U, 0xAFECU, 0xE954U, 0xBD18U, 0xFB4FU, 0x832FU, 0xFE3AU, 0xD34BU,
0xC8D6U, 0xC2D4U, 0x8AB0U, 0xD398U, 0x2824U, 0xC067U, 0xBA00U, 0x8A4AU,
0x55DAU, 0xC568U, 0x896EU, 0xF350U, 0x551EU, 0xED07U, 0x64A5U, 0xD77BU,
0xA07AU, 0xAA52U, 0x5302U, 0x8CEFU, 0x1D73U, 0xB277U, 0x9F7CU, 0xF26BU,
0xCA8FU, 0xD484U, 0x351DU, 0xF157U, 0xB9BDU, 0x8C0AU, 0x36F1U, 0xB672U,
0x8912U, 0x9E41U, 0xCB50U, 0x93A1U, 0xEFF0U, 0x9318U, 0x4755U, 0xC798U,
0x4A58U, 0x800DU, 0x771FU, 0xB805U, 0x4F1EU, 0xB63EU, 0x0A34U, 0xB5A8U,
0xF595U, 0xB081U, 0xB524U, 0xB5C9U, 0x8C0FU, 0xE0BAU, 0xBA4CU, 0xE06EU,
0x9E78U, 0xF2E2U, 0x875EU, 0xE3EAU, 0xB887U, 0xB3BAU, 0x674FU, 0xB5B7U,
0x120EU, 0xB783U, 0xE0ABU, 0xF421U, 0x214FU, 0xC002U, 0x67E9U, 0xFCEBU,
0x6A1AU, 0xE772U, 0x766DU, 0xAD09U, 0xCC8EU, 0xD466U, 0x0A94U, 0x91C5U,
0xC96FU, 0xB9F8U, 0xEA01U, 0x86DDU, 0xAA11U, 0x8430U, 0x93FFU, 0x8E7DU,
0x1F1EU, 0xF835U, 0x63CEU, 0x903BU, 0xCAF0U, 0xC4EFU, 0xA831U, 0x9676U,
0x2F1EU, 0xA3DDU, 0xBAE1U, 0xD808U, 0xEF86U, 0xDE0EU, 0x7976U, 0xA3EAU,
0x3200U, 0x900EU, 0x3EA4U, 0x944DU, 0x83AAU, 0xD992U, 0x2795U, 0xC090U,
0xF3C8U, 0xCA16U, 0x0FB9U, 0xBA4DU, 0xE1E2U, 0xA0FEU, 0x9241U, 0xBCF9U,
0x9717U, 0x9E37U, 0x9A69U, 0xD4B9U, 0xF990U, 0xF2B0U, 0xA926U, 0xD5BAU,
0x7B14U, 0xC8DBU, 0x1ADFU, 0xB2B3U, 0x110FU, 0xD2A6U, 0xE52EU, 0xB04DU,
0x914DU, 0xDFBCU, 0xDD9DU, 0xA70CU, 0xEFC3U, 0xC212U, 0x5ABCU, 0x99B5U,
0xC79EU, 0xADEAU, 0x99D4U, 0xC643U, 0xEEBBU, 0xA832U, 0xE6BDU, 0xA61FU,
0xFDA2U, 0xD67EU, 0xB9ACU, 0xED22U, 0x8EEEU, 0xBC96U, 0x2CC0U, 0xFA5CU,
0x748DU, 0xC52BU, 0x7E74U, 0x9AA5U, 0xA636U, 0x9E46U, 0xA68DU, 0xD539U,
0xBD18U, 0xAEF2U, 0x29E1U, 0xF7D9U, 0xCE22U, 0x95C9U, 0xB0E1U, 0xF909U,
0x399AU, 0xB226U, 0xB004U, 0xB6C8U, 0x4322U, 0xB603U, 0xD0B2U, 0xD05DU,
0x4A6DU, 0x8B82U, 0x3CB2U, 0xA8B4U, 0x79D8U, 0xA618U, 0xC582U, 0xD45DU,
0x5791U, 0xDB67U, 0x8AE7U, 0xF8BEU, 0xAAB0U, 0x84ABU, 0xE8DEU, 0xBB23U,
0x6884U, 0x9FCBU, 0x9A73U, 0xC6BEU, 0x439BU, 0xD4D9U, 0x3022U, 0xCDB6U,
0x3447U, 0x8D02U, 0x3256U, 0xFD0CU, 0x16DFU, 0xF3D6U, 0x31E9U, 0xE381U,
0xEC02U, 0xEA2EU, 0xA5CDU, 0xB06CU, 0x5EA9U, 0xDDDDU, 0x608FU, 0xAF5AU,
0x2441U, 0xCB12U, 0x04E0U, 0xFC24U, 0x071CU, 0x8494U, 0xE15AU, 0xFA04U,
0x2EC1U, 0xF3FDU, 0xD53FU, 0x9A5DU, 0x923BU, 0xF30EU, 0x685BU, 0xA623U,
0x8543U, 0xD126U, 0xD55DU, 0xA911U, 0x390DU, 0xF681U, 0xCFB1U, 0xDCA8U,
0x120FU, 0xD1C6U, 0xB2E5U, 0x9C99U, 0x9533U, 0xB106U, 0x69A0U, 0xAD2DU,
0x3DCCU, 0x9558U, 0x3FE3U, 0xB5B2U, 0x527FU, 0xE851U, 0xA650U, 0xB523U,
0xDA57U, 0xFC70U, 0x961AU, 0xBD2AU, 0xD673U, 0x82D9U, 0x0E9EU, 0x8973U,
0xC870U, 0xBA36U, 0xED52U, 0xF6AFU, 0x4088U, 0xECF4U, 0xB473U, 0xA465U,
0x9320U, 0xA71CU, 0x9F31U, 0xCAD1U, 0x1502U, 0xD3C0U, 0xB761U, 0xF22EU,
0xA411U, 0xC6F5U, 0x1C1FU, 0xD854U, 0x98BBU, 0xEC33U, 0xD2D2U, 0xBAF2U,
0xF15EU, 0xF2B1U, 0x2AF6U, 0xDF42U, 0x3B2EU, 0xE116U, 0x76A1U, 0xC3D8U,
0x0053U, 0x8854U, 0x743BU, 0xD797U, 0x4652U, 0xA081U, 0x1262U, 0xDA1AU,
0x2721U, 0xF431U, 0xDB85U, 0xD187U, 0x7C03U, 0x8747U, 0x64EDU, 0x8989U,
0x1B69U, 0x873AU, 0xCE82U, 0xEF98U, 0x0B3EU, 0xBEADU, 0xF5C0U, 0x83AAU,
0x649CU, 0xACC3U, 0xE1B1U, 0xC186U, 0x045EU, 0x8D1EU, 0x2D0CU, 0xE6FAU,
0xCF03U, 0xB836U, 0x44E6U, 0xFA12U, 0xE17FU, 0x8B5FU, 0x6223U, 0xDF53U,
0xE418U, 0xC4E3U, 0xF682U, 0xDF1FU, 0x1985U, 0xD182U, 0x8829U, 0x8BD9U,
0x12A1U, 0xB774U, 0xB240U, 0xBDB5U, 0x5AFCU, 0xC6CCU, 0x03FFU, 0xAA26U,
0xDD37U, 0x9CF7U, 0x962AU, 0xA7E2U, 0x7AA0U, 0xEDFEU, 0xDD8AU, 0xA54BU,
0x0A65U, 0xFF7AU, 0xC0F3U, 0x8E7FU, 0xEFEDU, 0xFF65U, 0x3186U, 0xF3ABU,
0x9C78U, 0xE007U, 0x6BF0U, 0x86ADU, 0x9674U, 0xFD34U, 0xB7E1U, 0xE741U,
0x3A72U, 0xF646U, 0xA1B2U, 0xBBE1U, 0xADA1U, 0xEAECU, 0x9F0EU, 0xA309U,
0x8363U, 0xFD68U, 0xB200U, 0xF80AU, 0xCC1AU, 0x8A03U, 0x5266U, 0xB59FU,
0xF6E6U, 0xF21CU, 0xAD9AU, 0x9563U, 0xB48AU, 0x94F2U, 0xDAFEU, 0xB700U,
0xA41CU, 0xF483U, 0xCE0FU, 0xE674U, 0x6328U, 0xC2DAU, 0xB6BDU, 0xABF7U,
0x804FU, 0xA42AU, 0xBE24U, 0x89A6U, 0xBABCU, 0xD61DU, 0x5D86U, 0xC122U,
0x544EU, 0xB189U, 0x355CU, 0xC41CU, 0x3B11U, 0xE66EU, 0x5EB3U, 0xB103U,
0xF64FU, 0xD29BU, 0x2AFEU, 0xE5D4U, 0x903AU, 0xA4AEU, 0x92C8U, 0xB2A3U,
0x96EEU, 0xEC81U, 0x26AEU, 0xA1E3U, 0x4AA9U, 0x99E5U, 0xD160U, 0xE2C7U,
0xC860U, 0xDDC4U, 0xF84BU, 0x84D1U, 0x706EU, 0x85D1U, 0x4BC3U, 0xDB2DU,
0xAA4BU, 0xFCDCU, 0x3C88U, 0x8FD5U, 0x9E29U, 0x90CCU, 0xA131U, 0xEEF9U,
};
const uint32_t hist_int_b[] = {
0x90A93FB7U, 0x826E31F4U, 0xD0241288U, 0xE6D6F079U, 0x91BFDA2CU,
0xE00B0BF0U, 0xD335B5BDU, 0xD5729684U, 0x8DFD09FEU, 0xDF404891U,
0xDBA8E042U, 0xD49A864DU, 0xAB620264U, 0xB89C8F60U, 0xA63BC044U,
0x8EAB0386U, 0xCC2547C9U, 0xFDE33AA2U, 0x993C97D9U, 0xC9A03E66U,
0xC733872DU, 0xAA961DE3U, 0xCDBED8B5U, 0x80C89AA6U, 0x866433C7U,
0xB6313FB3U, 0xC2CB78B0U, 0xC70699E2U, 0xFE997B57U, 0xABBA481FU,
0xA61ABBD5U, 0x8F42BB0EU, 0xAE287A14U, 0xF63ECE5DU, 0xF619AB87U,
0xBFE85440U, 0xD649DA4DU, 0xC94F6145U, 0x955AEAC4U, 0xE446E44BU,
0xA88FA9D6U, 0xF103CB06U, 0xB8E16A98U, 0xD3F1AC3AU, 0xA9A05A67U,
0xDF1D2ADCU, 0xE29CAFC0U, 0xF5C5A230U, 0xDD00657FU, 0xFBD94799U,
0xBF65E096U, 0xA433ECACU, 0xA66F657CU, 0x8D24B94BU, 0xA4FC8752U,
0xACD39943U, 0xC355F8FFU, 0xE7C80002U, 0xF3DA3325U, 0xC1EF7456U,
0x93824822U, 0x99F4EEFAU, 0xD1322F64U, 0xC1AAC236U, 0x9033BD58U,
0xC74BDAEBU, 0x81931676U, 0xE67D97A5U, 0x909B3C30U, 0x96EE013AU,
0xCAC47BF1U, 0xB92AE607U, 0x87F1CC41U, 0x83A5E689U, 0x8D1C9241U,
0xB19226A8U, 0xE2C31166U, 0xEFB94202U, 0xA757C8D8U, 0xBFC376E5U,
0xEB92899BU, 0xE6BDA96EU, 0xE3F76391U, 0x9201EF18U, 0xF3E262B9U,
0x88F3EAE3U, 0xBED5885BU, 0xB7385BB8U, 0xF0BBEAE6U, 0xB2AFBB81U,
0xF927D00EU, 0x843E3308U, 0xCCA4AA7BU, 0xCA59FF72U, 0xC5E8F53EU,
0xDCD867D3U, 0x91A5DA5EU, 0xC77C0BB4U, 0xC355FF79U, 0xA241168EU,
0xDE6A0CEEU, 0x8E1A7B6AU, 0xDB6BFC95U, 0xE65BD92FU, 0x91C061F3U,
0xE8888ED7U, 0x97EDFFD7U, 0xF4837359U, 0xD841D0D9U, 0xBF45C8AFU,
0xB446EA3EU, 0xC3D45A74U, 0xA603721DU, 0x983E4DCFU, 0xD5D6498CU,
0x99E5D4D7U, 0xA13238B3U, 0x94ABD1E8U, 0xD11E308FU, 0x91EE2399U,
0xC75B8D69U, 0xCA46009EU, 0x962C56A1U, 0x940037E4U, 0x94A00010U,
0xDC154BDFU, 0xF0D89FB8U, 0xA645DA6EU, 0xA3915793U, 0xB42E9F31U,
0xC886F0FDU, 0x81FB6481U, 0xC2491A9BU, 0xA3F2ED92U, 0xE8573DB1U,
0xD4097C8EU, 0x8C7B7C69U, 0x80453D88U, 0xC88CEFE8U, 0xE4BD4D42U,
0xBF8B0638U, 0xFCD3DA26U, 0xA891A7B7U, 0xE58E7855U, 0x951227F6U,
0xFE67F143U, 0xFF744D2CU, 0xB64460A9U, 0x9313C32BU, 0xD0927DBCU,
0xC8328442U, 0xDA6F5094U, 0x9AD87E5AU, 0xDE5EDAE3U, 0xEE6F8879U,
0xAF787E6AU, 0xBA7426C2U, 0xDF482831U, 0xD5BE58D9U, 0xDE057E55U,
0x9376C762U, 0x9E4549D6U, 0xE000E2D6U, 0xD5BFE1FDU, 0xC2383768U,
0xC8582087U, 0xA9C95E8BU, 0xCEB3B3D2U, 0xC89D5E10U, 0xF2564E73U,
0xB3710114U, 0x88286448U, 0xEF2A289AU, 0xDC02A8CBU, 0xEDB6DC9DU,
0x843C5090U, 0xDA6A9A0FU, 0xED2B29CAU, 0xBA80B139U, 0xED7E5D3AU,
0xBDBDA786U, 0x82B3357BU, 0xC7EDADCFU, 0xD89625E0U, 0xE112105EU,
0xB65D3648U, 0x880EA44AU, 0x9B863720U, 0x95A55E79U, 0xDDCCFD23U,
0xF98BB575U, 0xA91C25DBU, 0xFC1246F9U, 0xD98C984BU, 0xFEDC07D8U,
0xBE4A7E62U, 0xA1E4B8D3U, 0xA8A56663U, 0x8CFE3234U, 0xEA8216E3U,
0x9AFBB4D7U, 0xC06F3348U, 0xF2AA7B2BU, 0x8A25DD71U, 0x9C71DC14U,
0xE06157C8U, 0x8E622E01U, 0xF6DC7623U, 0xCD8C8192U, 0xC8E2DF3AU,
0xE45AD35DU, 0x8B4A2918U, 0xCB9614B5U, 0xAC48812CU, 0xE3E04EF8U,
0xACA82513U, 0xE2A5B774U, 0xEBEEF343U, 0xC82E5C33U, 0xF84B15EDU,
0xC9BBF066U, 0xC1BA11A8U, 0xA1673BC8U, 0xC5CE3760U, 0x9B46A9F3U,
0xA04343A0U, 0x8418B5C2U, 0xBD2B62C6U, 0xC8E8AA04U, 0x9116E7F6U,
0xA7AD79A9U, 0xE3E45EDBU, 0xD1861B3EU, 0x9A57F4D4U, 0xEE0A3C4CU,
0xEDF7F752U, 0xFAB94C9DU, 0xFC6C6A4DU, 0xE4D46D75U, 0xC845CE2FU,
0xC54F4987U, 0xC92F40D3U, 0xD38FF748U, 0x90E55E3CU, 0xF577C1FFU,
0xB7704640U, 0xBD8D834FU, 0xD81D7974U, 0xA35F3983U, 0x85BBDF82U,
0xD0688F61U, 0xED1B29EAU, 0xC775F12AU, 0xF1CFCB2AU, 0xB2E9614AU,
0xE2BC9B1DU,
};
const uint16_t hist_short_c[] = {
0xE1B7U, 0x88CEU, 0x414CU, 0xAA7CU, 0x7B31U, 0xB012U, 0xC76FU, 0xBF67U,
0xB688U, 0xF69FU, 0xB07DU, 0xEB31U, 0x1618U, 0xB055U, 0x14F8U, 0x846AU,
0xCCAAU, 0xA7ACU, 0x4BB7U, 0xD3AFU, 0x75B4U, 0x8132U, 0xD541U, 0xCE0BU,
0x8339U, 0xCD85U, 0x8CB2U, 0x807EU, 0xC9B5U, 0xEA68U, 0x6A85U, 0xC64DU,
0xB903U, 0xC362U, 0xD9C2U, 0x8FB7U, 0x79CCU, 0x9F44U, 0xE6F6U, 0xB9A4U,
0xED8AU, 0xC50FU, 0x8126U, 0xB56AU, 0x9BB6U, 0xEAECU, 0xCE6BU, 0x80A1U,
0xADE6U, 0xF0D5U, 0x4AE4U, 0x8C00U, 0x31F6U, 0x95B5U, 0x5631U, 0xF56CU,
0xBEA1U, 0x829AU, 0x1FA6U, 0xA260U, 0xA7ABU, 0x91BBU, 0xA058U, 0x8B69U,
0x60F2U, 0xCCDCU, 0x22DCU, 0xC1CEU, 0x67C7U, 0xCAD1U, 0x177AU, 0xC37CU,
0xD35AU, 0xACFFU, 0x7DE0U, 0xFB26U, 0x2C72U, 0xC7E6U, 0xA004U, 0xD4ACU,
0xC997U, 0xCED5U, 0xA226U, 0xC918U, 0x7546U, 0xA2B8U, 0x4CD0U, 0x9C5BU,
0x2ED8U, 0xC997U, 0x3EFBU, 0x8D21U, 0xB755U, 0xE2A8U, 0xE7DCU, 0x8CF9U,
0x18BDU, 0x9CD9U, 0x3121U, 0x81EDU, 0xCED2U, 0xC69EU, 0x0648U, 0xE1E9U,
0xB247U, 0xB757U, 0x6A88U, 0xB18BU, 0xD4B3U, 0xE28AU, 0x602EU, 0xA82DU,
0xB56CU, 0xBD8BU, 0x06A9U, 0xF840U, 0xB65FU, 0x9D99U, 0x740EU, 0xC026U,
0x264FU, 0x9AA0U, 0x5E0AU, 0xAF55U, 0x1466U, 0xCB90U, 0x8741U, 0xE77CU,
0x80E7U, 0xF123U, 0x7C2EU, 0x9661U, 0x9EBCU, 0xAAF8U, 0x5441U, 0x9E23U,
0xFA0EU, 0x9187U, 0xCB2EU, 0xF2DEU, 0xF445U, 0xF2CFU, 0xC3A5U, 0xE05DU,
0x6D55U, 0xBBF7U, 0x698BU, 0x9588U, 0x1075U, 0xFCB9U, 0x9C2DU, 0x858EU,
0xA886U, 0xA2A9U, 0xC7CAU, 0xDF61U, 0x8409U, 0x9288U, 0xC144U, 0xBF82U,
0xF8EBU, 0xE14EU, 0x52DBU, 0xD927U, 0xC78CU, 0xA16BU, 0xAB32U, 0x98A6U,
0xBD64U, 0x8AB2U, 0x9C3FU, 0x83F6U, 0x0B60U, 0xC0D4U, 0x72D0U, 0xC83EU,
0xA2E8U, 0xFC36U, 0xC1BFU, 0xDE6DU, 0xE6DEU, 0x8864U, 0xC937U, 0x96D6U,
0x1FCAU, 0x8DC3U, 0xFB45U, 0xD3F4U, 0x5078U, 0xFE53U, 0xA0B1U, 0xFEE6U,
0x7773U, 0xEA56U, 0xEF34U, 0xA94BU, 0xF4F2U, 0x9D09U, 0x7181U, 0xFBDEU,
0xBA63U, 0x9C2AU, 0xE937U, 0x8FD9U, 0x3526U, 0xDC3CU, 0x27B8U, 0xD822U,
0x52C3U, 0xA562U, 0x459BU, 0xD8F5U, 0xC3E5U, 0xDDB0U, 0xFB49U, 0xC80BU,
0x0D65U, 0xB857U, 0x47EFU, 0xF039U, 0xBC8DU, 0x878EU, 0x0650U, 0x99A6U,
0x9ACAU, 0xC960U, 0x8419U, 0xA8FAU, 0xB182U, 0xB24CU, 0x582EU, 0xD413U,
0x2058U, 0xACF1U, 0xBCE3U, 0xF320U, 0xCAFFU, 0x9C51U, 0xC340U, 0xA927U,
0x7EA2U, 0xD18EU, 0xB1DDU, 0xA4B6U, 0x8C77U, 0xBFFEU, 0x9E6CU, 0xDF51U,
0xAD22U, 0xF8ABU, 0xDCF0U, 0xBE51U, 0x3F1DU, 0xDE38U, 0x2495U, 0xE302U,
0xCC24U, 0xE79DU, 0x340FU, 0xFB42U, 0x9616U, 0xDEE0U, 0x8687U, 0x83C8U,
0x1D47U, 0x8B1CU, 0xCB3CU, 0xBB1CU, 0xAE3FU, 0xDBEAU, 0x700AU, 0xB07EU,
0x10D7U, 0x9412U, 0x7225U, 0xB99BU, 0x6B53U, 0xF88AU, 0x1E3CU, 0xCC69U,
0xBA14U, 0xA9D4U, 0x27E1U, 0x8019U, 0x248CU, 0xE60FU, 0x54DEU, 0xF335U,
0xABFAU, 0xA913U, 0xD60FU, 0x985BU, 0xAD0DU, 0xC748U, 0xCC53U, 0xD604U,
0x92F2U, 0x8B7CU, 0x780CU, 0xE39AU, 0x8F93U, 0xFF2CU, 0x1194U, 0xDD0BU,
0x29E9U, 0x8851U, 0x1C0BU, 0xBF2BU, 0xB001U, 0xBC5CU, 0xD70CU, 0x80FCU,
0xF8FBU, 0xFD7CU, 0xEF1EU, 0x9A94U, 0xFBA1U, 0xE3FEU, 0xC51FU, 0xE51AU,
0x232EU, 0x95D7U, 0x91B8U, 0xC2DFU, 0x4BA7U, 0xE8E3U, 0x4075U, 0xA0F3U,
0x5CF4U, 0xFDFCU, 0xF9E6U, 0xC4CDU, 0xB07FU, 0xD171U, 0x6DCCU, 0x920EU,
0x6C0BU, 0xFE69U, 0x1BD2U, 0xC9FCU, 0x8C08U, 0xDE77U, 0x261FU, 0xA83EU,
0x43B3U, 0xCA15U, 0xB095U, 0xC486U, 0x7AFEU, 0x9B73U, 0xEFAEU, 0xF328U,
0x86A4U, 0xDCE2U, 0x280BU, 0xE2BCU, 0xBC01U, 0xC92DU, 0x1996U, 0xE85FU,
0xA017U, 0xC656U, 0x4B94U, 0xC85AU, 0x2B2AU, 0xC56AU, 0xCA00U, 0xCEA7U,
0x679FU, 0x8785U, 0xDB2BU, 0x81C6U, 0xA10CU, 0xCFA4U, 0x609AU, 0x8502U,
0xCA4AU, 0x9C5BU, 0x9CAEU, 0xB3A3U, 0x25BAU, 0xEA1DU, 0xED78U, 0xB232U,
0x2E66U, 0xF683U, 0x7161U, 0xD300U, 0x2DEDU, 0xD326U, 0x8B5AU, 0xF47FU,
0x6B47U, 0x97CEU, 0xDE6CU, 0xA497U, 0xF926U, 0x868DU, 0xD753U, 0x9637U,
0xFA3EU, 0xEE93U, 0x852FU, 0xE505U, 0xFD72U, 0xBE75U, 0x3DF2U, 0xB8A9U,
0x35C4U, 0xA98CU, 0x7870U, 0xD9E9U, 0x2DA0U, 0xABD2U, 0xBC68U, 0x866EU,
0xA07BU, 0xBCA5U, 0xE9A1U, 0xF4FFU, 0xD5FEU, 0xEECDU, 0x4092U, 0x82FCU,
0x3535U, 0xBD5AU, 0x0128U, 0xB438U, 0x0A93U, 0xD1A4U, 0x9CD5U, 0xC4DFU,
0xDC54U, 0xB5FEU, 0xAB9FU, 0xA148U, 0xFD6FU, 0xC9E1U, 0xA69EU, 0xD25AU,
0x484DU, 0xD4ECU, 0x2329U, 0xB3FFU, 0x9416U, 0x848DU, 0x76B3U, 0xCB6FU,
0x948AU, 0x86FFU, 0xC203U, 0xD7B3U, 0x020EU, 0xBFEFU, 0xFFD2U, 0x9ECDU,
0xA06FU, 0xFC4BU, 0xFB34U, 0xC67CU, 0xD725U, 0xB505U, 0x9AADU, 0xEADFU,
0x8063U, 0xAB82U, 0xD497U, 0xF37BU, 0xD89FU, 0xA388U, 0xB627U, 0xD50EU,
0x4D08U, 0xCD65U, 0x063FU, 0xCF5BU, 0x728FU, 0xDB7DU, 0xED83U, 0x8A0AU,
0xEFE0U, 0xC45AU, 0x488DU, 0xCA4BU, 0x2E16U, 0x8D07U, 0x2516U, 0x81B5U,
0x49B6U, 0xFE83U, 0x38A9U, 0xDEABU, 0xC1EBU, 0xC694U, 0x260AU, 0xB482U,
0xE448U, 0xFFF3U, 0xBF5AU, 0x9076U, 0xCCA8U, 0x86DCU, 0x2C96U, 0xD4E0U,
0xE284U, 0xC475U, 0x60BEU, 0x8B6AU, 0xA349U, 0xA04FU, 0x770EU, 0xCB75U,
};
const uint32_t hist_int_c[] = {
0xA538EA22U, 0xA5BF52B3U, 0xA5FA7C30U, 0x99BC8E3EU, 0x8C3420C2U,
0xE8D4DF58U, 0xC5B444FBU, 0xB05EA112U, 0xF27B9D7CU, 0x9BD1FFB7U,
0xF180FE98U, 0xA404F1CAU, 0xDFEE3514U, 0xD7EF39A9U, 0xD508507DU,
0xB28A2B63U, 0xBDC364A7U, 0xF9B6E0B7U, 0xE52DBE2BU, 0xAA44FB95U,
0x9B9A0765U, 0xFF1308D5U, 0x8D0CCCF5U, 0xF95ECFC5U, 0x83E50120U,
0x92DE3D63U, 0xD48C1B88U, 0x80C1AB6BU, 0xA2B379ECU, 0xE558B9B2U,
0xEFBB4C9CU, 0xC7EC640EU, 0x8B180C65U, 0x95B5C8CCU, 0xE1A8F24DU,
0x974C2D28U, 0xFE8AA824U, 0xA75D3748U, 0xC7AACE3AU, 0xF10645A0U,
0xC32F3700U, 0xB92BCCD2U, 0x950B376AU, 0xA31D6C14U, 0x911B067CU,
0xEA1387E8U, 0xD5A79777U, 0xCEDE6B23U, 0xE3CA689FU, 0xBAD555A3U,
0xF92366B9U, 0xFF647005U, 0xB9E85E78U, 0x863033AEU, 0xF8C33FCAU,
0xBDCD5F98U, 0x990E7112U, 0xCD4F5B53U, 0xBE8F0B03U, 0xBBC1EAFEU,
0xB2A81505U, 0xAE4A579FU, 0x83AE4F0CU, 0xBDC0216AU, 0xC400206CU,
0xE5574159U, 0xD50C4E92U, 0xC28AC890U, 0x8CB478A2U, 0x9CB71CCCU,
0xB3910E31U, 0xCFE3AFA2U, 0xD5E2E99FU, 0xC89C459BU, 0xF3011BB6U,
0xE6FDF01BU, 0xB2AFCD83U, 0xC8A8B32DU, 0xB5DC5B3EU, 0x967A3623U,
0x837E08D0U, 0xAEFFC1F7U, 0x95DEA628U, 0xBD666748U, 0xB52FF5A6U,
0x8EA1E5F2U, 0xFB33C6E0U, 0xCE3E66B8U, 0xDBF14145U, 0xB9C2D1E3U,
0x8A0051B6U, 0x8E99564AU, 0xE80D2983U, 0x8DAEA0C2U, 0xCC5977B5U,
0xAC0D49EFU, 0xF305E21CU, 0xA165C647U, 0xEE98127FU, 0xFFBA5ABEU,
0xBE1CE314U, 0xA22920B0U, 0xCF9E0A60U, 0x93FFCCB3U, 0xEAC5664CU,
0xC29F2616U, 0xFAFDBCCEU, 0x9D7533CFU, 0x8B47D943U, 0xB0DA180CU,
0xB3EF69F2U, 0x8EC5E214U, 0xDFD9DA04U, 0xC9CE101AU, 0xCC2C495CU,
0x9509CFAAU, 0xD86FF60DU, 0xC760103DU, 0xE3483662U, 0xB4613752U,
0x8122E220U, 0xED488818U, 0xC2FA8D9DU, 0xE9300BA3U, 0xFAF728DAU,
0x8F540552U, 0x953D5592U, 0xEDFD0AF6U, 0xB0B9CB99U, 0x83D56812U,
0xEDB765B4U, 0xEED6AEADU, 0xA5FE88C2U, 0xBD557014U, 0x82D67B60U,
0x90C3EF0EU, 0xFFF4962AU, 0xFDD4382EU, 0xAE3922DEU, 0x8B3C6F6EU,
0xAEAE503BU, 0xE2288CD0U, 0x9A025182U, 0x8E882A3FU, 0xABF69CEBU,
0xE62E9ADEU, 0xA391F9E9U, 0x846692F8U, 0xAD8EAB1BU, 0x86DA304BU,
0xB8C7CA4AU, 0xAEB18D3CU, 0xF422B863U, 0xFBC257E7U, 0x97E198DFU,
0xEF19E13DU, 0x8B165D39U, 0xAD1EEE72U, 0xDD16EC34U, 0xBBD028D3U,
0xB0F45684U, 0xCACE51E8U, 0xAAA6D780U, 0xD6F2DF46U, 0x8823C1FDU,
0xAD7D52E1U, 0xE7B6CE55U, 0x88185827U, 0xAB518B0FU, 0x95EFF133U,
0x9354C795U, 0xD9FFDB4AU, 0xF8187E03U, 0xAD571917U, 0xE8880589U,
0xA40F1AEEU, 0x9385B3F6U, 0x8C19FF72U, 0xA875ADE6U, 0xC1145F11U,
0x92F42FBDU, 0xE13D7831U, 0xEFC5EC4DU, 0x8716E820U, 0xDCFFD018U,
0x87A7852DU, 0xF630C95EU, 0xE8162D52U, 0xB4C6739FU, 0xD347B592U,
0xA3E65625U, 0xE5BACA23U, 0x9E16077AU, 0xCE8D2DA5U, 0xBCADA969U,
0xA639C977U, 0xFC0A8086U, 0xA46477BEU, 0xAE52219FU, 0xA75C0B96U,
0xBA5468F1U, 0xC1A6E934U, 0x815BE6E0U, 0xB26CE6F5U, 0xEEFE024CU,
0xE9E3EC6AU, 0xD67C01E3U, 0x8283B642U, 0xF5FDEBDCU, 0xFEF1AFCAU,
0xC3981553U, 0x88F21B9AU, 0xE02F27FBU, 0xB35E01A1U, 0x900903BAU,
0xBD2EF813U, 0xBB0586CEU, 0x8639CD18U, 0xA5452565U, 0xEFCBFA6DU,
0xD98182AAU, 0xC92B7B8AU, 0xD586C490U, 0xF7978A25U, 0x97B8A930U,
0x92346DF9U, 0x9DD1539CU, 0x93C329B6U, 0xB698E5B8U, 0xCC23753BU,
0xBB1F354CU, 0xF0ED4EA9U, 0x8DCA5E70U, 0xBC7B1C2DU, 0xA35A359EU,
0xFCC860BCU, 0xA65F0897U, 0xF9D63782U, 0xFF4C16FEU, 0x9C5CF473U,
0xF8C7E74CU, 0xC2E42C51U, 0xA54F100DU, 0xD8F70F47U, 0xF6422DF2U,
0xB55813C8U, 0x9626075AU, 0xB147B4C0U, 0xBB91E0E0U, 0xBB6B2CC0U,
0xA113AF2DU, 0x9513638BU, 0x8496A84AU, 0xF69A73BDU, 0x8CAAEDB0U,
0x9C4F517AU
};
const int16_t pva_pfsd_data_dlut_tbl0[] = {
#include "dlut_data/table.0.csv"
};
const uint16_t pva_pfsd_data_dlut_tbl1[] = {
#include "dlut_data/table.1.csv"
};
const uint16_t pva_pfsd_data_dlut_tbl2[] = {
#include "dlut_data/table.2.csv"
};
const uint8_t pva_pfsd_data_dlut_tbl3[] = {
#include "dlut_data/table.3.csv"
};
const int16_t pva_pfsd_data_dlut_indices0[] = {
#include "dlut_data/indices.0.csv"
};
const int32_t pva_pfsd_data_dlut_indices1[] = {
#include "dlut_data/indices.1.csv"
};
const int32_t pva_pfsd_data_dlut_indices2[] = {
#include "dlut_data/indices.2.csv"
};
const int32_t pva_pfsd_data_dlut_indices3[] = {
#include "dlut_data/indices.3.csv"
};
const uint8_t pva_pfsd_vpu_elf_t23x[] = {
#include "elf/pva_pfsd_vpu_elf_t23x.csv"
};
const uint8_t pva_pfsd_vpu_elf_t26x[] = {
#include "elf/pva_pfsd_vpu_elf_t26x.csv"
};
const uint8_t pva_pfsd_ppe_elf_t26x[] = {
#include "elf/pva_pfsd_ppe_elf_t26x.csv"
};

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_limits.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_fw.h" #include "pva_fw.h"
#include "pva_kmd_device_memory.h" #include "pva_kmd_device_memory.h"
@@ -20,7 +21,8 @@ enum pva_error pva_kmd_prepare_suspend(struct pva_kmd_device *pva)
pva_kmd_set_cmd_suspend_fw(&cmd); pva_kmd_set_cmd_suspend_fw(&cmd);
err = pva_kmd_submit_cmd_sync(&pva->submitter, &cmd, sizeof(cmd), err = pva_kmd_submit_cmd_sync(&pva->submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -32,18 +34,168 @@ err_out:
return err; return err;
} }
static enum pva_error
init_context_resources(struct pva_kmd_cmdbuf_builder *builder,
struct pva_kmd_device *pva, struct pva_kmd_context *ctx,
struct pva_cmd_init_queue **queue_cmd_out,
const struct pva_syncpt_rw_info **syncpt_info_out)
{
struct pva_cmd_init_resource_table *res_cmd;
struct pva_cmd_init_queue *queue_cmd;
struct pva_cmd_init_shared_dram_buffer *shared_buf_cmd;
const struct pva_syncpt_rw_info *syncpt_info;
enum pva_error err = PVA_SUCCESS;
/**Initialize resource table */
res_cmd =
pva_kmd_reserve_cmd_space(builder, (uint16_t)sizeof(*res_cmd));
if (res_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for context registration in FW resume command failed\n");
err = PVA_NOMEM;
goto err_out;
}
pva_dbg_printf("PVA: Resume init resource table for context %d\n",
ctx->ccq_id);
pva_kmd_set_cmd_init_resource_table(
res_cmd, ctx->resource_table_id,
ctx->ctx_resource_table.table_mem->iova,
ctx->ctx_resource_table.n_entries, ctx->status_mem->iova);
queue_cmd = pva_kmd_reserve_cmd_space(builder,
(uint16_t)sizeof(*queue_cmd));
if (queue_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for queue registration in FW resume command failed\n");
err = PVA_NOMEM;
goto err_out;
}
/* Initialize shared buffer */
shared_buf_cmd = pva_kmd_reserve_cmd_space(
builder, (uint16_t)sizeof(*shared_buf_cmd));
if (shared_buf_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for shared buffer registration in FW resume command failed\n");
err = PVA_NOMEM;
goto err_out;
}
pva_dbg_printf("PVA: Resume shared buffer for context %d\n",
ctx->ccq_id);
/* Validate resource memory size and iova fit in uint32_t */
if ((pva->kmd_fw_buffers[ctx->ccq_id].resource_memory->size >
U32_MAX) ||
(pva->kmd_fw_buffers[ctx->ccq_id].resource_memory->iova >
U32_MAX)) {
pva_kmd_log_err("Resource memory size or iova exceeds U32_MAX");
err = PVA_INVAL;
goto err_out;
}
/* CERT INT31-C: iova and size validated to fit in uint32_t, safe to cast */
pva_kmd_set_cmd_init_shared_dram_buffer(
shared_buf_cmd, ctx->ccq_id,
pva->kmd_fw_buffers[ctx->ccq_id].resource_memory->iova,
pva->kmd_fw_buffers[ctx->ccq_id].resource_memory->size);
pva_dbg_printf("PVA: Resume priv queue for context %d\n", ctx->ccq_id);
syncpt_info = pva_kmd_queue_get_rw_syncpt_info(pva, PVA_PRIV_CCQ_ID,
ctx->ccq_id);
*queue_cmd_out = queue_cmd;
*syncpt_info_out = syncpt_info;
err_out:
return err;
}
static enum pva_error init_context_user_queues(
struct pva_kmd_cmdbuf_builder *builder, struct pva_kmd_device *pva,
struct pva_kmd_context *ctx, struct pva_cmd_init_queue *priv_queue_cmd,
const struct pva_syncpt_rw_info *priv_syncpt_info)
{
struct pva_cmd_init_queue *queue_cmd;
struct pva_kmd_queue *queue;
const struct pva_syncpt_rw_info *syncpt_info;
enum pva_error err = PVA_SUCCESS;
pva_dbg_printf("PVA: Resume priv queue for context %d\n", ctx->ccq_id);
pva_kmd_set_cmd_init_queue(
priv_queue_cmd, PVA_PRIV_CCQ_ID,
ctx->ccq_id, /* For privileged queues, queue ID == user CCQ ID*/
ctx->ctx_queue.queue_memory->iova,
ctx->ctx_queue.max_num_submit, priv_syncpt_info->syncpt_id,
priv_syncpt_info->syncpt_iova);
/**Initialize resource table */
for (uint32_t j = 0; j < ctx->max_n_queues; j++) {
pva_kmd_mutex_lock(&ctx->queue_allocator.allocator_lock);
queue = pva_kmd_get_block_unsafe(&ctx->queue_allocator, j);
if (queue != NULL) {
pva_dbg_printf(
"PVA: Resume queue for context %d, queue %d\n",
queue->ccq_id, queue->queue_id);
queue_cmd = pva_kmd_reserve_cmd_space(
builder, (uint16_t)sizeof(*queue_cmd));
if (queue_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for queue registration in FW resume command failed\n");
err = PVA_NOMEM;
pva_kmd_mutex_unlock(
&ctx->queue_allocator.allocator_lock);
goto err_out;
}
syncpt_info = pva_kmd_queue_get_rw_syncpt_info(
pva, ctx->ccq_id, queue->queue_id);
pva_kmd_set_cmd_init_queue(queue_cmd, queue->ccq_id,
queue->queue_id,
queue->queue_memory->iova,
queue->max_num_submit,
syncpt_info->syncpt_id,
syncpt_info->syncpt_iova);
}
pva_kmd_mutex_unlock(&ctx->queue_allocator.allocator_lock);
}
err_out:
return err;
}
static enum pva_error
handle_submit_and_wait(struct pva_kmd_device *pva,
struct pva_kmd_cmdbuf_builder *builder)
{
enum pva_error err = PVA_SUCCESS;
uint32_t fence_val;
err = pva_kmd_submitter_submit(&pva->submitter, builder, &fence_val);
if (err != PVA_SUCCESS) {
// Error is either QUEUE_FULL or TIMEDOUT
pva_kmd_log_err(
"PVA: Submission for FW resume command failed\n");
goto err_out;
}
err = pva_kmd_submitter_wait(&pva->submitter, fence_val,
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Waiting for FW timed out when resuming from suspend state");
goto err_out;
}
err_out:
return err;
}
enum pva_error pva_kmd_complete_resume(struct pva_kmd_device *pva) enum pva_error pva_kmd_complete_resume(struct pva_kmd_device *pva)
{ {
struct pva_kmd_cmdbuf_builder builder; struct pva_kmd_cmdbuf_builder builder;
struct pva_kmd_submitter *dev_submitter = &pva->submitter; struct pva_kmd_submitter *dev_submitter = &pva->submitter;
struct pva_cmd_init_resource_table *res_cmd;
struct pva_cmd_init_queue *queue_cmd;
struct pva_cmd_resume_fw *fw_resume; struct pva_cmd_resume_fw *fw_resume;
struct pva_cmd_init_shared_dram_buffer *shared_buf_cmd;
enum pva_error err; enum pva_error err;
uint32_t fence_val;
struct pva_kmd_queue *queue;
const struct pva_syncpt_rw_info *syncpt_info;
err = pva_kmd_submitter_prepare(dev_submitter, &builder); err = pva_kmd_submitter_prepare(dev_submitter, &builder);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -52,7 +204,8 @@ enum pva_error pva_kmd_complete_resume(struct pva_kmd_device *pva)
goto err_out; goto err_out;
} }
fw_resume = pva_kmd_reserve_cmd_space(&builder, sizeof(*fw_resume)); fw_resume = pva_kmd_reserve_cmd_space(&builder,
(uint16_t)sizeof(*fw_resume));
if (fw_resume == NULL) { if (fw_resume == NULL) {
pva_kmd_log_err( pva_kmd_log_err(
"PVA: Memory alloc for FW resume command failed\n"); "PVA: Memory alloc for FW resume command failed\n");
@@ -66,117 +219,27 @@ enum pva_error pva_kmd_complete_resume(struct pva_kmd_device *pva)
struct pva_kmd_context *ctx = pva_kmd_get_context( struct pva_kmd_context *ctx = pva_kmd_get_context(
pva, sat_add8(i, PVA_KMD_USER_CONTEXT_ID_BASE)); pva, sat_add8(i, PVA_KMD_USER_CONTEXT_ID_BASE));
if (ctx != NULL) { if (ctx != NULL) {
/**Initialize resource table */ struct pva_cmd_init_queue *priv_queue_cmd;
res_cmd = pva_kmd_reserve_cmd_space(&builder, const struct pva_syncpt_rw_info *priv_syncpt_info;
sizeof(*res_cmd));
if (res_cmd == NULL) { err = init_context_resources(&builder, pva, ctx,
pva_kmd_log_err( &priv_queue_cmd,
"PVA: Memory alloc for context registration in FW resume command failed\n"); &priv_syncpt_info);
err = PVA_NOMEM; if (err != PVA_SUCCESS) {
goto cancel_builder; goto cancel_builder;
} }
pva_dbg_printf( err = init_context_user_queues(&builder, pva, ctx,
"PVA: Resume init resource table for context %d\n", priv_queue_cmd,
ctx->ccq_id); priv_syncpt_info);
pva_kmd_set_cmd_init_resource_table( if (err != PVA_SUCCESS) {
res_cmd, ctx->resource_table_id,
ctx->ctx_resource_table.table_mem->iova,
ctx->ctx_resource_table.n_entries);
queue_cmd = pva_kmd_reserve_cmd_space(
&builder, sizeof(*queue_cmd));
if (queue_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for queue registration in FW resume command failed\n");
err = PVA_NOMEM;
goto cancel_builder; goto cancel_builder;
} }
/* Initialize shared buffer */
shared_buf_cmd = pva_kmd_reserve_cmd_space(
&builder, sizeof(*shared_buf_cmd));
if (shared_buf_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for shared buffer registration in FW resume command failed\n");
err = PVA_NOMEM;
goto cancel_builder;
}
pva_dbg_printf(
"PVA: Resume shared buffer for context %d\n",
ctx->ccq_id);
pva_kmd_set_cmd_init_shared_dram_buffer(
shared_buf_cmd, ctx->ccq_id,
pva->kmd_fw_buffers[ctx->ccq_id]
.resource_memory->iova,
pva->kmd_fw_buffers[ctx->ccq_id]
.resource_memory->size);
pva_dbg_printf(
"PVA: Resume priv queue for context %d\n",
ctx->ccq_id);
syncpt_info = pva_kmd_queue_get_rw_syncpt_info(
pva, PVA_PRIV_CCQ_ID, ctx->ccq_id);
pva_kmd_set_cmd_init_queue(
queue_cmd, PVA_PRIV_CCQ_ID,
ctx->ccq_id, /* For privileged queues, queue ID == user CCQ ID*/
ctx->ctx_queue.queue_memory->iova,
ctx->ctx_queue.max_num_submit,
syncpt_info->syncpt_id,
syncpt_info->syncpt_iova);
/**Initialize resource table */
for (uint32_t j = 0; j < ctx->max_n_queues; j++) {
pva_kmd_mutex_lock(
&ctx->queue_allocator.allocator_lock);
queue = pva_kmd_get_block_unsafe(
&ctx->queue_allocator, j);
if (queue != NULL) {
pva_dbg_printf(
"PVA: Resume queue for context %d, queue %d\n",
queue->ccq_id, queue->queue_id);
queue_cmd = pva_kmd_reserve_cmd_space(
&builder, sizeof(*queue_cmd));
if (queue_cmd == NULL) {
pva_kmd_log_err(
"PVA: Memory alloc for queue registration in FW resume command failed\n");
err = PVA_NOMEM;
goto cancel_builder;
}
syncpt_info =
pva_kmd_queue_get_rw_syncpt_info(
pva, ctx->ccq_id,
queue->queue_id);
pva_kmd_set_cmd_init_queue(
queue_cmd, queue->ccq_id,
queue->queue_id,
queue->queue_memory->iova,
queue->max_num_submit,
syncpt_info->syncpt_id,
syncpt_info->syncpt_iova);
}
pva_kmd_mutex_unlock(
&ctx->queue_allocator.allocator_lock);
}
} }
} }
err = pva_kmd_submitter_submit(dev_submitter, &builder, &fence_val); err = handle_submit_and_wait(pva, &builder);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
// Error is either QUEUE_FULL or TIMEDOUT
pva_kmd_log_err(
"PVA: Submission for FW resume command failed\n");
goto cancel_builder;
}
err = pva_kmd_submitter_wait(dev_submitter, fence_val,
PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"Waiting for FW timed out when resuming from suspend state");
goto cancel_builder; goto cancel_builder;
} }

View File

@@ -5,7 +5,60 @@
#define PVA_KMD_PM_H #define PVA_KMD_PM_H
struct pva_kmd_device; struct pva_kmd_device;
/**
* @brief Prepare PVA device for system suspend operation
*
* @details This function performs the following operations:
* - Ensures all pending commands are completed or properly handled
* - Saves critical device state information for resume
* - Gracefully halts firmware execution in preparation for suspend
* - Configures hardware for low-power suspend state
* - Validates that device is ready for power state transition
* - Prepares synchronization mechanisms for suspend/resume cycle
* - Ensures proper resource cleanup before suspend
*
* This function is called as part of the system suspend sequence to ensure
* the PVA device can safely enter a suspended state without losing critical
* information or leaving the hardware in an inconsistent state.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS Device prepared for suspend successfully
* @retval PVA_AGAIN Device has pending operations preventing suspend
* @retval PVA_INTERNAL Firmware in invalid state for suspend
* @retval PVA_TIMEDOUT Timeout waiting for operations to complete
* @retval PVA_ERR_FW_ABORTED Power management operation failed
*/
enum pva_error pva_kmd_prepare_suspend(struct pva_kmd_device *pva); enum pva_error pva_kmd_prepare_suspend(struct pva_kmd_device *pva);
/**
* @brief Complete PVA device resume operation after system wake
*
* @details This function performs the following operations:
* - Restores hardware configuration and register state
* - Reinitializes firmware and brings it to operational state
* - Restores saved device context and operational parameters
* - Re-establishes communication channels with firmware
* - Validates device functionality after resume
* - Restores resource tables and memory mappings
* - Ensures device is fully operational for command processing
*
* This function is called as part of the system resume sequence to restore
* the PVA device to full operational state after waking from suspend.
* It ensures that all device functionality is restored and available.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS Device resumed successfully
* @retval PVA_ERR_FW_ABORTED Failed to boot or initialize firmware
* @retval PVA_INTERNAL Failed to initialize hardware after resume
* @retval PVA_TIMEDOUT Failed to establish firmware communication
* @retval PVA_UNKNOWN_ERROR Power management operation failed
* @retval PVA_INVAL Device in invalid state after resume
*/
enum pva_error pva_kmd_complete_resume(struct pva_kmd_device *pva); enum pva_error pva_kmd_complete_resume(struct pva_kmd_device *pva);
#endif #endif

View File

@@ -11,6 +11,7 @@
#include "pva_utils.h" #include "pva_utils.h"
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_kmd_limits.h"
void pva_kmd_queue_init(struct pva_kmd_queue *queue, struct pva_kmd_device *pva, void pva_kmd_queue_init(struct pva_kmd_queue *queue, struct pva_kmd_device *pva,
uint8_t ccq_id, uint8_t queue_id, uint8_t ccq_id, uint8_t queue_id,
@@ -43,7 +44,7 @@ pva_kmd_queue_submit(struct pva_kmd_queue *queue,
struct pva_fw_cmdbuf_submit_info *items = pva_offset_pointer( struct pva_fw_cmdbuf_submit_info *items = pva_offset_pointer(
queue->queue_header, sizeof(*queue->queue_header)); queue->queue_header, sizeof(*queue->queue_header));
if (pva_fw_queue_space(head, tail, size) == 0) { if (pva_fw_queue_space(head, tail, size) == 0U) {
return PVA_QUEUE_FULL; return PVA_QUEUE_FULL;
} }
@@ -65,7 +66,8 @@ static enum pva_error notify_fw_queue_deinit(struct pva_kmd_context *ctx,
pva_kmd_set_cmd_deinit_queue(&cmd, queue->ccq_id, queue->queue_id); pva_kmd_set_cmd_deinit_queue(&cmd, queue->ccq_id, queue->queue_id);
err = pva_kmd_submit_cmd_sync(&ctx->submitter, &cmd, sizeof(cmd), err = pva_kmd_submit_cmd_sync(&ctx->submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -105,7 +107,16 @@ enum pva_error pva_kmd_queue_create(struct pva_kmd_context *ctx,
goto err_free_queue; goto err_free_queue;
} }
pva_kmd_queue_init(queue, ctx->pva, ctx->ccq_id, *queue_id, /* Validate queue_id fits in uint8_t */
/* MISRA C-2023 Rule 10.4: Both operands must have same essential type */
if (*queue_id > (uint32_t)U8_MAX) {
pva_kmd_log_err("Queue ID exceeds U8_MAX");
err = PVA_INVAL;
goto err_free_queue;
}
/* CERT INT31-C: queue_id validated to fit in uint8_t, safe to cast */
pva_kmd_queue_init(queue, ctx->pva, ctx->ccq_id, (uint8_t)*queue_id,
submission_mem_kmd, in_args->max_submission_count); submission_mem_kmd, in_args->max_submission_count);
/* Get device mapped IOVA to share with FW */ /* Get device mapped IOVA to share with FW */
@@ -124,7 +135,8 @@ enum pva_error pva_kmd_queue_create(struct pva_kmd_context *ctx,
syncpt_info->syncpt_id, syncpt_info->syncpt_id,
syncpt_info->syncpt_iova); syncpt_info->syncpt_iova);
err = pva_kmd_submit_cmd_sync(&ctx->submitter, &cmd, sizeof(cmd), err = pva_kmd_submit_cmd_sync(&ctx->submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -182,9 +194,15 @@ const struct pva_syncpt_rw_info *
pva_kmd_queue_get_rw_syncpt_info(struct pva_kmd_device *pva, uint8_t ccq_id, pva_kmd_queue_get_rw_syncpt_info(struct pva_kmd_device *pva, uint8_t ccq_id,
uint8_t queue_id) uint8_t queue_id)
{ {
uint8_t ctx_offset = uint8_t ctx_offset;
safe_mulu32(ccq_id, PVA_NUM_RW_SYNCPTS_PER_CONTEXT); uint8_t syncpt_index_u8;
uint32_t syncpt_index = safe_addu32(ctx_offset, queue_id); uint32_t syncpt_index;
/* Use uint8_t arithmetic - all values fit in uint8_t range */
ctx_offset =
safe_mulu8(ccq_id, (uint8_t)PVA_NUM_RW_SYNCPTS_PER_CONTEXT);
syncpt_index_u8 = safe_addu8(ctx_offset, queue_id);
syncpt_index = (uint32_t)syncpt_index_u8;
ASSERT(syncpt_index < PVA_NUM_RW_SYNCPTS); ASSERT(syncpt_index < PVA_NUM_RW_SYNCPTS);
return &pva->rw_syncpts[syncpt_index]; return &pva->rw_syncpts[syncpt_index];

View File

@@ -7,32 +7,220 @@
#include "pva_kmd_device_memory.h" #include "pva_kmd_device_memory.h"
#include "pva_kmd_mutex.h" #include "pva_kmd_mutex.h"
/**
* @brief Structure for managing PVA command submission queues
*
* @details This structure represents a command queue used for submitting
* command buffers to the PVA firmware. Each queue is associated with a
* specific CCQ (Command and Control Queue) and maintains submission state,
* memory management, and synchronization mechanisms for thread-safe operation.
*/
struct pva_kmd_queue { struct pva_kmd_queue {
/**
* @brief Pointer to the parent PVA device
* Valid value: non-null
*/
struct pva_kmd_device *pva; struct pva_kmd_device *pva;
/**
* @brief Device memory allocation for queue data structures
*/
struct pva_kmd_device_memory *queue_memory; struct pva_kmd_device_memory *queue_memory;
/**
* @brief Pointer to firmware queue header for submission tracking
*/
struct pva_fw_submit_queue_header *queue_header; struct pva_fw_submit_queue_header *queue_header;
/**
* @brief CCQ (Command and Control Queue) identifier
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
*/
uint8_t ccq_id; uint8_t ccq_id;
/**
* @brief Queue identifier within the CCQ
* Valid range: [0 .. PVA_MAX_QUEUES_PER_CCQ-1]
*/
uint8_t queue_id; uint8_t queue_id;
/**
* @brief Maximum number of submissions this queue can hold
* Valid range: [1 .. UINT32_MAX]
*/
uint32_t max_num_submit; uint32_t max_num_submit;
}; };
/**
* @brief Initialize a PVA command queue structure
*
* @details This function performs the following operations:
* - Initializes all fields of the queue structure with provided parameters
* - Associates the queue with the specified PVA device and CCQ
* - Sets up queue memory and header pointers for submission tracking
* - Configures synchronization mechanisms using the provided CCQ lock
* - Prepares the queue for command buffer submissions
*
* The queue structure must be allocated before calling this function.
* After initialization, the queue is ready to accept command submissions
* using @ref pva_kmd_queue_submit().
*
* @param[out] queue Pointer to @ref pva_kmd_queue structure to initialize
* Valid value: non-null
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] ccq_id CCQ identifier for this queue
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
* @param[in] queue_id Queue identifier within the CCQ
* Valid range: [0 .. PVA_MAX_QUEUES_PER_CCQ-1]
* @param[in] ccq_lock Pointer to mutex for CCQ synchronization
* Valid value: non-null, must be initialized
* @param[in] queue_memory Pointer to allocated queue memory
* Valid value: non-null
* @param[in] max_num_submit Maximum number of submissions for this queue
* Valid range: [1 .. UINT32_MAX]
*/
void pva_kmd_queue_init(struct pva_kmd_queue *queue, struct pva_kmd_device *pva, void pva_kmd_queue_init(struct pva_kmd_queue *queue, struct pva_kmd_device *pva,
uint8_t ccq_id, uint8_t queue_id, uint8_t ccq_id, uint8_t queue_id,
struct pva_kmd_device_memory *queue_memory, struct pva_kmd_device_memory *queue_memory,
uint32_t max_num_submit); uint32_t max_num_submit);
/**
* @brief Create a new user queue within a context
*
* @details This function performs the following operations:
* - Validates the queue creation parameters provided by the user
* - Allocates a new queue identifier from the context's queue pool
* - Initializes queue data structures and memory allocations
* - Sets up the queue for the specified context and configuration
* - Registers the queue with the firmware for operation
* - Returns the allocated queue identifier to the caller
*
* The created queue can be used for submitting command buffers within
* the specified context. The queue should be destroyed using
* @ref pva_kmd_queue_destroy() when no longer needed.
*
* @param[in, out] ctx Pointer to @ref pva_kmd_context structure
* Valid value: non-null, must be initialized
* @param[in] in_args Pointer to queue creation parameters
* Valid value: non-null
* @param[out] queue_id Pointer to store the allocated queue identifier
* Valid value: non-null
*
* @retval PVA_SUCCESS Queue created successfully
* @retval PVA_INVAL Invalid parameters or context
* @retval PVA_NOMEM Failed to allocate queue resources
* @retval PVA_NO_RESOURCE_ID No available queue identifiers
* @retval PVA_TIMEDOUT Failed to register queue with firmware
*/
enum pva_error pva_kmd_queue_create(struct pva_kmd_context *ctx, enum pva_error pva_kmd_queue_create(struct pva_kmd_context *ctx,
const struct pva_ops_queue_create *in_args, const struct pva_ops_queue_create *in_args,
uint32_t *queue_id); uint32_t *queue_id);
/**
* @brief Destroy a user queue and free associated resources
*
* @details This function performs the following operations:
* - Validates that the queue identifier is valid for the context
* - Ensures no pending submissions remain in the queue
* - Unregisters the queue from firmware operation
* - Frees allocated memory and data structures for the queue
* - Returns the queue identifier to the context's available pool
* - Cleans up synchronization mechanisms and state
*
* All pending operations on the queue should be completed before
* calling this function. After destruction, the queue identifier
* becomes invalid and cannot be used for further operations.
*
* @param[in, out] ctx Pointer to @ref pva_kmd_context structure
* Valid value: non-null, must be initialized
* @param[in] queue_id Queue identifier to destroy
* Valid range: [0 .. max_queues-1]
*
* @retval PVA_SUCCESS Queue destroyed successfully
* @retval PVA_INVAL Invalid queue identifier or context
* @retval PVA_AGAIN Queue has pending operations
* @retval PVA_TIMEDOUT Failed to unregister queue from firmware
*/
enum pva_error pva_kmd_queue_destroy(struct pva_kmd_context *ctx, enum pva_error pva_kmd_queue_destroy(struct pva_kmd_context *ctx,
uint32_t queue_id); uint32_t queue_id);
/**
* @brief Submit a command buffer to the specified queue
*
* @details This function performs the following operations:
* - Validates the submission information and queue state
* - Acquires the queue's CCQ lock for thread-safe submission
* - Adds the submission to the queue's submission ring buffer
* - Updates queue pointers and submission tracking information
* - Notifies firmware of the new submission via CCQ mechanism
* - Releases the CCQ lock after successful submission
* - Handles submission errors and queue overflow conditions
*
* The command buffer must be properly prepared and all referenced
* resources must be registered before calling this function. The
* submission is processed asynchronously by the firmware.
*
* @param[in, out] queue Pointer to @ref pva_kmd_queue structure
* Valid value: non-null, must be initialized
* @param[in] submit_info Pointer to command buffer submission information
* Valid value: non-null
*
* @retval PVA_SUCCESS Submission completed successfully
* @retval PVA_INVAL Invalid queue or submission parameters
* @retval PVA_QUEUE_FULL Queue has no space for new submissions
* @retval PVA_TIMEDOUT Failed to notify firmware of submission
*/
enum pva_error enum pva_error
pva_kmd_queue_submit(struct pva_kmd_queue *queue, pva_kmd_queue_submit(struct pva_kmd_queue *queue,
struct pva_fw_cmdbuf_submit_info const *submit_info); struct pva_fw_cmdbuf_submit_info const *submit_info);
/**
* @brief Get available space in the submission queue
*
* @details This function performs the following operations:
* - Reads the current queue head and tail pointers
* - Calculates the number of available submission slots
* - Accounts for queue wraparound and boundary conditions
* - Returns the number of submissions that can be queued
* - Provides thread-safe access to queue state information
*
* This function can be used to check if the queue has space for
* additional submissions before attempting to submit command buffers.
* The returned value represents an instantaneous snapshot and may
* change if other threads are also submitting to the queue.
*
* @param[in] queue Pointer to @ref pva_kmd_queue structure
* Valid value: non-null, must be initialized
*
* @retval space_count Number of available submission slots in the queue
*/
uint32_t pva_kmd_queue_space(struct pva_kmd_queue *queue); uint32_t pva_kmd_queue_space(struct pva_kmd_queue *queue);
/**
* @brief Get read-write syncpoint information for a specific queue
*
* @details This function performs the following operations:
* - Validates the provided CCQ and queue identifiers
* - Looks up the syncpoint information for the specified queue
* - Returns the syncpoint configuration including ID and IOVA address
* - Provides access to queue-specific synchronization mechanisms
* - Ensures proper mapping between queues and their assigned syncpoints
*
* The returned syncpoint information can be used for synchronization
* operations and fence management specific to the queue. Each queue
* is assigned dedicated syncpoint resources for independent operation.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] ccq_id CCQ identifier
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
* @param[in] queue_id Queue identifier within the CCQ
* Valid range: [0 .. PVA_MAX_QUEUES_PER_CCQ-1]
*
* @retval non-null Pointer to @ref pva_syncpt_rw_info structure
* @retval NULL Invalid CCQ/queue identifier or not configured
*/
const struct pva_syncpt_rw_info * const struct pva_syncpt_rw_info *
pva_kmd_queue_get_rw_syncpt_info(struct pva_kmd_device *pva, uint8_t ccq_id, pva_kmd_queue_get_rw_syncpt_info(struct pva_kmd_device *pva, uint8_t ccq_id,
uint8_t queue_id); uint8_t queue_id);

View File

@@ -7,12 +7,105 @@
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#include "pva_kmd.h" #include "pva_kmd.h"
/**
* @brief Read data from R5 on-chip debug (OCD) interface
*
* @details This function performs read operations from the R5 processor's
* on-chip debug interface. It provides access to R5 debug registers, memory,
* and other debug-accessible resources for debugging and development purposes.
* The function reads data from the specified offset within the R5 debug space
* and copies it to the provided buffer.
*
* @param[in] dev Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] file_data Pointer to file-specific data context
* Valid value: platform-specific pointer or NULL
* @param[out] data Buffer to store read data
* Valid value: non-null, must have capacity >= size
* @param[in] offset Byte offset within R5 debug space to read from
* Valid range: [0 .. R5_DEBUG_SPACE_SIZE-1]
* @param[in] size Number of bytes to read
* Valid range: [1 .. remaining_space_from_offset]
*
* @retval >=0 Number of bytes successfully read
* @retval PVA_INVAL Invalid argument provided
* @retval PVA_INTERNAL Device not in proper state for debug access
* @retval PVA_EACCES Debug access not permitted
* @retval PVA_TIMEDOUT Timeout during debug operation
* @retval PVA_INTERNAL Hardware error during debug access
*/
int64_t pva_kmd_r5_ocd_read(struct pva_kmd_device *dev, void *file_data, int64_t pva_kmd_r5_ocd_read(struct pva_kmd_device *dev, void *file_data,
uint8_t *data, uint64_t offset, uint64_t size); uint8_t *data, uint64_t offset, uint64_t size);
/**
* @brief Write data to R5 on-chip debug (OCD) interface
*
* @details This function performs write operations to the R5 processor's
* on-chip debug interface. It provides access to write to R5 debug registers,
* memory, and other debug-accessible resources for debugging and development
* purposes. The function writes data from the provided buffer to the specified
* offset within the R5 debug space.
*
* @param[in] dev Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] file_data Pointer to file-specific data context
* Valid value: platform-specific pointer or NULL
* @param[in] data Buffer containing data to write
* Valid value: non-null, must contain valid data
* @param[in] offset Byte offset within R5 debug space to write to
* Valid range: [0 .. R5_DEBUG_SPACE_SIZE-1]
* @param[in] size Number of bytes to write
* Valid range: [1 .. remaining_space_from_offset]
*
* @retval >=0 Number of bytes successfully written
* @retval PVA_INVAL Invalid argument provided
* @retval PVA_INTERNAL Device not in proper state for debug access
* @retval PVA_EACCES Debug access not permitted
* @retval PVA_TIMEDOUT Timeout during debug operation
* @retval PVA_INTERNAL Hardware error during debug access
*/
int64_t pva_kmd_r5_ocd_write(struct pva_kmd_device *dev, void *file_data, int64_t pva_kmd_r5_ocd_write(struct pva_kmd_device *dev, void *file_data,
const uint8_t *data, uint64_t offset, const uint8_t *data, uint64_t offset,
uint64_t size); uint64_t size);
/**
* @brief Open R5 on-chip debug (OCD) interface for access
*
* @details This function initializes and opens the R5 processor's on-chip
* debug interface for subsequent debug operations. It performs necessary
* hardware setup, validation checks, and prepares the debug interface for
* read/write operations. This function must be called before any debug
* access operations can be performed.
*
* @param[in] dev Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS R5 OCD interface opened successfully
* @retval PVA_INVAL Invalid device pointer provided
* @retval PVA_INTERNAL Device not in proper state for debug access
* @retval PVA_EACCES Debug access not permitted
* @retval PVA_AGAIN Debug interface already in use
* @retval PVA_INTERNAL Hardware initialization failure
*/
int pva_kmd_r5_ocd_open(struct pva_kmd_device *dev); int pva_kmd_r5_ocd_open(struct pva_kmd_device *dev);
/**
* @brief Release R5 on-chip debug (OCD) interface and cleanup resources
*
* @details This function releases the R5 processor's on-chip debug interface
* and performs necessary cleanup operations. It ensures proper shutdown of
* the debug interface, releases any allocated resources, and restores the
* device to normal operation mode. This function should be called when debug
* access is no longer needed.
*
* @param[in] dev Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*
* @retval PVA_SUCCESS R5 OCD interface released successfully
* @retval PVA_INVAL Invalid device pointer provided
* @retval PVA_INTERNAL Device not in proper state for release
* @retval PVA_INTERNAL Hardware shutdown failure
*/
int pva_kmd_r5_ocd_release(struct pva_kmd_device *dev); int pva_kmd_r5_ocd_release(struct pva_kmd_device *dev);
#endif #endif

View File

@@ -7,147 +7,832 @@
#include "pva_api.h" #include "pva_api.h"
#include "pva_constants.h" #include "pva_constants.h"
/**
* @brief SEC (Security) subsystem base offset
*
* @details Base offset for SEC subsystem registers within PVA aperture.
* The SEC subsystem handles security-related functionality including
* error monitoring and interrupt management.
* Value: 0x20000 (128KB offset)
*/
#define PVA0_SEC_OFFSET 0x20000 #define PVA0_SEC_OFFSET 0x20000
/**
* @brief PROC (Processor) subsystem base offset
*
* @details Base offset for PROC subsystem registers within PVA aperture.
* The PROC subsystem manages the R5 processor control and status.
* Value: 0x30000 (192KB offset)
*/
#define PVA0_PROC_OFFSET 0x30000 #define PVA0_PROC_OFFSET 0x30000
/**
* @brief PM (Power Management) subsystem base offset
*
* @details Base offset for PM subsystem registers within PVA aperture.
* The PM subsystem handles power management and clock control.
* Value: 0x200000 (2MB offset)
*/
#define PVA0_PM_OFFSET 0x200000 #define PVA0_PM_OFFSET 0x200000
/**
* @brief CFG SID (Stream ID) configuration base offset
*
* @details Base offset for CFG SID registers within PVA aperture.
* These registers configure Stream IDs for SMMU translation.
* Value: 0x240000 (2.25MB offset)
*/
#define PVA0_CFG_SID_OFFSET 0x240000 #define PVA0_CFG_SID_OFFSET 0x240000
/**
* @brief CFG CCQ (Command and Control Queue) configuration base offset
*
* @details Base offset for CFG CCQ registers within PVA aperture.
* These registers configure the CCQ interfaces for command submission.
* Value: 0x260000 (2.375MB offset)
*/
#define PVA0_CFG_CCQ_OFFSET 0x260000 #define PVA0_CFG_CCQ_OFFSET 0x260000
/**
* @brief HSP (Hardware Synchronization Primitives) base offset
*
* @details Base offset for HSP registers within PVA aperture.
* HSP provides hardware synchronization mechanisms including
* semaphores and shared mailboxes.
* Value: 0x160000 (1.375MB offset)
*/
#define PVA0_HSP_OFFSET 0x160000 #define PVA0_HSP_OFFSET 0x160000
/**
* @brief EVP (Exception Vector Processor) base offset
*
* @details Base offset for EVP registers within PVA aperture.
* EVP manages exception vectors and interrupt handling for the R5.
* Value: 0x0 (base of aperture)
*/
#define PVA0_EVP_OFFSET 0x0 #define PVA0_EVP_OFFSET 0x0
/**
* @brief SEC subsystem aperture size
*
* @details Size of the SEC subsystem register aperture.
* Value: 0x10000 (64KB)
*/
#define PVA_KMD_PVA0_SEC_SIZE 0x10000 // 64KB #define PVA_KMD_PVA0_SEC_SIZE 0x10000 // 64KB
/**
* @brief PROC subsystem aperture size
*
* @details Size of the PROC subsystem register aperture.
* Value: 0x10000 (64KB)
*/
#define PVA_KMD_PVA0_PROC_SIZE 0x10000 // 64KB #define PVA_KMD_PVA0_PROC_SIZE 0x10000 // 64KB
/**
* @brief PM subsystem aperture size
*
* @details Size of the PM subsystem register aperture.
* Value: 0x10000 (64KB)
*/
#define PVA_KMD_PVA0_PM_SIZE 0x10000 // 64KB #define PVA_KMD_PVA0_PM_SIZE 0x10000 // 64KB
/**
* @brief CFG SID configuration aperture size
*
* @details Size of the CFG SID register aperture.
* Value: 0x20000 (128KB)
*/
#define PVA_KMD_PVA0_CFG_SID_SIZE 0x20000 // 128KB #define PVA_KMD_PVA0_CFG_SID_SIZE 0x20000 // 128KB
/**
* @brief CFG CCQ configuration aperture size
*
* @details Size of the CFG CCQ register aperture.
* Value: 0x80000 (512KB)
*/
#define PVA_KMD_PVA0_CFG_CCQ_SIZE 0x80000 // 512KB #define PVA_KMD_PVA0_CFG_CCQ_SIZE 0x80000 // 512KB
/**
* @brief HSP aperture size
*
* @details Size of the HSP register aperture.
* Value: 0x90000 (576KB)
*/
#define PVA_KMD_PVA0_HSP_SIZE 0x90000 // 576KB #define PVA_KMD_PVA0_HSP_SIZE 0x90000 // 576KB
/**
* @brief EVP aperture size
*
* @details Size of the EVP register aperture.
* Value: 0x10000 (64KB)
*/
#define PVA_KMD_PVA0_EVP_SIZE 0x10000 // 64KB #define PVA_KMD_PVA0_EVP_SIZE 0x10000 // 64KB
/* Exception vectors */ /**
* @brief Reset exception vector address
*
* @details Register address for the reset exception vector entry point.
* This vector is executed when the R5 processor is reset.
* Value: 0x20
*/
#define PVA_REG_EVP_RESET_ADDR 0x20 #define PVA_REG_EVP_RESET_ADDR 0x20
/**
* @brief Undefined instruction exception vector address
*
* @details Register address for the undefined instruction exception vector.
* This vector is executed when an undefined instruction is encountered.
* Value: 0x24
*/
#define PVA_REG_EVP_UNDEF_ADDR 0x24 #define PVA_REG_EVP_UNDEF_ADDR 0x24
/**
* @brief Software interrupt exception vector address
*
* @details Register address for the software interrupt exception vector.
* This vector is executed for software-generated interrupts (SWI).
* Value: 0x28
*/
#define PVA_REG_EVP_SWI_ADDR 0x28 #define PVA_REG_EVP_SWI_ADDR 0x28
/**
* @brief Prefetch abort exception vector address
*
* @details Register address for the prefetch abort exception vector.
* This vector is executed when a prefetch abort occurs.
* Value: 0x2c
*/
#define PVA_REG_EVP_PREFETCH_ABORT_ADDR 0x2c #define PVA_REG_EVP_PREFETCH_ABORT_ADDR 0x2c
/**
* @brief Data abort exception vector address
*
* @details Register address for the data abort exception vector.
* This vector is executed when a data abort occurs.
* Value: 0x30
*/
#define PVA_REG_EVP_DATA_ABORT_ADDR 0x30 #define PVA_REG_EVP_DATA_ABORT_ADDR 0x30
/**
* @brief Reserved exception vector address
*
* @details Register address for the reserved exception vector slot.
* This vector is reserved for future use.
* Value: 0x34
*/
#define PVA_REG_EVP_RSVD_ADDR 0x34 #define PVA_REG_EVP_RSVD_ADDR 0x34
/**
* @brief IRQ exception vector address
*
* @details Register address for the IRQ exception vector.
* This vector is executed for interrupt requests (IRQ).
* Value: 0x38
*/
#define PVA_REG_EVP_IRQ_ADDR 0x38 #define PVA_REG_EVP_IRQ_ADDR 0x38
/**
* @brief FIQ exception vector address
*
* @details Register address for the FIQ exception vector.
* This vector is executed for fast interrupt requests (FIQ).
* Value: 0x3c
*/
#define PVA_REG_EVP_FIQ_ADDR 0x3c #define PVA_REG_EVP_FIQ_ADDR 0x3c
/* R5 */ /**
* @brief R5 processor CPU halt control register address
*
* @details Register address for controlling R5 processor halt state.
* Writing to this register can halt or resume the R5 processor.
* Value: 0x30000
*/
#define PVA_REG_PROC_CPUHALT_ADDR 0x30000 #define PVA_REG_PROC_CPUHALT_ADDR 0x30000
/* SCRs */ /**
* @brief SEC external interrupt event SCR address
*
* @details Register address for SEC external interrupt event control.
* This SCR (Secure Configuration Register) manages external interrupts.
* Value: 0x28804
*/
#define PVA_SEC_SCR_SECEXT_INTR_EVENT 0x28804 #define PVA_SEC_SCR_SECEXT_INTR_EVENT 0x28804
/**
* @brief PROC subsystem SCR address
*
* @details Register address for PROC subsystem control.
* This SCR manages processor-related security configuration.
* Value: 0x30800
*/
#define PVA_PROC_SCR_PROC 0x30800 #define PVA_PROC_SCR_PROC 0x30800
/**
* @brief EVP SCR register address
*
* @details Register address for EVP (Exception Vector Processor) control.
* Corresponds to PVA_EVP_SCR_EVP_0 hardware register.
* Value: 0x40
*/
#define PVA_REG_EVP_SCR_ADDR 0x40 //PVA_EVP_SCR_EVP_0 #define PVA_REG_EVP_SCR_ADDR 0x40 //PVA_EVP_SCR_EVP_0
/**
* @brief CFG status control SCR address
*
* @details Register address for configuration status control.
* Corresponds to PVA_CFG_SCR_STATUS_CNTL_0 hardware register.
* Value: 0x258000
*/
#define PVA_CFG_SCR_STATUS_CNTL 0x258000 //PVA_CFG_SCR_STATUS_CNTL_0 #define PVA_CFG_SCR_STATUS_CNTL 0x258000 //PVA_CFG_SCR_STATUS_CNTL_0
/**
* @brief CFG privilege control SCR address
*
* @details Register address for configuration privilege control.
* Corresponds to PVA_CFG_SCR_PRIV_0 hardware register.
* Value: 0x258008
*/
#define PVA_CFG_SCR_PRIV 0x258008 //PVA_CFG_SCR_PRIV_0 #define PVA_CFG_SCR_PRIV 0x258008 //PVA_CFG_SCR_PRIV_0
/**
* @brief CFG CCQ control SCR address
*
* @details Register address for CCQ (Command and Control Queue) control.
* Corresponds to PVA_CFG_SCR_CCQ_CNTL_0 hardware register.
* Value: 0x258010
*/
#define PVA_CFG_SCR_CCQ_CNTL 0x258010 //PVA_CFG_SCR_CCQ_CNTL_0 #define PVA_CFG_SCR_CCQ_CNTL 0x258010 //PVA_CFG_SCR_CCQ_CNTL_0
/* HSP */ /**
* @brief HSP common control register address
*
* @details Base register address for HSP common control functionality.
* This controls overall HSP operation and configuration.
* Value: 0x160000
*/
#define PVA_REG_HSP_COMMON_ADDR 0x160000 #define PVA_REG_HSP_COMMON_ADDR 0x160000
/**
* @brief HSP interrupt enable 0 register address
*
* @details Register address for HSP interrupt enable control (channel 0).
* Controls which HSP interrupts are enabled.
* Value: 0x160100
*/
#define PVA_REG_HSP_INT_IE0_ADDR 0x160100 #define PVA_REG_HSP_INT_IE0_ADDR 0x160100
/**
* @brief HSP interrupt enable 1 register address
*
* @details Register address for HSP interrupt enable control (channel 1).
* Value: 0x160104
*/
#define PVA_REG_HSP_INT_IE1_ADDR 0x160104 #define PVA_REG_HSP_INT_IE1_ADDR 0x160104
/**
* @brief HSP interrupt enable 2 register address
*
* @details Register address for HSP interrupt enable control (channel 2).
* Value: 0x160108
*/
#define PVA_REG_HSP_INT_IE2_ADDR 0x160108 #define PVA_REG_HSP_INT_IE2_ADDR 0x160108
/**
* @brief HSP interrupt enable 3 register address
*
* @details Register address for HSP interrupt enable control (channel 3).
* Value: 0x16010c
*/
#define PVA_REG_HSP_INT_IE3_ADDR 0x16010c #define PVA_REG_HSP_INT_IE3_ADDR 0x16010c
/**
* @brief HSP interrupt enable 4 register address
*
* @details Register address for HSP interrupt enable control (channel 4).
* Value: 0x160110
*/
#define PVA_REG_HSP_INT_IE4_ADDR 0x160110 #define PVA_REG_HSP_INT_IE4_ADDR 0x160110
/**
* @brief HSP external interrupt register address
*
* @details Register address for HSP external interrupt status and control.
* Value: 0x160300
*/
#define PVA_REG_HSP_INT_EXTERNAL_ADDR 0x160300 #define PVA_REG_HSP_INT_EXTERNAL_ADDR 0x160300
/**
* @brief HSP internal interrupt register address
*
* @details Register address for HSP internal interrupt status and control.
* Value: 0x160304
*/
#define PVA_REG_HSP_INT_INTERNAL_ADDR 0x160304 #define PVA_REG_HSP_INT_INTERNAL_ADDR 0x160304
/**
* @brief HSP shared mailbox 0 base address
*
* @details Base register address for HSP shared mailbox 0.
* Used for inter-processor communication.
* Value: 0x170000
*/
#define PVA_REG_HSP_SM0_ADDR 0x170000 #define PVA_REG_HSP_SM0_ADDR 0x170000
/**
* @brief HSP shared mailbox 1 base address
*
* @details Base register address for HSP shared mailbox 1.
* Value: 0x178000
*/
#define PVA_REG_HSP_SM1_ADDR 0x178000 #define PVA_REG_HSP_SM1_ADDR 0x178000
/**
* @brief HSP shared mailbox 2 base address
*
* @details Base register address for HSP shared mailbox 2.
* Value: 0x180000
*/
#define PVA_REG_HSP_SM2_ADDR 0x180000 #define PVA_REG_HSP_SM2_ADDR 0x180000
/**
* @brief HSP shared mailbox 3 base address
*
* @details Base register address for HSP shared mailbox 3.
* Value: 0x188000
*/
#define PVA_REG_HSP_SM3_ADDR 0x188000 #define PVA_REG_HSP_SM3_ADDR 0x188000
/**
* @brief HSP shared mailbox 4 base address
*
* @details Base register address for HSP shared mailbox 4.
* Value: 0x190000
*/
#define PVA_REG_HSP_SM4_ADDR 0x190000 #define PVA_REG_HSP_SM4_ADDR 0x190000
/**
* @brief HSP shared mailbox 5 base address
*
* @details Base register address for HSP shared mailbox 5.
* Value: 0x198000
*/
#define PVA_REG_HSP_SM5_ADDR 0x198000 #define PVA_REG_HSP_SM5_ADDR 0x198000
/**
* @brief HSP shared mailbox 6 base address
*
* @details Base register address for HSP shared mailbox 6.
* Value: 0x1a0000
*/
#define PVA_REG_HSP_SM6_ADDR 0x1a0000 #define PVA_REG_HSP_SM6_ADDR 0x1a0000
/**
* @brief HSP shared mailbox 7 base address
*
* @details Base register address for HSP shared mailbox 7.
* Value: 0x1a8000
*/
#define PVA_REG_HSP_SM7_ADDR 0x1a8000 #define PVA_REG_HSP_SM7_ADDR 0x1a8000
/**
* @brief HSP shared semaphore 0 state register address
*
* @details Register address for HSP shared semaphore 0 state.
* Used for hardware synchronization between processors.
* Value: 0x1b0000
*/
#define PVA_REG_HSP_SS0_STATE_ADDR 0x1b0000 #define PVA_REG_HSP_SS0_STATE_ADDR 0x1b0000
/**
* @brief HSP shared semaphore 0 set register address
*
* @details Register address for setting HSP shared semaphore 0.
* Value: 0x1b0004
*/
#define PVA_REG_HSP_SS0_SET_ADDR 0x1b0004 #define PVA_REG_HSP_SS0_SET_ADDR 0x1b0004
/**
* @brief HSP shared semaphore 0 clear register address
*
* @details Register address for clearing HSP shared semaphore 0.
* Value: 0x1b0008
*/
#define PVA_REG_HSP_SS0_CLR_ADDR 0x1b0008 #define PVA_REG_HSP_SS0_CLR_ADDR 0x1b0008
/**
* @brief HSP shared semaphore 1 state register address
*
* @details Register address for HSP shared semaphore 1 state.
* Value: 0x1c0000
*/
#define PVA_REG_HSP_SS1_STATE_ADDR 0x1c0000 #define PVA_REG_HSP_SS1_STATE_ADDR 0x1c0000
/**
* @brief HSP shared semaphore 1 set register address
*
* @details Register address for setting HSP shared semaphore 1.
* Value: 0x1c0004
*/
#define PVA_REG_HSP_SS1_SET_ADDR 0x1c0004 #define PVA_REG_HSP_SS1_SET_ADDR 0x1c0004
/**
* @brief HSP shared semaphore 1 clear register address
*
* @details Register address for clearing HSP shared semaphore 1.
* Value: 0x1c0008
*/
#define PVA_REG_HSP_SS1_CLR_ADDR 0x1c0008 #define PVA_REG_HSP_SS1_CLR_ADDR 0x1c0008
/**
* @brief HSP shared semaphore 2 state register address
*
* @details Register address for HSP shared semaphore 2 state.
* Value: 0x1d0000
*/
#define PVA_REG_HSP_SS2_STATE_ADDR 0x1d0000 #define PVA_REG_HSP_SS2_STATE_ADDR 0x1d0000
/**
* @brief HSP shared semaphore 2 set register address
*
* @details Register address for setting HSP shared semaphore 2.
* Value: 0x1d0004
*/
#define PVA_REG_HSP_SS2_SET_ADDR 0x1d0004 #define PVA_REG_HSP_SS2_SET_ADDR 0x1d0004
/**
* @brief HSP shared semaphore 2 clear register address
*
* @details Register address for clearing HSP shared semaphore 2.
* Value: 0x1d0008
*/
#define PVA_REG_HSP_SS2_CLR_ADDR 0x1d0008 #define PVA_REG_HSP_SS2_CLR_ADDR 0x1d0008
/**
* @brief HSP shared semaphore 3 state register address
*
* @details Register address for HSP shared semaphore 3 state.
* Value: 0x1e0000
*/
#define PVA_REG_HSP_SS3_STATE_ADDR 0x1e0000 #define PVA_REG_HSP_SS3_STATE_ADDR 0x1e0000
/**
* @brief HSP shared semaphore 3 set register address
*
* @details Register address for setting HSP shared semaphore 3.
* Value: 0x1e0004
*/
#define PVA_REG_HSP_SS3_SET_ADDR 0x1e0004 #define PVA_REG_HSP_SS3_SET_ADDR 0x1e0004
/**
* @brief HSP shared semaphore 3 clear register address
*
* @details Register address for clearing HSP shared semaphore 3.
* Value: 0x1e0008
*/
#define PVA_REG_HSP_SS3_CLR_ADDR 0x1e0008 #define PVA_REG_HSP_SS3_CLR_ADDR 0x1e0008
/* SEC */ /**
* @brief SEC error slice 0 mission error enable register address
*
* @details Register address for enabling mission-critical error detection
* on SEC error slice 0. Mission errors are critical system errors.
* Value: 0x20030
*/
#define PVA_REG_SEC_ERRSLICE0_MISSIONERR_ENABLE_ADDR 0x20030 #define PVA_REG_SEC_ERRSLICE0_MISSIONERR_ENABLE_ADDR 0x20030
/**
* @brief SEC error slice 1 mission error enable register address
*
* @details Register address for enabling mission-critical error detection
* on SEC error slice 1.
* Value: 0x20060
*/
#define PVA_REG_SEC_ERRSLICE1_MISSIONERR_ENABLE_ADDR 0x20060 #define PVA_REG_SEC_ERRSLICE1_MISSIONERR_ENABLE_ADDR 0x20060
/**
* @brief SEC error slice 2 mission error enable register address
*
* @details Register address for enabling mission-critical error detection
* on SEC error slice 2.
* Value: 0x20090
*/
#define PVA_REG_SEC_ERRSLICE2_MISSIONERR_ENABLE_ADDR 0x20090 #define PVA_REG_SEC_ERRSLICE2_MISSIONERR_ENABLE_ADDR 0x20090
/**
* @brief SEC error slice 3 mission error enable register address
*
* @details Register address for enabling mission-critical error detection
* on SEC error slice 3.
* Value: 0x200c0
*/
#define PVA_REG_SEC_ERRSLICE3_MISSIONERR_ENABLE_ADDR 0x200c0 #define PVA_REG_SEC_ERRSLICE3_MISSIONERR_ENABLE_ADDR 0x200c0
/**
* @brief SEC error slice 0 latent error enable register address
*
* @details Register address for enabling latent error detection
* on SEC error slice 0. Latent errors are non-critical but monitored.
* Value: 0x20040
*/
#define PVA_REG_SEC_ERRSLICE0_LATENTERR_ENABLE_ADDR 0x20040 #define PVA_REG_SEC_ERRSLICE0_LATENTERR_ENABLE_ADDR 0x20040
/**
* @brief SEC error slice 1 latent error enable register address
*
* @details Register address for enabling latent error detection
* on SEC error slice 1.
* Value: 0x20070
*/
#define PVA_REG_SEC_ERRSLICE1_LATENTERR_ENABLE_ADDR 0x20070 #define PVA_REG_SEC_ERRSLICE1_LATENTERR_ENABLE_ADDR 0x20070
/**
* @brief SEC error slice 2 latent error enable register address
*
* @details Register address for enabling latent error detection
* on SEC error slice 2.
* Value: 0x200a0
*/
#define PVA_REG_SEC_ERRSLICE2_LATENTERR_ENABLE_ADDR 0x200a0 #define PVA_REG_SEC_ERRSLICE2_LATENTERR_ENABLE_ADDR 0x200a0
/**
* @brief SEC error slice 3 latent error enable register address
*
* @details Register address for enabling latent error detection
* on SEC error slice 3.
* Value: 0x200d0
*/
#define PVA_REG_SEC_ERRSLICE3_LATENTERR_ENABLE_ADDR 0x200d0 #define PVA_REG_SEC_ERRSLICE3_LATENTERR_ENABLE_ADDR 0x200d0
/* SEC_LIC_INTR_STATUS */ /**
* @brief SEC LIC INTR H1X field MSB bit position
*
* @details Most significant bit position for H1X interrupt field
* in SEC LIC interrupt status register.
* Value: 7
*/
#define PVA_REG_SEC_LIC_INTR_H1X_MSB 7 #define PVA_REG_SEC_LIC_INTR_H1X_MSB 7
/**
* @brief SEC LIC INTR H1X field LSB bit position
*
* @details Least significant bit position for H1X interrupt field
* in SEC LIC interrupt status register.
* Value: 5
*/
#define PVA_REG_SEC_LIC_INTR_H1X_LSB 5 #define PVA_REG_SEC_LIC_INTR_H1X_LSB 5
/**
* @brief SEC LIC INTR HSP field MSB bit position
*
* @details Most significant bit position for HSP interrupt field
* in SEC LIC interrupt status register.
* Value: 4
*/
#define PVA_REG_SEC_LIC_INTR_HSP_MSB 4 #define PVA_REG_SEC_LIC_INTR_HSP_MSB 4
/**
* @brief SEC LIC INTR HSP field LSB bit position
*
* @details Least significant bit position for HSP interrupt field
* in SEC LIC interrupt status register.
* Value: 1
*/
#define PVA_REG_SEC_LIC_INTR_HSP_LSB 1 #define PVA_REG_SEC_LIC_INTR_HSP_LSB 1
/**
* @brief SEC LIC INTR WDT field MSB bit position
*
* @details Most significant bit position for watchdog timer interrupt field
* in SEC LIC interrupt status register.
* Value: 0
*/
#define PVA_REG_SEC_LIC_INTR_WDT_MSB 0 #define PVA_REG_SEC_LIC_INTR_WDT_MSB 0
/**
* @brief SEC LIC INTR WDT field LSB bit position
*
* @details Least significant bit position for watchdog timer interrupt field
* in SEC LIC interrupt status register.
* Value: 0
*/
#define PVA_REG_SEC_LIC_INTR_WDT_LSB 0 #define PVA_REG_SEC_LIC_INTR_WDT_LSB 0
/* CCQ status 2 */ /**
* @brief CCQ status 2 interrupt overflow bit
*
* @details Bit mask for CCQ interrupt overflow condition in status register 2.
* Indicates CCQ overflow condition requiring attention.
*/
#define PVA_REG_CCQ_STATUS2_INTR_OVERFLOW_BIT PVA_BIT(28) #define PVA_REG_CCQ_STATUS2_INTR_OVERFLOW_BIT PVA_BIT(28)
/**
* @brief CCQ status 2 interrupt status 8 bit
*
* @details Bit mask for CCQ interrupt status 8 in status register 2.
*/
#define PVA_REG_CCQ_STATUS2_INTR_STATUS8_BIT PVA_BIT(24) #define PVA_REG_CCQ_STATUS2_INTR_STATUS8_BIT PVA_BIT(24)
/**
* @brief CCQ status 2 interrupt status 7 bit
*
* @details Bit mask for CCQ interrupt status 7 in status register 2.
*/
#define PVA_REG_CCQ_STATUS2_INTR_STATUS7_BIT PVA_BIT(20) #define PVA_REG_CCQ_STATUS2_INTR_STATUS7_BIT PVA_BIT(20)
/**
* @brief CCQ status 2 all interrupt bits combined
*
* @details Combined bit mask for all CCQ interrupt conditions in status register 2.
* Includes overflow, status8, and status7 interrupt bits.
*/
#define PVA_REG_CCQ_STATUS2_INTR_ALL_BITS \ #define PVA_REG_CCQ_STATUS2_INTR_ALL_BITS \
(PVA_REG_CCQ_STATUS2_INTR_OVERFLOW_BIT | \ (PVA_REG_CCQ_STATUS2_INTR_OVERFLOW_BIT | \
PVA_REG_CCQ_STATUS2_INTR_STATUS8_BIT | \ PVA_REG_CCQ_STATUS2_INTR_STATUS8_BIT | \
PVA_REG_CCQ_STATUS2_INTR_STATUS7_BIT) PVA_REG_CCQ_STATUS2_INTR_STATUS7_BIT)
/**
* @brief CCQ status 2 number of entries field MSB bit position
*
* @details Most significant bit position for number of entries field
* in CCQ status register 2.
* Value: 4
*/
#define PVA_REG_CCQ_STATUS2_NUM_ENTRIES_MSB 4 #define PVA_REG_CCQ_STATUS2_NUM_ENTRIES_MSB 4
/**
* @brief CCQ status 2 number of entries field LSB bit position
*
* @details Least significant bit position for number of entries field
* in CCQ status register 2.
* Value: 0
*/
#define PVA_REG_CCQ_STATUS2_NUM_ENTRIES_LSB 0 #define PVA_REG_CCQ_STATUS2_NUM_ENTRIES_LSB 0
/**
* @brief CCQ register specification structure
*
* @details This structure defines the register layout for a single CCQ
* (Command and Control Queue) interface including status registers and
* the command FIFO register. Each CCQ provides an independent command
* submission interface between software and firmware.
*/
struct pva_kmd_ccq_regspec { struct pva_kmd_ccq_regspec {
/**
* @brief Number of status registers for this CCQ
* Valid range: [1 .. PVA_CFG_CCQ_STATUS_COUNT]
*/
uint32_t status_count; uint32_t status_count;
/**
* @brief Array of CCQ status register addresses
*/
uint32_t status[PVA_CFG_CCQ_STATUS_COUNT]; uint32_t status[PVA_CFG_CCQ_STATUS_COUNT];
/**
* @brief CCQ FIFO register address for command submission
*/
uint32_t fifo; uint32_t fifo;
}; };
/**
* @brief Complete PVA register specification structure
*
* @details This structure contains the complete register specification for
* a PVA device including all subsystem registers, security configuration,
* Stream ID configuration, and CCQ interfaces. It provides a comprehensive
* mapping of all hardware registers needed for PVA operation.
*/
struct pva_kmd_regspec { struct pva_kmd_regspec {
/**
* @brief SEC LIC interrupt enable register address
*/
uint32_t sec_lic_intr_enable; uint32_t sec_lic_intr_enable;
/**
* @brief SEC LIC interrupt status register address
*/
uint32_t sec_lic_intr_status; uint32_t sec_lic_intr_status;
/**
* @brief CFG R5 user lower segment register address
*/
uint32_t cfg_r5user_lsegreg; uint32_t cfg_r5user_lsegreg;
/**
* @brief CFG R5 user upper segment register address
*/
uint32_t cfg_r5user_usegreg; uint32_t cfg_r5user_usegreg;
/**
* @brief CFG privilege AR1 lower segment register address
*/
uint32_t cfg_priv_ar1_lsegreg; uint32_t cfg_priv_ar1_lsegreg;
/**
* @brief CFG privilege AR1 upper segment register address
*/
uint32_t cfg_priv_ar1_usegreg; uint32_t cfg_priv_ar1_usegreg;
/**
* @brief CFG privilege AR2 lower segment register address
*/
uint32_t cfg_priv_ar2_lsegreg; uint32_t cfg_priv_ar2_lsegreg;
/**
* @brief CFG privilege AR2 upper segment register address
*/
uint32_t cfg_priv_ar2_usegreg; uint32_t cfg_priv_ar2_usegreg;
/**
* @brief CFG privilege AR1 start address register
*/
uint32_t cfg_priv_ar1_start; uint32_t cfg_priv_ar1_start;
/**
* @brief CFG privilege AR1 end address register
*/
uint32_t cfg_priv_ar1_end; uint32_t cfg_priv_ar1_end;
/**
* @brief CFG privilege AR2 start address register
*/
uint32_t cfg_priv_ar2_start; uint32_t cfg_priv_ar2_start;
/**
* @brief CFG privilege AR2 end address register
*/
uint32_t cfg_priv_ar2_end; uint32_t cfg_priv_ar2_end;
/**
* @brief CFG user Stream ID base register address
*/
uint32_t cfg_user_sid_base; uint32_t cfg_user_sid_base;
/**
* @brief CFG privilege Stream ID register address
*/
uint32_t cfg_priv_sid; uint32_t cfg_priv_sid;
/**
* @brief CFG VPS Stream ID register address
*/
uint32_t cfg_vps_sid; uint32_t cfg_vps_sid;
/**
* @brief CFG performance monitor register address
*/
uint32_t cfg_perf_mon; uint32_t cfg_perf_mon;
/**
* @brief CFG SCR privilege 0 register address
*/
uint32_t cfg_scr_priv_0; uint32_t cfg_scr_priv_0;
/**
* @brief Number of CCQ interfaces available
* Valid range: [1 .. PVA_MAX_NUM_CCQ]
*/
uint32_t ccq_count; uint32_t ccq_count;
/**
* @brief Array of VPU debug instruction register offsets
*/
uint32_t vpu_dbg_instr_reg_offset[PVA_NUM_ENGINES]; uint32_t vpu_dbg_instr_reg_offset[PVA_NUM_ENGINES];
/**
* @brief Array of CCQ register specifications
*/
struct pva_kmd_ccq_regspec ccq_regs[PVA_MAX_NUM_CCQ]; struct pva_kmd_ccq_regspec ccq_regs[PVA_MAX_NUM_CCQ];
}; };
/**
* @brief Enumeration of PVA register apertures
*
* @details This enumeration defines the different register apertures within
* the PVA hardware that can be accessed for device control and monitoring.
* Each aperture corresponds to a specific subsystem or functional block
* within the PVA cluster.
*/
enum pva_kmd_reg_aperture { enum pva_kmd_reg_aperture {
/** Main PVA_CLUSTER aperture */ /** @brief Main PVA cluster aperture containing all subsystems */
PVA_KMD_APERTURE_PVA_CLUSTER = 0, PVA_KMD_APERTURE_PVA_CLUSTER = 0,
/** Sub-clusters within PVA_CLUSTER */ /** @brief SEC (Security) subsystem aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_SEC, PVA_KMD_APERTURE_PVA_CLUSTER_SEC,
/** @brief PROC (Processor) subsystem aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_PROC, PVA_KMD_APERTURE_PVA_CLUSTER_PROC,
/** @brief PM (Power Management) subsystem aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_PM, PVA_KMD_APERTURE_PVA_CLUSTER_PM,
/** @brief HSP (Hardware Synchronization Primitives) aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_HSP, PVA_KMD_APERTURE_PVA_CLUSTER_HSP,
/** @brief EVP (Exception Vector Processor) aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_EVP, PVA_KMD_APERTURE_PVA_CLUSTER_EVP,
/** @brief CFG SID (Stream ID configuration) aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_CFG_SID, PVA_KMD_APERTURE_PVA_CLUSTER_CFG_SID,
/** @brief CFG CCQ (Command and Control Queue configuration) aperture */
PVA_KMD_APERTURE_PVA_CLUSTER_CFG_CCQ, PVA_KMD_APERTURE_PVA_CLUSTER_CFG_CCQ,
/** Debug aperture */ /** @brief VPU debug aperture for debugging support */
PVA_KMD_APERTURE_VPU_DEBUG, PVA_KMD_APERTURE_VPU_DEBUG,
/** @brief Total number of apertures */
PVA_KMD_APERTURE_COUNT, PVA_KMD_APERTURE_COUNT,
}; };

View File

@@ -51,17 +51,26 @@ pva_kmd_resource_table_init(struct pva_kmd_resource_table *res_table,
uint32_t max_dma_config_size = get_max_dma_config_size(pva); uint32_t max_dma_config_size = get_max_dma_config_size(pva);
enum pva_error err; enum pva_error err;
uint64_t size; uint64_t size;
uint32_t size_u32;
res_table->pva = pva; res_table->pva = pva;
res_table->n_entries = n_entries; res_table->n_entries = safe_addu32(n_entries, PVA_MAX_PRIV_RES_ID);
res_table->user_smmu_ctx_id = user_smmu_ctx_id; res_table->user_smmu_ctx_id = user_smmu_ctx_id;
pva_kmd_sema_init(&res_table->resource_semaphore, n_entries); pva_kmd_sema_init(&res_table->resource_semaphore, res_table->n_entries);
pva_kmd_mutex_init(&res_table->resource_table_lock); err = pva_kmd_mutex_init(&res_table->resource_table_lock);
if (err != PVA_SUCCESS) {
pva_kmd_log_err(
"pva_kmd_resource_table_init mutex_init failed");
return err;
}
size = (uint64_t)safe_mulu32( size = (uint64_t)safe_mulu32(
n_entries, (uint32_t)sizeof(struct pva_resource_entry)); res_table->n_entries,
size += (uint64_t)safe_mulu32( (uint32_t)sizeof(struct pva_resource_entry));
n_entries, (uint32_t)sizeof(struct pva_resource_aux_info)); size = safe_addu64(
size, (uint64_t)safe_mulu32(
res_table->n_entries,
(uint32_t)sizeof(struct pva_resource_aux_info)));
res_table->table_mem = pva_kmd_device_memory_alloc_map( res_table->table_mem = pva_kmd_device_memory_alloc_map(
size, pva, PVA_ACCESS_RW, PVA_R5_SMMU_CONTEXT_ID); size, pva, PVA_ACCESS_RW, PVA_R5_SMMU_CONTEXT_ID);
if (res_table->table_mem == NULL) { if (res_table->table_mem == NULL) {
@@ -69,9 +78,10 @@ pva_kmd_resource_table_init(struct pva_kmd_resource_table *res_table,
goto deinit_locks; goto deinit_locks;
} }
size = (uint64_t)safe_mulu32(sizeof(struct pva_kmd_resource_record), size_u32 = safe_mulu32((uint32_t)sizeof(struct pva_kmd_resource_record),
n_entries); res_table->n_entries);
res_table->records_mem = pva_kmd_zalloc(size); res_table->records_mem =
(struct pva_kmd_resource_record *)pva_kmd_zalloc(size_u32);
if (res_table->records_mem == NULL) { if (res_table->records_mem == NULL) {
err = PVA_NOMEM; err = PVA_NOMEM;
@@ -79,13 +89,26 @@ pva_kmd_resource_table_init(struct pva_kmd_resource_table *res_table,
} }
err = pva_kmd_block_allocator_init( err = pva_kmd_block_allocator_init(
&res_table->resource_record_allocator, res_table->records_mem, &res_table->priv_resource_record_allocator,
PVA_RESOURCE_ID_BASE, sizeof(struct pva_kmd_resource_record), res_table->records_mem, PVA_RESOURCE_ID_BASE,
n_entries); (uint32_t)sizeof(struct pva_kmd_resource_record),
PVA_MAX_PRIV_RES_ID);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto free_records_mem; goto free_records_mem;
} }
err = pva_kmd_block_allocator_init(
&res_table->resource_record_allocator,
(uint8_t *)res_table->records_mem +
safe_mulu32(PVA_MAX_PRIV_RES_ID,
(uint32_t)sizeof(
struct pva_kmd_resource_record)),
PVA_USER_RESOURCE_ID_BASE,
(uint32_t)sizeof(struct pva_kmd_resource_record), n_entries);
if (err != PVA_SUCCESS) {
goto free_priv_resource_record_allocator;
}
err = pva_kmd_devmem_pool_init(&res_table->dma_config_pool, pva, err = pva_kmd_devmem_pool_init(&res_table->dma_config_pool, pva,
PVA_R5_SMMU_CONTEXT_ID, PVA_R5_SMMU_CONTEXT_ID,
max_dma_config_size, max_dma_config_size,
@@ -98,6 +121,9 @@ pva_kmd_resource_table_init(struct pva_kmd_resource_table *res_table,
free_resource_record_allocator: free_resource_record_allocator:
pva_kmd_block_allocator_deinit(&res_table->resource_record_allocator); pva_kmd_block_allocator_deinit(&res_table->resource_record_allocator);
free_priv_resource_record_allocator:
pva_kmd_block_allocator_deinit(
&res_table->priv_resource_record_allocator);
free_records_mem: free_records_mem:
pva_kmd_free(res_table->records_mem); pva_kmd_free(res_table->records_mem);
free_table_mem: free_table_mem:
@@ -110,7 +136,7 @@ deinit_locks:
static struct pva_kmd_resource_record * static struct pva_kmd_resource_record *
pva_kmd_alloc_resource_id(struct pva_kmd_resource_table *resource_table, pva_kmd_alloc_resource_id(struct pva_kmd_resource_table *resource_table,
uint32_t *out_resource_id) uint32_t *out_resource_id, bool priv)
{ {
enum pva_error err; enum pva_error err;
struct pva_kmd_resource_record *rec = NULL; struct pva_kmd_resource_record *rec = NULL;
@@ -129,9 +155,21 @@ pva_kmd_alloc_resource_id(struct pva_kmd_resource_table *resource_table,
goto out; goto out;
} }
rec = (struct pva_kmd_resource_record *)pva_kmd_zalloc_block( if (priv) {
&resource_table->resource_record_allocator, out_resource_id); rec = (struct pva_kmd_resource_record *)pva_kmd_zalloc_block(
ASSERT(rec != NULL); &resource_table->priv_resource_record_allocator,
out_resource_id);
} else {
rec = (struct pva_kmd_resource_record *)pva_kmd_zalloc_block(
&resource_table->resource_record_allocator,
out_resource_id);
}
if (rec == NULL) {
pva_kmd_log_err(
"pva_kmd_alloc_resource_id: No available resource slots");
pva_kmd_sema_post(&resource_table->resource_semaphore);
goto out;
}
out: out:
return rec; return rec;
@@ -143,8 +181,15 @@ pva_kmd_free_resource_id(struct pva_kmd_resource_table *resource_table,
{ {
enum pva_error err; enum pva_error err;
err = pva_kmd_free_block(&resource_table->resource_record_allocator, if (resource_id <= PVA_MAX_PRIV_RES_ID) {
resource_id); err = pva_kmd_free_block(
&resource_table->priv_resource_record_allocator,
resource_id);
} else {
err = pva_kmd_free_block(
&resource_table->resource_record_allocator,
resource_id);
}
ASSERT(err == PVA_SUCCESS); ASSERT(err == PVA_SUCCESS);
pva_kmd_sema_post(&resource_table->resource_semaphore); pva_kmd_sema_post(&resource_table->resource_semaphore);
@@ -154,9 +199,8 @@ static void
pva_kmd_release_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_release_resource(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id, bool drop_dma_reference) uint32_t resource_id, bool drop_dma_reference)
{ {
struct pva_kmd_resource_record *rec = pva_kmd_get_block_unsafe( struct pva_kmd_resource_record *rec =
&resource_table->resource_record_allocator, resource_id); pva_kmd_peek_resource(resource_table, resource_id);
ASSERT(rec != NULL); ASSERT(rec != NULL);
switch (rec->type) { switch (rec->type) {
@@ -180,6 +224,7 @@ pva_kmd_release_resource(struct pva_kmd_resource_table *resource_table,
default: default:
FAULT("Unsupported resource type"); FAULT("Unsupported resource type");
/* NOTREACHED */
} }
pva_kmd_free_resource_id(resource_table, resource_id); pva_kmd_free_resource_id(resource_table, resource_id);
@@ -188,13 +233,14 @@ pva_kmd_release_resource(struct pva_kmd_resource_table *resource_table,
enum pva_error enum pva_error
pva_kmd_add_dram_buffer_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_add_dram_buffer_resource(struct pva_kmd_resource_table *resource_table,
struct pva_kmd_device_memory *dev_mem, struct pva_kmd_device_memory *dev_mem,
uint32_t *out_resource_id) uint32_t *out_resource_id, bool priv)
{ {
struct pva_kmd_resource_record *rec = struct pva_kmd_resource_record *rec = pva_kmd_alloc_resource_id(
pva_kmd_alloc_resource_id(resource_table, out_resource_id); resource_table, out_resource_id, priv);
if (rec == NULL) { if (rec == NULL) {
pva_kmd_log_err("No more resource id"); pva_kmd_log_err(
"pva_kmd_add_dram_buffer_resource No more resource id");
return PVA_NO_RESOURCE_ID; return PVA_NO_RESOURCE_ID;
} }
@@ -237,8 +283,13 @@ void pva_kmd_update_fw_resource_table(struct pva_kmd_resource_table *res_table)
for (id = PVA_RESOURCE_ID_BASE; id <= max_resource_id; id++) { for (id = PVA_RESOURCE_ID_BASE; id <= max_resource_id; id++) {
struct pva_resource_entry *entry = struct pva_resource_entry *entry =
get_fw_resource(res_table, id); get_fw_resource(res_table, id);
rec = pva_kmd_get_block_unsafe( if (id <= PVA_MAX_PRIV_RES_ID) {
&res_table->resource_record_allocator, id); rec = pva_kmd_get_block_unsafe(
&res_table->priv_resource_record_allocator, id);
} else {
rec = pva_kmd_get_block_unsafe(
&res_table->resource_record_allocator, id);
}
if (rec == NULL) { if (rec == NULL) {
continue; continue;
} }
@@ -251,13 +302,17 @@ void pva_kmd_update_fw_resource_table(struct pva_kmd_resource_table *res_table)
entry->size_lo = iova_lo(rec->dram.mem->size); entry->size_lo = iova_lo(rec->dram.mem->size);
entry->size_hi = iova_hi(rec->dram.mem->size); entry->size_hi = iova_hi(rec->dram.mem->size);
entry->smmu_context_id = rec->dram.mem->smmu_ctx_idx; entry->smmu_context_id = rec->dram.mem->smmu_ctx_idx;
entry->access_flags = rec->dram.mem->iova_access_flags; /* CERT INT31-C: iova_access_flags limited to PVA_ACCESS_* values (1,2,3),
* always fits in uint8_t, safe to cast */
entry->access_flags =
(uint8_t)rec->dram.mem->iova_access_flags;
break; break;
case PVA_RESOURCE_TYPE_INVALID: case PVA_RESOURCE_TYPE_INVALID:
break; break;
default: default:
pva_kmd_log_err("Unsupported resource type"); pva_kmd_log_err("Unsupported resource type");
pva_kmd_fault(); pva_kmd_fault();
/* NOTREACHED */
} }
} }
} }
@@ -266,9 +321,8 @@ struct pva_kmd_resource_record *
pva_kmd_use_resource_unsafe(struct pva_kmd_resource_table *res_table, pva_kmd_use_resource_unsafe(struct pva_kmd_resource_table *res_table,
uint32_t resource_id) uint32_t resource_id)
{ {
struct pva_kmd_resource_record *rec = pva_kmd_get_block_unsafe( struct pva_kmd_resource_record *rec =
&res_table->resource_record_allocator, resource_id); pva_kmd_peek_resource(res_table, resource_id);
if (rec == NULL) { if (rec == NULL) {
return NULL; return NULL;
} }
@@ -283,9 +337,8 @@ pva_kmd_use_resource(struct pva_kmd_resource_table *res_table,
{ {
struct pva_kmd_resource_record *rec; struct pva_kmd_resource_record *rec;
pva_kmd_mutex_lock(&res_table->resource_table_lock); pva_kmd_mutex_lock(&res_table->resource_table_lock);
rec = pva_kmd_get_block_unsafe(&res_table->resource_record_allocator,
resource_id);
rec = pva_kmd_peek_resource(res_table, resource_id);
if (rec == NULL) { if (rec == NULL) {
pva_kmd_mutex_unlock(&res_table->resource_table_lock); pva_kmd_mutex_unlock(&res_table->resource_table_lock);
return NULL; return NULL;
@@ -301,8 +354,15 @@ struct pva_kmd_resource_record *
pva_kmd_peek_resource(struct pva_kmd_resource_table *res_table, pva_kmd_peek_resource(struct pva_kmd_resource_table *res_table,
uint32_t resource_id) uint32_t resource_id)
{ {
struct pva_kmd_resource_record *rec = pva_kmd_get_block_unsafe( struct pva_kmd_resource_record *rec;
&res_table->resource_record_allocator, resource_id); if (resource_id <= PVA_MAX_PRIV_RES_ID) {
rec = pva_kmd_get_block_unsafe(
&res_table->priv_resource_record_allocator,
resource_id);
} else {
rec = pva_kmd_get_block_unsafe(
&res_table->resource_record_allocator, resource_id);
}
return rec; return rec;
} }
@@ -318,10 +378,8 @@ void pva_kmd_drop_resource(struct pva_kmd_resource_table *resource_table,
void pva_kmd_drop_resource_unsafe(struct pva_kmd_resource_table *resource_table, void pva_kmd_drop_resource_unsafe(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id) uint32_t resource_id)
{ {
struct pva_kmd_resource_record *rec; struct pva_kmd_resource_record *rec =
pva_kmd_peek_resource(resource_table, resource_id);
rec = pva_kmd_get_block_unsafe(
&resource_table->resource_record_allocator, resource_id);
if (rec == NULL) { if (rec == NULL) {
pva_kmd_log_err_u64("Unexpected resource ID drop", resource_id); pva_kmd_log_err_u64("Unexpected resource ID drop", resource_id);
@@ -329,7 +387,7 @@ void pva_kmd_drop_resource_unsafe(struct pva_kmd_resource_table *resource_table,
} }
rec->ref_count = safe_subu32(rec->ref_count, 1U); rec->ref_count = safe_subu32(rec->ref_count, 1U);
if (rec->ref_count == 0) { if (rec->ref_count == 0U) {
pva_kmd_release_resource(resource_table, resource_id, true); pva_kmd_release_resource(resource_table, resource_id, true);
} }
} }
@@ -337,15 +395,17 @@ void pva_kmd_drop_resource_unsafe(struct pva_kmd_resource_table *resource_table,
enum pva_error enum pva_error
pva_kmd_add_vpu_bin_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_add_vpu_bin_resource(struct pva_kmd_resource_table *resource_table,
const void *executable, uint32_t executable_size, const void *executable, uint32_t executable_size,
uint32_t *out_resource_id) uint32_t *out_resource_id, bool priv)
{ {
uint32_t res_id; uint32_t res_id;
struct pva_kmd_resource_record *rec = struct pva_kmd_resource_record *rec =
pva_kmd_alloc_resource_id(resource_table, &res_id); pva_kmd_alloc_resource_id(resource_table, &res_id, priv);
enum pva_error err; enum pva_error err;
struct pva_kmd_vpu_bin_resource *vpu_bin; struct pva_kmd_vpu_bin_resource *vpu_bin;
if (rec == NULL) { if (rec == NULL) {
pva_kmd_log_err(
"pva_kmd_add_vpu_bin_resource No more resource id");
err = PVA_NO_RESOURCE_ID; err = PVA_NO_RESOURCE_ID;
goto err_out; goto err_out;
} }
@@ -395,7 +455,9 @@ pva_kmd_make_resource_entry(struct pva_kmd_resource_table *resource_table,
entry->size_lo = iova_lo(rec->dram.mem->size); entry->size_lo = iova_lo(rec->dram.mem->size);
entry->size_hi = iova_hi(rec->dram.mem->size); entry->size_hi = iova_hi(rec->dram.mem->size);
entry->smmu_context_id = rec->dram.mem->smmu_ctx_idx; entry->smmu_context_id = rec->dram.mem->smmu_ctx_idx;
entry->access_flags = rec->dram.mem->iova_access_flags; /* CERT INT31-C: iova_access_flags limited to PVA_ACCESS_* values (1,2,3),
* always fits in uint8_t, safe to cast */
entry->access_flags = (uint8_t)rec->dram.mem->iova_access_flags;
break; break;
case PVA_RESOURCE_TYPE_EXEC_BIN: case PVA_RESOURCE_TYPE_EXEC_BIN:
entry->type = rec->type; entry->type = rec->type;
@@ -419,6 +481,7 @@ pva_kmd_make_resource_entry(struct pva_kmd_resource_table *resource_table,
default: default:
pva_kmd_log_err("Unsupported resource type"); pva_kmd_log_err("Unsupported resource type");
pva_kmd_fault(); pva_kmd_fault();
/* NOTREACHED */
} }
pva_kmd_drop_resource(resource_table, resource_id); pva_kmd_drop_resource(resource_table, resource_id);
@@ -428,7 +491,7 @@ pva_kmd_make_resource_entry(struct pva_kmd_resource_table *resource_table,
enum pva_error pva_kmd_add_dma_config_resource( enum pva_error pva_kmd_add_dma_config_resource(
struct pva_kmd_resource_table *resource_table, struct pva_kmd_resource_table *resource_table,
const struct pva_ops_dma_config_register *dma_cfg_hdr, const struct pva_ops_dma_config_register *dma_cfg_hdr,
uint32_t dma_config_size, uint32_t *out_resource_id) uint32_t dma_config_size, uint32_t *out_resource_id, bool priv)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
uint32_t fw_fetch_size; uint32_t fw_fetch_size;
@@ -437,6 +500,7 @@ enum pva_error pva_kmd_add_dma_config_resource(
struct pva_kmd_resource_record *rec; struct pva_kmd_resource_record *rec;
uint32_t res_id; uint32_t res_id;
struct pva_kmd_devmem_element dma_cfg_mem = { 0 }; struct pva_kmd_devmem_element dma_cfg_mem = { 0 };
bool skip_validation = false;
err = pva_kmd_devmem_pool_zalloc(&resource_table->dma_config_pool, err = pva_kmd_devmem_pool_zalloc(&resource_table->dma_config_pool,
&dma_cfg_mem); &dma_cfg_mem);
@@ -445,9 +509,7 @@ enum pva_error pva_kmd_add_dma_config_resource(
} }
fw_dma_cfg = pva_kmd_get_devmem_va(&dma_cfg_mem); fw_dma_cfg = pva_kmd_get_devmem_va(&dma_cfg_mem);
// Must satisfy alignment requirement for converting to struct ASSERT(((uintptr_t)(void *)fw_dma_cfg) % sizeof(uint64_t) == 0UL);
// pva_dma_config_resource*
ASSERT(((uintptr_t)fw_dma_cfg) % sizeof(uint64_t) == 0);
dma_aux = pva_kmd_zalloc(sizeof(struct pva_kmd_dma_resource_aux)); dma_aux = pva_kmd_zalloc(sizeof(struct pva_kmd_dma_resource_aux));
if (dma_aux == NULL) { if (dma_aux == NULL) {
@@ -456,16 +518,17 @@ enum pva_error pva_kmd_add_dma_config_resource(
} }
dma_aux->res_table = resource_table; dma_aux->res_table = resource_table;
skip_validation = (priv || resource_table->pva->test_mode);
pva_kmd_mutex_lock(&resource_table->resource_table_lock); pva_kmd_mutex_lock(&resource_table->resource_table_lock);
err = pva_kmd_load_dma_config(resource_table, dma_cfg_hdr, err = pva_kmd_load_dma_config(resource_table, dma_cfg_hdr,
dma_config_size, dma_aux, fw_dma_cfg, dma_config_size, dma_aux, fw_dma_cfg,
&fw_fetch_size); &fw_fetch_size, skip_validation);
pva_kmd_mutex_unlock(&resource_table->resource_table_lock); pva_kmd_mutex_unlock(&resource_table->resource_table_lock);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto free_dma_aux; goto free_dma_aux;
} }
rec = pva_kmd_alloc_resource_id(resource_table, &res_id); rec = pva_kmd_alloc_resource_id(resource_table, &res_id, priv);
if (rec == NULL) { if (rec == NULL) {
err = PVA_NO_RESOURCE_ID; err = PVA_NO_RESOURCE_ID;
goto unload_dma; goto unload_dma;
@@ -521,8 +584,10 @@ pva_kmd_release_all_resources(struct pva_kmd_resource_table *res_table)
void pva_kmd_resource_table_deinit(struct pva_kmd_resource_table *res_table) void pva_kmd_resource_table_deinit(struct pva_kmd_resource_table *res_table)
{ {
pva_kmd_release_all_resources(res_table); (void)pva_kmd_release_all_resources(res_table);
pva_kmd_block_allocator_deinit(&res_table->resource_record_allocator); pva_kmd_block_allocator_deinit(&res_table->resource_record_allocator);
pva_kmd_block_allocator_deinit(
&res_table->priv_resource_record_allocator);
pva_kmd_free(res_table->records_mem); pva_kmd_free(res_table->records_mem);
pva_kmd_devmem_pool_deinit(&res_table->dma_config_pool); pva_kmd_devmem_pool_deinit(&res_table->dma_config_pool);
pva_kmd_mutex_deinit(&res_table->resource_table_lock); pva_kmd_mutex_deinit(&res_table->resource_table_lock);
@@ -535,7 +600,10 @@ void pva_kmd_resource_table_lock(struct pva_kmd_device *pva,
{ {
struct pva_kmd_context *ctx = pva_kmd_get_context(pva, res_table_id); struct pva_kmd_context *ctx = pva_kmd_get_context(pva, res_table_id);
pva_kmd_mutex_lock(&ctx->ctx_resource_table.resource_table_lock); if (ctx != NULL) {
pva_kmd_mutex_lock(
&ctx->ctx_resource_table.resource_table_lock);
}
} }
void pva_kmd_resource_table_unlock(struct pva_kmd_device *pva, void pva_kmd_resource_table_unlock(struct pva_kmd_device *pva,
@@ -543,5 +611,8 @@ void pva_kmd_resource_table_unlock(struct pva_kmd_device *pva,
{ {
struct pva_kmd_context *ctx = pva_kmd_get_context(pva, res_table_id); struct pva_kmd_context *ctx = pva_kmd_get_context(pva, res_table_id);
pva_kmd_mutex_unlock(&ctx->ctx_resource_table.resource_table_lock); if (ctx != NULL) {
pva_kmd_mutex_unlock(
&ctx->ctx_resource_table.resource_table_lock);
}
} }

View File

@@ -16,128 +16,575 @@
#include "pva_kmd_thread_sema.h" #include "pva_kmd_thread_sema.h"
#include "pva_kmd_devmem_pool.h" #include "pva_kmd_devmem_pool.h"
#define PVA_USER_RESOURCE_ID_BASE (PVA_MAX_PRIV_RES_ID + 1U)
struct pva_kmd_device; struct pva_kmd_device;
/**
* @brief Resource structure for DRAM memory buffers
*
* @details This structure contains information about a DRAM memory buffer
* resource that has been registered with the resource table. It provides
* access to the device memory allocation that backs the DRAM resource.
*/
struct pva_kmd_dram_resource { struct pva_kmd_dram_resource {
/**
* @brief Pointer to device memory allocation for this DRAM resource
*/
struct pva_kmd_device_memory *mem; struct pva_kmd_device_memory *mem;
}; };
/**
* @brief Resource structure for VPU binary executables
*
* @details This structure contains information about a VPU executable binary
* that has been loaded and registered with the resource table. It includes
* both metadata and code sections, along with symbol table information for
* proper executable management and debugging.
*/
struct pva_kmd_vpu_bin_resource { struct pva_kmd_vpu_bin_resource {
/**
* @brief Device memory allocation for executable metadata
*/
struct pva_kmd_device_memory *metainfo_mem; struct pva_kmd_device_memory *metainfo_mem;
/**
* @brief Device memory allocation for executable code sections
*/
struct pva_kmd_device_memory *sections_mem; struct pva_kmd_device_memory *sections_mem;
/**
* @brief Symbol table for debugging and runtime symbol resolution
*/
struct pva_kmd_exec_symbol_table symbol_table; struct pva_kmd_exec_symbol_table symbol_table;
}; };
/**
* @brief Resource structure for DMA configuration objects
*
* @details This structure contains information about a DMA configuration
* that has been validated and registered with the resource table. It includes
* the device memory element, auxiliary memory, and addressing information
* needed for DMA operations.
*/
struct pva_kmd_dma_config_resource { struct pva_kmd_dma_config_resource {
/**
* @brief Device memory element for DMA configuration storage
*/
struct pva_kmd_devmem_element devmem; struct pva_kmd_devmem_element devmem;
/**
* @brief Auxiliary memory for additional DMA configuration data
*/
struct pva_kmd_dma_resource_aux *aux_mem; struct pva_kmd_dma_resource_aux *aux_mem;
/**
* @brief Size of the DMA configuration in bytes
* Valid range: [1 .. UINT64_MAX]
*/
uint64_t size; uint64_t size;
/**
* @brief IOVA address for hardware access to DMA configuration
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t iova_addr; uint64_t iova_addr;
}; };
/**
* @brief Resource record for tracking registered resources
*
* @details This structure represents a single entry in the resource table,
* containing type information, reference counting, and type-specific data
* for the resource. Resources can be DRAM buffers, VPU executables, or
* DMA configurations, each with their own specific data requirements.
*/
struct pva_kmd_resource_record { struct pva_kmd_resource_record {
/** /**
* Possible types: * @brief Type of resource stored in this record
* PVA_RESOURCE_TYPE_DRAM *
* PVA_RESOURCE_TYPE_EXEC_BIN * @details Possible types:
* PVA_RESOURCE_TYPE_DMA_CONFIG * - PVA_RESOURCE_TYPE_DRAM
*/ * - PVA_RESOURCE_TYPE_EXEC_BIN
* - PVA_RESOURCE_TYPE_DMA_CONFIG
* Valid values: @ref pva_resource_type enumeration values
*/
uint8_t type; uint8_t type;
/**
* @brief Reference count for tracking resource usage
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t ref_count; uint32_t ref_count;
/**
* @brief Union containing type-specific resource data
*/
union { union {
/** @brief DRAM resource data */
struct pva_kmd_dram_resource dram; struct pva_kmd_dram_resource dram;
/** @brief VPU binary resource data */
struct pva_kmd_vpu_bin_resource vpu_bin; struct pva_kmd_vpu_bin_resource vpu_bin;
/** @brief DMA configuration resource data */
struct pva_kmd_dma_config_resource dma_config; struct pva_kmd_dma_config_resource dma_config;
}; };
}; };
/** /**
* @brief Resource table for managing hardware resources and firmware communication
* *
* @details This structure manages the resource table used for communication
* between KMD and firmware. It provides secure resource management through
* indirection, where user space applications use opaque resource IDs instead
* of direct hardware addresses. The table supports different resource types
* including DRAM buffers, VPU executables, and DMA configurations.
*/ */
struct pva_kmd_resource_table { struct pva_kmd_resource_table {
/** @brief User smmu context ID. /**
* @brief User SMMU context ID for memory protection
* *
* - DRAM memory, VPU data/text sections will be mapped to this space. * @details - DRAM memory, VPU data/text sections will be mapped to this space.
* - VPU metadata, DMA configurations will always be mapped to R5 SMMU * - VPU metadata, DMA configurations will always be mapped to R5 SMMU context.
* context. */ * Valid range: [0 .. PVA_MAX_NUM_SMMU_CONTEXTS-1]
*/
uint8_t user_smmu_ctx_id; uint8_t user_smmu_ctx_id;
/**
* @brief Number of allocated entries in the resource table
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t n_entries; uint32_t n_entries;
/** Maximum resource ID we have seen so far */
/**
* @brief Maximum resource ID allocated so far
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t curr_max_resource_id; uint32_t curr_max_resource_id;
/** Semaphore to keep track of resources in use*/ /**
* @brief Semaphore to track resources currently in use
*
* @details Semaphore to keep track of resources in use
*/
pva_kmd_sema_t resource_semaphore; pva_kmd_sema_t resource_semaphore;
/** Memory for resource table entries, in R5 segment */ /**
* @brief Device memory for resource table entries in R5 segment
*
* @details Memory for resource table entries, in R5 segment
*/
struct pva_kmd_device_memory *table_mem; struct pva_kmd_device_memory *table_mem;
/** Pool for FW DMA configurations */ /**
* @brief Memory pool for firmware DMA configurations
*
* @details Pool for FW DMA configurations
*/
struct pva_kmd_devmem_pool dma_config_pool; struct pva_kmd_devmem_pool dma_config_pool;
/** Memory for resource records */ /**
* @brief Memory allocation for resource record storage
*
* @details Memory for resource records
*/
void *records_mem; void *records_mem;
/**
* @brief Block allocator for managing resource record allocation
*/
struct pva_kmd_block_allocator resource_record_allocator; struct pva_kmd_block_allocator resource_record_allocator;
/**
* @brief Block allocator for managing privileged resource record allocation
*/
struct pva_kmd_block_allocator priv_resource_record_allocator;
/**
* @brief Pointer to parent PVA device
*/
struct pva_kmd_device *pva; struct pva_kmd_device *pva;
/**
* @brief Mutex protecting resource table operations
*/
pva_kmd_mutex_t resource_table_lock; pva_kmd_mutex_t resource_table_lock;
}; };
/**
* @brief Initialize a resource table for KMD-firmware communication
*
* @details This function performs the following operations:
* - Allocates device memory for the resource table entries
* - Initializes the resource record allocator for managing entries
* - Sets up the DMA configuration pool for firmware DMA operations
* - Configures SMMU context for user memory protection
* - Initializes synchronization primitives for thread-safe access
* - Prepares the table for resource registration and management
* - Establishes communication interface with firmware
*
* The initialized resource table provides secure resource management by
* using opaque resource IDs instead of direct hardware addresses. After
* initialization, resources can be registered using the various add
* functions and accessed through resource IDs.
*
* @param[out] res_table Pointer to @ref pva_kmd_resource_table structure to initialize
* Valid value: non-null
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] user_smmu_ctx_id SMMU context ID for user memory protection
* Valid range: [0 .. PVA_MAX_NUM_SMMU_CONTEXTS-1]
* @param[in] n_entries Maximum number of resource entries supported
* Valid range: [1 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Resource table initialized successfully
* @retval PVA_NOMEM Failed to allocate table memory
* @retval PVA_INTERNAL Failed to initialize DMA configuration pool
* @retval PVA_ENOSPC Failed to initialize resource record allocator
*/
enum pva_error enum pva_error
pva_kmd_resource_table_init(struct pva_kmd_resource_table *res_table, pva_kmd_resource_table_init(struct pva_kmd_resource_table *res_table,
struct pva_kmd_device *pva, struct pva_kmd_device *pva,
uint8_t user_smmu_ctx_id, uint32_t n_entries); uint8_t user_smmu_ctx_id, uint32_t n_entries);
/**
* @brief Deinitialize a resource table and free associated resources
*
* @details This function performs the following operations:
* - Ensures all resources are properly released and unreferenced
* - Deinitializes the DMA configuration pool
* - Cleans up the resource record allocator
* - Frees allocated device memory for table entries
* - Destroys synchronization primitives
* - Invalidates the resource table for future use
*
* All resources must be properly dropped before calling this function.
* After deinitialization, the resource table becomes invalid and cannot
* be used for further operations.
*
* @param[in, out] res_table Pointer to @ref pva_kmd_resource_table structure to deinitialize
* Valid value: non-null, must be initialized
*/
void pva_kmd_resource_table_deinit(struct pva_kmd_resource_table *res_table); void pva_kmd_resource_table_deinit(struct pva_kmd_resource_table *res_table);
/** KMD only writes to FW resource table during init time. Once the address of /**
* @brief Update firmware resource table with current resource information
*
* @details This function performs the following operations:
* - Synchronizes the firmware resource table with KMD resource state
* - Updates resource entries that firmware needs for operation
* - Ensures firmware has current IOVA mappings and resource metadata
* - Maintains consistency between KMD and firmware resource views
*
* KMD only writes to FW resource table during init time. Once the address of
* the resource table is sent to FW, all updates should be done through commands. * the resource table is sent to FW, all updates should be done through commands.
* This function is typically called during initialization or after significant
* resource table changes that require firmware synchronization.
*
* @param[in, out] res_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
*/ */
void pva_kmd_update_fw_resource_table(struct pva_kmd_resource_table *res_table); void pva_kmd_update_fw_resource_table(struct pva_kmd_resource_table *res_table);
/**
* @brief Add a DRAM buffer resource to the resource table
*
* @details This function performs the following operations:
* - Validates the provided device memory allocation
* - Allocates a new resource record for the DRAM buffer
* - Maps the memory to the appropriate SMMU context
* - Assigns a unique resource ID for the buffer
* - Initializes reference counting for the resource
* - Updates the resource table with the new entry
* - Returns the assigned resource ID to the caller
*
* The DRAM buffer becomes accessible to firmware through the returned
* resource ID. The memory must remain valid for the lifetime of the
* resource registration.
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] memory Pointer to device memory allocation
* Valid value: non-null, must be allocated
* @param[out] out_resource_id Pointer to store the assigned resource ID
* Valid value: non-null
*
* @retval PVA_SUCCESS Resource added successfully
* @retval PVA_NOMEM Failed to allocate resource record
* @retval PVA_NO_RESOURCE_ID No available resource IDs
* @retval PVA_INVAL Failed to map memory to SMMU context
*/
enum pva_error enum pva_error
pva_kmd_add_dram_buffer_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_add_dram_buffer_resource(struct pva_kmd_resource_table *resource_table,
struct pva_kmd_device_memory *memory, struct pva_kmd_device_memory *memory,
uint32_t *out_resource_id); uint32_t *out_resource_id, bool priv);
/**
* @brief Add a VPU binary executable resource to the resource table
*
* @details This function performs the following operations:
* - Validates and parses the provided executable binary
* - Allocates device memory for executable metadata and code sections
* - Loads the executable into appropriate memory segments
* - Maps executable sections to SMMU contexts with proper permissions
* - Extracts and stores symbol table information for debugging
* - Assigns a unique resource ID for the executable
* - Updates the resource table with the new executable entry
*
* The VPU executable becomes available for execution through the returned
* resource ID. The executable data must remain valid for the lifetime of
* the resource registration.
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] executable Pointer to executable binary data
* Valid value: non-null
* @param[in] executable_size Size of executable binary in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[out] out_resource_id Pointer to store the assigned resource ID
* Valid value: non-null
*
* @retval PVA_SUCCESS Executable resource added successfully
* @retval PVA_INVALID_SYMBOL Executable format is invalid or corrupted
* @retval PVA_NOMEM Failed to allocate memory for executable
* @retval PVA_NO_RESOURCE_ID No available resource IDs
* @retval PVA_INVAL Failed to map executable to SMMU context
*/
enum pva_error enum pva_error
pva_kmd_add_vpu_bin_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_add_vpu_bin_resource(struct pva_kmd_resource_table *resource_table,
const void *executable, uint32_t executable_size, const void *executable, uint32_t executable_size,
uint32_t *out_resource_id); uint32_t *out_resource_id, bool priv);
/**
* @brief Add a DMA configuration resource to the resource table
*
* @details This function performs the following operations:
* - Validates the provided DMA configuration parameters
* - Allocates device memory from the DMA configuration pool
* - Stores the DMA configuration in firmware-accessible memory
* - Maps the configuration to appropriate SMMU contexts
* - Validates DMA access patterns and constraints
* - Assigns a unique resource ID for the DMA configuration
* - Updates the resource table with the new configuration entry
*
* The DMA configuration becomes available for DMA operations through the
* returned resource ID. The configuration includes transfer parameters,
* access patterns, and memory slot definitions.
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] dma_cfg_hdr Pointer to DMA configuration header
* Valid value: non-null
* @param[in] dma_config_size Size of DMA configuration in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[out] out_resource_id Pointer to store the assigned resource ID
* Valid value: non-null
*
* @retval PVA_SUCCESS DMA configuration added successfully
* @retval PVA_INVALID_DMA_CONFIG DMA configuration is invalid
* @retval PVA_ENOSPC DMA configuration pool is full
* @retval PVA_NO_RESOURCE_ID No available resource IDs
* @retval PVA_INVAL Failed to map configuration to SMMU context
*/
enum pva_error pva_kmd_add_dma_config_resource( enum pva_error pva_kmd_add_dma_config_resource(
struct pva_kmd_resource_table *resource_table, struct pva_kmd_resource_table *resource_table,
const struct pva_ops_dma_config_register *dma_cfg_hdr, const struct pva_ops_dma_config_register *dma_cfg_hdr,
uint32_t dma_config_size, uint32_t *out_resource_id); uint32_t dma_config_size, uint32_t *out_resource_id, bool priv);
/** /**
* Increment reference count of the resources * @brief Increment reference count and get resource record (unsafe version)
* *
* TODO: make use and drop thread safe. * @details This function performs the following operations:
* */ * - Validates the resource ID against the resource table bounds
* - Retrieves the resource record for the specified ID
* - Increments the reference count for usage tracking
* - Returns pointer to the resource record for access
*
* This function is not thread-safe and requires external synchronization.
* The caller must ensure proper locking around calls to this function and
* the corresponding @ref pva_kmd_drop_resource_unsafe().
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] resource_id Resource ID to access
* Valid range: [0 .. curr_max_resource_id]
*
* @retval non-null Pointer to @ref pva_kmd_resource_record if resource exists
* @retval NULL Invalid resource ID or resource not found
*
* @note TODO: make use and drop thread safe.
*/
struct pva_kmd_resource_record * struct pva_kmd_resource_record *
pva_kmd_use_resource_unsafe(struct pva_kmd_resource_table *resource_table, pva_kmd_use_resource_unsafe(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id); uint32_t resource_id);
/**
* @brief Increment reference count and get resource record (thread-safe version)
*
* @details This function performs the following operations:
* - Acquires the resource table lock for thread-safe operation
* - Validates the resource ID against the resource table bounds
* - Retrieves the resource record for the specified ID
* - Increments the reference count for usage tracking
* - Releases the resource table lock
* - Returns pointer to the resource record for access
*
* This function is thread-safe and can be called concurrently from multiple
* threads. The returned resource record remains valid until the corresponding
* @ref pva_kmd_drop_resource() is called.
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] resource_id Resource ID to access
* Valid range: [0 .. curr_max_resource_id]
*
* @retval non-null Pointer to @ref pva_kmd_resource_record if resource exists
* @retval NULL Invalid resource ID or resource not found
*/
struct pva_kmd_resource_record * struct pva_kmd_resource_record *
pva_kmd_use_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_use_resource(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id); uint32_t resource_id);
/**
* @brief Get resource record without incrementing reference count
*
* @details This function performs the following operations:
* - Acquires the resource table lock for thread-safe operation
* - Validates the resource ID against the resource table bounds
* - Retrieves the resource record for the specified ID
* - Returns pointer to the resource record without changing reference count
* - Releases the resource table lock
*
* This function allows inspection of resource records without affecting
* their reference counting. The returned pointer is only valid while
* the caller maintains appropriate synchronization with the resource table.
*
* @param[in] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] resource_id Resource ID to inspect
* Valid range: [0 .. curr_max_resource_id]
*
* @retval non-null Pointer to @ref pva_kmd_resource_record if resource exists
* @retval NULL Invalid resource ID or resource not found
*/
struct pva_kmd_resource_record * struct pva_kmd_resource_record *
pva_kmd_peek_resource(struct pva_kmd_resource_table *resource_table, pva_kmd_peek_resource(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id); uint32_t resource_id);
/**
* @brief Decrement reference count for a resource (thread-safe version)
*
* @details This function performs the following operations:
* - Acquires the resource table lock for thread-safe operation
* - Validates the resource ID against the resource table bounds
* - Decrements the reference count for the specified resource
* - Checks if the reference count reaches zero for cleanup
* - Frees the resource record if no longer referenced
* - Releases the resource table lock
*
* This function must be called for every successful @ref pva_kmd_use_resource()
* to maintain proper reference counting. When the reference count reaches
* zero, the resource is automatically cleaned up and its ID becomes available
* for reuse.
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] resource_id Resource ID to release
* Valid range: [0 .. curr_max_resource_id]
*/
void pva_kmd_drop_resource(struct pva_kmd_resource_table *resource_table, void pva_kmd_drop_resource(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id); uint32_t resource_id);
/**
* @brief Decrement reference count for a resource (unsafe version)
*
* @details This function performs the following operations:
* - Validates the resource ID against the resource table bounds
* - Decrements the reference count for the specified resource
* - Checks if the reference count reaches zero for cleanup
* - Frees the resource record if no longer referenced
*
* This function is not thread-safe and requires external synchronization.
* The caller must ensure proper locking around calls to this function and
* the corresponding @ref pva_kmd_use_resource_unsafe().
*
* @param[in, out] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] resource_id Resource ID to release
* Valid range: [0 .. curr_max_resource_id]
*/
void pva_kmd_drop_resource_unsafe(struct pva_kmd_resource_table *resource_table, void pva_kmd_drop_resource_unsafe(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id); uint32_t resource_id);
/**
* @brief Create a firmware-compatible resource entry from a resource record
*
* @details This function performs the following operations:
* - Retrieves the resource record for the specified resource ID
* - Extracts type-specific information from the resource record
* - Converts the resource data to firmware-compatible format
* - Populates the provided resource entry structure
* - Includes IOVA addresses and metadata needed by firmware
* - Validates resource consistency before entry creation
*
* The created resource entry can be used by firmware to access the
* resource through hardware operations. The entry contains all necessary
* information for firmware to perform DMA operations or executable loading.
*
* @param[in] resource_table Pointer to @ref pva_kmd_resource_table structure
* Valid value: non-null, must be initialized
* @param[in] resource_id Resource ID to create entry for
* Valid range: [0 .. curr_max_resource_id]
* @param[out] entry Pointer to @ref pva_resource_entry to populate
* Valid value: non-null
*
* @retval PVA_SUCCESS Resource entry created successfully
* @retval PVA_INVAL Invalid resource ID or entry pointer
* @retval PVA_INVALID_RESOURCE Resource in invalid state for entry creation
*/
enum pva_error enum pva_error
pva_kmd_make_resource_entry(struct pva_kmd_resource_table *resource_table, pva_kmd_make_resource_entry(struct pva_kmd_resource_table *resource_table,
uint32_t resource_id, uint32_t resource_id,
struct pva_resource_entry *entry); struct pva_resource_entry *entry);
/**
* @brief Acquire lock for a specific resource table
*
* @details This function performs the following operations:
* - Identifies the resource table associated with the specified ID
* - Acquires the mutex lock for thread-safe resource table access
* - Provides exclusive access to resource table operations
* - Ensures atomic operations on resource table state
*
* This function should be used when multiple resource table operations
* need to be performed atomically. The lock must be released using
* @ref pva_kmd_resource_table_unlock() after the operations complete.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] res_table_id Resource table identifier to lock
* Valid range: [0 .. PVA_KMD_MAX_NUM_KMD_RESOURCES-1]
*/
void pva_kmd_resource_table_lock(struct pva_kmd_device *pva, void pva_kmd_resource_table_lock(struct pva_kmd_device *pva,
uint8_t res_table_id); uint8_t res_table_id);
/**
* @brief Release lock for a specific resource table
*
* @details This function performs the following operations:
* - Identifies the resource table associated with the specified ID
* - Releases the mutex lock to allow other threads access
* - Completes the atomic operation sequence started with lock
* - Enables other threads to perform resource table operations
*
* This function must be called after @ref pva_kmd_resource_table_lock()
* to release the exclusive access to the resource table. Failure to
* unlock will result in deadlock for other threads.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] res_table_id Resource table identifier to unlock
* Valid range: [0 .. PVA_KMD_MAX_NUM_KMD_RESOURCES-1]
*/
void pva_kmd_resource_table_unlock(struct pva_kmd_device *pva, void pva_kmd_resource_table_unlock(struct pva_kmd_device *pva,
uint8_t res_table_id); uint8_t res_table_id);
#endif // PVA_KMD_RESOURCE_TABLE_H #endif // PVA_KMD_RESOURCE_TABLE_H

View File

@@ -107,14 +107,14 @@ static void sha256_transform(struct sha256_ctx *ctx, const void *data_in)
void sha256_init(struct sha256_ctx *ctx) void sha256_init(struct sha256_ctx *ctx)
{ {
ctx->bitlen = 0; ctx->bitlen = 0;
ctx->state[0] = U32(0x6a09e667); ctx->state[0] = U32(0x6a09e667U);
ctx->state[1] = U32(0xbb67ae85); ctx->state[1] = U32(0xbb67ae85U);
ctx->state[2] = U32(0x3c6ef372); ctx->state[2] = U32(0x3c6ef372U);
ctx->state[3] = U32(0xa54ff53a); ctx->state[3] = U32(0xa54ff53aU);
ctx->state[4] = U32(0x510e527f); ctx->state[4] = U32(0x510e527fU);
ctx->state[5] = U32(0x9b05688c); ctx->state[5] = U32(0x9b05688cU);
ctx->state[6] = U32(0x1f83d9ab); ctx->state[6] = U32(0x1f83d9abU);
ctx->state[7] = U32(0x5be0cd19); ctx->state[7] = U32(0x5be0cd19U);
} }
void sha256_update(struct sha256_ctx *ctx, const void *data, size_t len) void sha256_update(struct sha256_ctx *ctx, const void *data, size_t len)
@@ -122,7 +122,7 @@ void sha256_update(struct sha256_ctx *ctx, const void *data, size_t len)
uint32_t i; uint32_t i;
for (i = 0; i < len; i += U32(64)) { for (i = 0; i < len; i += U32(64)) {
ctx->bitlen &= U32(0xffffffff); ctx->bitlen &= U32(0xffffffffU);
sha256_transform(ctx, ((const uint8_t *)data) + i); sha256_transform(ctx, ((const uint8_t *)data) + i);
ctx->bitlen = ctx->bitlen =
safe_wrap_add_u32((uint32_t)ctx->bitlen, U32(512)); safe_wrap_add_u32((uint32_t)ctx->bitlen, U32(512));
@@ -141,8 +141,8 @@ void sha256_finalize(struct sha256_ctx *ctx, const void *input,
void *p = data; void *p = data;
uint32_t t; uint32_t t;
input_size &= U32(0xffffffff); input_size &= U32(0xffffffffU);
ctx->bitlen &= U32(0xffffffff); ctx->bitlen &= U32(0xffffffffU);
/* the false of this condition is illegal for this API agreement */ /* the false of this condition is illegal for this API agreement */
/* this check is here only for Coverity INT30-C */ /* this check is here only for Coverity INT30-C */

View File

@@ -5,69 +5,138 @@
#define PVA_KMD_SHA256_H #define PVA_KMD_SHA256_H
#include "pva_api_types.h" #include "pva_api_types.h"
/**
* @brief Utility macro to cast value to uint32_t
*
* @details Convenience macro for casting values to 32-bit unsigned integers.
* Used throughout SHA256 implementation for type safety and clarity.
*/
#define U32(x) ((uint32_t)(x)) #define U32(x) ((uint32_t)(x))
/**
* @brief SHA256 hash computation context structure
*
* @details This structure maintains the state for incremental SHA256 hash
* computation. It stores the bit length of processed data and the current
* hash state array. The union for bitlen accommodates both size_t (for
* efficiency on RISC-V and other architectures) and uint32_t (for Coverity
* analysis) representations of the bit length.
*/
struct sha256_ctx { struct sha256_ctx {
/* /**
* On bitlen: * @brief Bit length of processed data
* *
* While we don't exceed 2^32 bit (2^29 byte) length for the input buffer, * @details Union to handle bit length efficiently while satisfying static analysis.
* size_t is more efficient at least on RISC-V. This particular * While we don't exceed 2^32 bit (2^29 byte) length for input buffers,
* structure is needed to make Coverity happy. * size_t is more efficient on at least RISC-V. This union structure
* is needed to make Coverity static analysis happy.
*/ */
union { union {
/** @brief Bit length as size_t for efficiency */
size_t bitlen; size_t bitlen;
/** @brief Bit length as uint32_t for static analysis */
uint32_t bitlen_low; uint32_t bitlen_low;
}; };
/**
* @brief SHA256 hash state array
*
* @details Array of 8 32-bit words representing the current SHA256 hash state.
* These values are updated during hash computation and contain the final
* hash result when computation is complete.
*/
uint32_t state[8]; uint32_t state[8];
}; };
/** /**
* Initializes struct sha256_ctx * @brief Initialize SHA256 context for hash computation
* *
* \param[in] ctx pointer of struct sha256_ctx context * @details This function performs the following operations:
* - Initializes the SHA256 context structure to known initial state
* - Sets the bit length counter to zero
* - Loads the SHA256 initial hash values into the state array
* - Prepares the context for incremental hash computation
* - Ensures context is in valid state for subsequent operations
* *
* \return void * This function must be called before any hash data can be processed
* using @ref sha256_update() or @ref sha256_finalize().
*
* @param[out] ctx Pointer to @ref sha256_ctx context structure to initialize
* Valid value: non-null
*/ */
void sha256_init(struct sha256_ctx *ctx); void sha256_init(struct sha256_ctx *ctx);
/** /**
* \brief * @brief Process full blocks of data for SHA256 hash computation
* Hash full blocks, in units of 64 bytes
* can be called repeatedly with chunks of the message
* to be hashed (len bytes at data).
* *
* \param[in] ctx pointer of struct sha256_ctx context * @details This function performs the following operations:
* \param[in] data pointer to the data block to be hashed * - Processes complete 64-byte blocks of input data
* \param[in] len length (in units of 64 bytes) of the data to be hashed. * - Updates the SHA256 state with the processed block data
* - Maintains bit length counter for the total processed data
* - Can be called repeatedly with chunks of the message to be hashed
* - Optimized for processing large amounts of data efficiently
* - Handles block-aligned data for optimal performance
* *
* \return void * This function processes data in 64-byte chunks and can be called multiple
* times to hash large inputs incrementally. The input length should be a
* multiple of 64 bytes for optimal operation.
*
* @param[in, out] ctx Pointer to @ref sha256_ctx context structure
* Valid value: non-null, must be initialized
* @param[in] data Pointer to input data block to be hashed
* Valid value: non-null
* @param[in] len Length of data in bytes (should be multiple of 64)
* Valid range: [0 .. SIZE_MAX]
*/ */
void sha256_update(struct sha256_ctx *ctx, const void *data, size_t len); void sha256_update(struct sha256_ctx *ctx, const void *data, size_t len);
/** /**
* \brief * @brief Finalize SHA256 hash computation and produce result
* Finalize the hash and keep the calcualted hash in out.
* Required: input_size < 64. Call pva_sha256_update() first otherwise.
* *
* \param[in] ctx pointer of struct sha256_ctx context * @details This function performs the following operations:
* \param[in] input pointer to the data block * - Processes any remaining input data less than 64 bytes
* (left over from \ref pva_sha256_update) to be hashed * - Applies SHA256 padding according to the algorithm specification
* \param[in] input_size size of the data block to hashed * - Includes the total bit length in the final padding block
* (left over from \ref pva_sha256_update to be hashed) * - Completes the hash computation and produces the final result
* \param[out] out places the calcuated sha256 key in out. * - Stores the 256-bit hash result in the output array
* - Handles final block processing with proper padding
* *
* \return void * This function must be called after all data has been processed with
* @ref sha256_update() to complete the hash computation. The input_size
* parameter must be less than 64 bytes (remaining data after block processing).
*
* @param[in, out] ctx Pointer to @ref sha256_ctx context structure
* Valid value: non-null, must be initialized
* @param[in] input Pointer to remaining data block to be hashed
* Valid value: non-null if input_size > 0,
* may be null if input_size == 0
* @param[in] input_size Size of remaining data block in bytes
* Valid range: [0 .. 63]
* @param[out] out Array to store the computed SHA256 hash result
* Valid value: non-null, must have space for 8 uint32_t values
*/ */
void sha256_finalize(struct sha256_ctx *ctx, const void *input, void sha256_finalize(struct sha256_ctx *ctx, const void *input,
size_t input_size, uint32_t out[8]); size_t input_size, uint32_t out[8]);
/** /**
* \brief * @brief Copy SHA256 context state from one context to another
* copy state information to ctx_out from ctx_in *
* \param[in] ctx_in input struct sha256_ctx * @details This function performs the following operations:
* \param[out] ctx_out output struct sha256_ctx * - Copies the complete state from input context to output context
* \return void * - Transfers bit length counter and hash state array
* - Creates an independent copy that can be used separately
* - Enables branched hash computation from a common base
* - Preserves the state for continued computation on both contexts
* - Useful for scenarios requiring multiple hash computations from same base
*
* This function allows creating checkpoints in hash computation or
* branching hash computation to produce multiple related hashes efficiently.
*
* @param[in] ctx_in Pointer to source @ref sha256_ctx structure to copy from
* Valid value: non-null, must be initialized
* @param[out] ctx_out Pointer to destination @ref sha256_ctx structure to copy to
* Valid value: non-null
*/ */
void sha256_copy(const struct sha256_ctx *ctx_in, struct sha256_ctx *ctx_out); void sha256_copy(const struct sha256_ctx *ctx_in, struct sha256_ctx *ctx_out);

View File

@@ -6,6 +6,8 @@
#include "pva_kmd_context.h" #include "pva_kmd_context.h"
#include "pva_kmd_shim_trace_event.h" #include "pva_kmd_shim_trace_event.h"
#include "pva_kmd_shared_buffer.h" #include "pva_kmd_shared_buffer.h"
#include "pva_kmd_fw_tracepoints.h"
#include "pva_kmd_limits.h"
enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva, enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva,
uint8_t interface, uint8_t interface,
@@ -21,7 +23,7 @@ enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva,
uint64_t buffer_size; uint64_t buffer_size;
struct pva_cmd_init_shared_dram_buffer init_cmd = { 0 }; struct pva_cmd_init_shared_dram_buffer init_cmd = { 0 };
ASSERT(interface < PVA_MAX_NUM_CCQ); ASSERT(interface < (uint8_t)PVA_MAX_NUM_CCQ);
buffer = &pva->kmd_fw_buffers[interface]; buffer = &pva->kmd_fw_buffers[interface];
// If the buffer is already initialized, skip buffer allocation and just notify FW. // If the buffer is already initialized, skip buffer allocation and just notify FW.
@@ -65,11 +67,21 @@ enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva,
device_memory = buffer->resource_memory; device_memory = buffer->resource_memory;
} }
pva_kmd_set_cmd_init_shared_dram_buffer( /* Validate device memory size and iova fit in uint32_t */
&init_cmd, interface, device_memory->iova, device_memory->size); if ((device_memory->size > U32_MAX) ||
(device_memory->iova > U32_MAX)) {
pva_kmd_log_err("Device memory size or iova exceeds U32_MAX");
err = PVA_INVAL;
goto release_handler;
}
/* CERT INT31-C: iova and size validated to fit in uint32_t, safe to cast */
pva_kmd_set_cmd_init_shared_dram_buffer(&init_cmd, (uint8_t)interface,
device_memory->iova,
device_memory->size);
err = pva_kmd_submit_cmd_sync(&pva->submitter, &init_cmd, err = pva_kmd_submit_cmd_sync(&pva->submitter, &init_cmd,
sizeof(init_cmd), (uint32_t)sizeof(init_cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -95,13 +107,13 @@ enum pva_error pva_kmd_shared_buffer_deinit(struct pva_kmd_device *pva,
struct pva_kmd_shared_buffer *buffer; struct pva_kmd_shared_buffer *buffer;
struct pva_cmd_deinit_shared_dram_buffer deinit_cmd = { 0 }; struct pva_cmd_deinit_shared_dram_buffer deinit_cmd = { 0 };
ASSERT(interface < PVA_MAX_NUM_CCQ); ASSERT(interface < (uint8_t)PVA_MAX_NUM_CCQ);
buffer = &pva->kmd_fw_buffers[interface]; buffer = &pva->kmd_fw_buffers[interface];
pva_kmd_set_cmd_deinit_shared_dram_buffer(&deinit_cmd, interface); pva_kmd_set_cmd_deinit_shared_dram_buffer(&deinit_cmd, interface);
err = pva_kmd_submit_cmd_sync(&pva->submitter, &deinit_cmd, err = pva_kmd_submit_cmd_sync(&pva->submitter, &deinit_cmd,
sizeof(deinit_cmd), (uint32_t)sizeof(deinit_cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -119,58 +131,43 @@ enum pva_error pva_kmd_shared_buffer_deinit(struct pva_kmd_device *pva,
return err; return err;
} }
static void shared_buffer_process_msg(struct pva_kmd_device *pva, static void process_fw_event_msg(struct pva_kmd_device *pva, void *msg_body,
uint8_t interface, void *msg) uint32_t msg_size)
{ {
enum pva_error err = PVA_SUCCESS; // TODO: This must be updated once profiler config is exposed through debugfs.
struct pva_kmd_fw_buffer_msg_header header; // KMD must use the same timestamp size as the FW. It is possible that the user
struct pva_kmd_fw_msg_cmdbuf_trace cmdbuf_trace; // changes the timestamp size through debugfs after FW logged the event.
struct pva_kmd_fw_msg_vpu_exec_trace vpu_trace; // FW must log the type of timestamp it used to capture the event.
struct pva_kmd_fw_msg_engine_acquire_trace engine_acquire_trace; ASSERT(msg_size == sizeof(struct pva_fw_event_message) +
struct pva_kmd_fw_msg_fence_trace fence_trace; pva->debugfs_context.g_fw_profiling_config
struct pva_kmd_fw_msg_res_unreg unreg_data; .timestamp_size);
struct pva_kmd_context *ctx = NULL;
void *msg_body;
uint32_t msg_size;
struct pva_fw_tracepoint tracepoint;
ASSERT(msg != NULL); pva_kmd_process_fw_event(pva, (uint8_t *)msg_body, msg_size);
}
// Copy the header static void process_trace_msg(struct pva_kmd_device *pva, uint32_t msg_type,
memcpy(&header, msg, sizeof(header)); void *msg_body, uint32_t msg_size)
msg_size = safe_subu32(header.size, sizeof(header)); {
msg_body = (uint8_t *)msg + sizeof(header); switch (msg_type) {
#if PVA_ENABLE_FW_TRACEPOINTS == 1
switch (header.type) {
case PVA_KMD_FW_BUF_MSG_TYPE_FW_EVENT: {
// TODO: This must be updated once profiler config is exposed through debugfs.
// KMD must use the same timestamp size as the FW. It is possible that the user
// changes the timestamp size through debugfs after FW logged the event.
// FW must log the type of timestamp it used to capture the event.
ASSERT(msg_size ==
sizeof(struct pva_fw_event_message) +
pva->debugfs_context.g_fw_profiling_config
.timestamp_size);
err = pva_kmd_process_fw_event(pva, msg_body, msg_size);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to process FW event");
}
break;
}
case PVA_KMD_FW_BUF_MSG_TYPE_FW_TRACEPOINT: { case PVA_KMD_FW_BUF_MSG_TYPE_FW_TRACEPOINT: {
struct pva_fw_tracepoint tracepoint;
ASSERT(msg_size == sizeof(struct pva_fw_tracepoint)); ASSERT(msg_size == sizeof(struct pva_fw_tracepoint));
memcpy(&tracepoint, msg_body, sizeof(tracepoint)); memcpy(&tracepoint, msg_body, sizeof(tracepoint));
pva_kmd_process_fw_tracepoint(pva, &tracepoint); pva_kmd_process_fw_tracepoint(pva, &tracepoint);
break; break;
} }
#endif
#if PVA_ENABLE_NSYS_PROFILING == 1
case PVA_KMD_FW_BUF_MSG_TYPE_CMD_BUF_TRACE: { case PVA_KMD_FW_BUF_MSG_TYPE_CMD_BUF_TRACE: {
struct pva_kmd_fw_msg_cmdbuf_trace cmdbuf_trace;
ASSERT(msg_size == sizeof(struct pva_kmd_fw_msg_cmdbuf_trace)); ASSERT(msg_size == sizeof(struct pva_kmd_fw_msg_cmdbuf_trace));
memcpy(&cmdbuf_trace, msg_body, sizeof(cmdbuf_trace)); memcpy(&cmdbuf_trace, msg_body, sizeof(cmdbuf_trace));
pva_kmd_nsys_cmdbuf_trace(pva, &cmdbuf_trace); pva_kmd_nsys_cmdbuf_trace(pva, &cmdbuf_trace);
break; break;
} }
case PVA_KMD_FW_BUF_MSG_TYPE_VPU_TRACE: { case PVA_KMD_FW_BUF_MSG_TYPE_VPU_TRACE: {
struct pva_kmd_fw_msg_vpu_exec_trace vpu_trace;
ASSERT(msg_size == ASSERT(msg_size ==
sizeof(struct pva_kmd_fw_msg_vpu_exec_trace)); sizeof(struct pva_kmd_fw_msg_vpu_exec_trace));
memcpy(&vpu_trace, msg_body, sizeof(vpu_trace)); memcpy(&vpu_trace, msg_body, sizeof(vpu_trace));
@@ -181,33 +178,83 @@ static void shared_buffer_process_msg(struct pva_kmd_device *pva,
break; break;
} }
case PVA_KMD_FW_BUF_MSG_TYPE_FENCE_TRACE: { case PVA_KMD_FW_BUF_MSG_TYPE_FENCE_TRACE: {
struct pva_kmd_fw_msg_fence_trace fence_trace;
ASSERT(msg_size == sizeof(struct pva_kmd_fw_msg_fence_trace)); ASSERT(msg_size == sizeof(struct pva_kmd_fw_msg_fence_trace));
memcpy(&fence_trace, msg_body, sizeof(fence_trace)); (void)memcpy(&fence_trace, (const uint8_t *)msg_body,
sizeof(fence_trace));
pva_kmd_nsys_fence_trace(pva, &fence_trace); pva_kmd_nsys_fence_trace(pva, &fence_trace);
break; break;
} }
case PVA_KMD_FW_BUF_MSG_TYPE_ENGINE_ACQUIRE_TRACE: { case PVA_KMD_FW_BUF_MSG_TYPE_ENGINE_ACQUIRE_TRACE: {
struct pva_kmd_fw_msg_engine_acquire_trace engine_acquire_trace;
ASSERT(msg_size == ASSERT(msg_size ==
sizeof(struct pva_kmd_fw_msg_engine_acquire_trace)); sizeof(struct pva_kmd_fw_msg_engine_acquire_trace));
memcpy(&engine_acquire_trace, msg_body, (void)memcpy(&engine_acquire_trace, (const uint8_t *)msg_body,
sizeof(engine_acquire_trace)); sizeof(engine_acquire_trace));
pva_kmd_nsys_engine_acquire_trace(pva, &engine_acquire_trace); pva_kmd_nsys_engine_acquire_trace(pva, &engine_acquire_trace);
break; break;
} }
case PVA_KMD_FW_BUF_MSG_TYPE_RES_UNREG: { #endif
ASSERT(msg_size == sizeof(struct pva_kmd_fw_msg_res_unreg)); default: {
memcpy(&unreg_data, msg_body, sizeof(unreg_data)); // This should not happen as we only call this function for known message types.
ctx = pva_kmd_get_context(pva, interface); // Added for fixing the compiler warning.
FAULT("Unexpected trace message type in process_trace_msg");
ASSERT(ctx != NULL);
// We do not lock the resource table here because this function is intended
// to be called from the shared buffer processing function which should acquire
// the required lock.
pva_kmd_drop_resource_unsafe(&ctx->ctx_resource_table,
unreg_data.resource_id);
break; break;
} }
}
}
static void process_res_unreg_msg(struct pva_kmd_device *pva, uint8_t interface,
void *msg_body, uint32_t msg_size)
{
struct pva_kmd_fw_msg_res_unreg unreg_data;
struct pva_kmd_context *ctx = NULL;
ASSERT(msg_size == sizeof(struct pva_kmd_fw_msg_res_unreg));
/* MISRA C-2023 Rule 11.5: msg_body is void*, explicit cast needed for type safety */
(void)memcpy(&unreg_data,
(const struct pva_kmd_fw_msg_res_unreg *)msg_body,
sizeof(unreg_data));
ctx = pva_kmd_get_context(pva, interface);
ASSERT(ctx != NULL);
// We do not lock the resource table here because this function is intended
// to be called from the shared buffer processing function which should acquire
// the required lock.
pva_kmd_drop_resource_unsafe(&ctx->ctx_resource_table,
unreg_data.resource_id);
}
static void shared_buffer_process_msg(struct pva_kmd_device *pva,
uint8_t interface, void *msg)
{
struct pva_kmd_fw_buffer_msg_header header;
void *msg_body;
uint32_t msg_size;
ASSERT(msg != NULL);
// Copy the header
(void)memcpy(&header, (const struct pva_kmd_fw_buffer_msg_header *)msg,
sizeof(header));
msg_size = safe_subu32(header.size, (uint32_t)sizeof(header));
msg_body = (uint8_t *)msg + sizeof(header);
switch (header.type) {
case PVA_KMD_FW_BUF_MSG_TYPE_FW_EVENT:
process_fw_event_msg(pva, msg_body, msg_size);
break;
case PVA_KMD_FW_BUF_MSG_TYPE_FW_TRACEPOINT:
case PVA_KMD_FW_BUF_MSG_TYPE_CMD_BUF_TRACE:
case PVA_KMD_FW_BUF_MSG_TYPE_VPU_TRACE:
case PVA_KMD_FW_BUF_MSG_TYPE_FENCE_TRACE:
case PVA_KMD_FW_BUF_MSG_TYPE_ENGINE_ACQUIRE_TRACE:
process_trace_msg(pva, header.type, msg_body, msg_size);
break;
case PVA_KMD_FW_BUF_MSG_TYPE_RES_UNREG:
process_res_unreg_msg(pva, interface, msg_body, msg_size);
break;
default: default:
FAULT("Unexpected message type while processing shared buffer"); FAULT("Unexpected message type while processing shared buffer");
break; break;
@@ -216,32 +263,43 @@ static void shared_buffer_process_msg(struct pva_kmd_device *pva,
void pva_kmd_shared_buffer_process(void *pva_dev, uint8_t interface) void pva_kmd_shared_buffer_process(void *pva_dev, uint8_t interface)
{ {
struct pva_kmd_device *pva = (struct pva_kmd_device *)pva_dev; struct pva_kmd_device *pva;
struct pva_kmd_shared_buffer *fw_buffer = struct pva_kmd_shared_buffer *fw_buffer;
&pva->kmd_fw_buffers[interface];
uint32_t *buffer_head; uint32_t *buffer_head;
uint32_t buffer_tail; uint32_t buffer_tail;
uint32_t buffer_size; uint32_t buffer_size;
uint8_t *buffer_body; uint8_t *buffer_body;
uint32_t element_size; uint32_t element_size;
uint8_t *current_element = NULL; uint8_t *current_element;
uint64_t buffer_size_u64;
pva = (struct pva_kmd_device *)pva_dev;
fw_buffer = &pva->kmd_fw_buffers[interface];
current_element = NULL;
if (fw_buffer->lock_cb != NULL) {
fw_buffer->lock_cb(pva, interface);
}
ASSERT(fw_buffer->resource_memory->size > sizeof(*fw_buffer->header)); ASSERT(fw_buffer->resource_memory->size > sizeof(*fw_buffer->header));
buffer_head = &fw_buffer->header->head; buffer_head = &fw_buffer->header->head;
buffer_tail = fw_buffer->header->tail; buffer_tail = fw_buffer->header->tail;
buffer_size = /* buffer size bounded by resource memory allocation */
buffer_size_u64 =
fw_buffer->resource_memory->size - sizeof(*fw_buffer->header); fw_buffer->resource_memory->size - sizeof(*fw_buffer->header);
ASSERT(buffer_size_u64 <= U32_MAX);
buffer_size = (uint32_t)buffer_size_u64;
buffer_body = fw_buffer->body; buffer_body = fw_buffer->body;
element_size = fw_buffer->header->element_size; element_size = fw_buffer->header->element_size;
ASSERT(buffer_body != NULL); ASSERT(buffer_body != NULL);
// Ensure element size fits within the buffer // Ensure element size fits within the buffer
ASSERT(buffer_size % element_size == 0); ASSERT(buffer_size % element_size == 0U);
// check buffer header to see if there was an overflow // check buffer header to see if there was an overflow
if (fw_buffer->header->flags & PVA_KMD_FW_BUF_FLAG_OVERFLOW) { if ((fw_buffer->header->flags & PVA_KMD_FW_BUF_FLAG_OVERFLOW) != 0U) {
// Clear the overflow flag // Clear the overflow flag
// Note: this might be error prone. We are writing the flag here and at // Note: this might be error prone. We are writing the flag here and at
// the same time, the FW might be updating the flag too. Since the // the same time, the FW might be updating the flag too. Since the
@@ -270,10 +328,6 @@ void pva_kmd_shared_buffer_process(void *pva_dev, uint8_t interface)
// We will drop the overflowed messages. // We will drop the overflowed messages.
} }
if (fw_buffer->lock_cb != NULL) {
fw_buffer->lock_cb(pva, interface);
}
// Loop while `head` has not yet caught up to `tail` // Loop while `head` has not yet caught up to `tail`
while (*buffer_head != buffer_tail) { while (*buffer_head != buffer_tail) {
// Ensure current position is valid // Ensure current position is valid

View File

@@ -5,31 +5,140 @@
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
/**
* @brief Function pointer type for processing shared buffer elements
*
* @details This function pointer type defines the signature for callback
* functions used to process individual elements from shared buffers. The
* callback is invoked for each element that needs to be processed, allowing
* different interfaces to handle their specific element types appropriately.
*
* @param[in] context Pointer to context data for the processing operation
* Valid value: can be null if no context needed
* @param[in] interface Interface identifier for the shared buffer
* Valid range: [0 .. UINT8_MAX]
* @param[in] element Pointer to the element data to be processed
* Valid value: non-null
*
* @retval PVA_SUCCESS Element processed successfully
* @retval error_code Processing failed with specific error
*/
typedef enum pva_error (*shared_buffer_process_element_cb)(void *context, typedef enum pva_error (*shared_buffer_process_element_cb)(void *context,
uint8_t interface, uint8_t interface,
uint8_t *element); uint8_t *element);
/**
* @brief Function pointer type for shared buffer locking operations
*
* @details This function pointer type defines the signature for callback
* functions used to lock and unlock shared buffers. These callbacks provide
* synchronization mechanisms to ensure thread-safe access to shared buffer
* data structures between KMD and firmware operations.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] interface Identifier for the shared buffer interface
* Valid range: [0 .. UINT8_MAX]
*/
typedef void (*shared_buffer_lock_cb)(struct pva_kmd_device *pva, typedef void (*shared_buffer_lock_cb)(struct pva_kmd_device *pva,
uint8_t interface); uint8_t interface);
/**
* @brief Structure for managing shared buffer communication between KMD and firmware
*
* @details This structure manages a shared buffer used for communication between
* the KMD and firmware. The buffer consists of a header located in shared DRAM
* memory that both KMD and firmware can access, along with local KMD fields
* for bookkeeping and callback management. The structure supports element-based
* communication with configurable processing and synchronization callbacks.
*/
struct pva_kmd_shared_buffer { struct pva_kmd_shared_buffer {
// Only 'header' is in shared DRAM memory /**
// Other fields are local to KMD and should be used for internal bookkeeping * @brief Pointer to shared buffer header in DRAM memory
*
* @details Only 'header' is in shared DRAM memory accessible by both KMD and firmware
*/
struct pva_fw_shared_buffer_header *header; struct pva_fw_shared_buffer_header *header;
// 'body' tracks the begining of buffer contents in DRAM
/**
* @brief Pointer to beginning of buffer contents in DRAM
*
* @details 'body' tracks the beginning of buffer contents in DRAM
*/
uint8_t *body; uint8_t *body;
// 'process_cb' callback is used to process elements in the buffer
/**
* @brief Callback function for processing buffer elements
*
* @details 'process_cb' callback is used to process elements in the buffer
*/
shared_buffer_process_element_cb process_cb; shared_buffer_process_element_cb process_cb;
// 'lock_cb' callback is used to lock the buffer
/**
* @brief Callback function for acquiring buffer lock
*
* @details 'lock_cb' callback is used to lock the buffer for thread safety
*/
shared_buffer_lock_cb lock_cb; shared_buffer_lock_cb lock_cb;
// 'unlock_cb' callback is used to unlock the buffer
/**
* @brief Callback function for releasing buffer lock
*
* @details 'unlock_cb' callback is used to unlock the buffer
*/
shared_buffer_lock_cb unlock_cb; shared_buffer_lock_cb unlock_cb;
// 'resource_memory' is used to track the memory allocated for the buffer
/**
* @brief Device memory allocation tracking for the buffer
*
* @details 'resource_memory' is used to track the memory allocated for the buffer
*/
struct pva_kmd_device_memory *resource_memory; struct pva_kmd_device_memory *resource_memory;
// 'resource_offset' is used to track offset of buffer in 'resource_id'
/**
* @brief Offset of buffer within the allocated resource
*
* @details 'resource_offset' is used to track offset of buffer in 'resource_id'
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t resource_offset; uint32_t resource_offset;
}; };
/**
* @brief Initialize a shared buffer for KMD-firmware communication
*
* @details This function performs the following operations:
* - Allocates device memory for the shared buffer and its header
* - Initializes the buffer header with specified element and buffer sizes
* - Sets up the buffer structure with provided callback functions
* - Configures the buffer for the specified interface identifier
* - Registers the buffer memory with the device's resource management system
* - Establishes proper synchronization mechanisms for thread-safe access
* - Prepares the buffer for element-based communication with firmware
*
* The initialized buffer can be used for bidirectional communication between
* KMD and firmware, with elements processed using the provided callback
* functions. The buffer must be deinitialized using @ref pva_kmd_shared_buffer_deinit()
* when no longer needed.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] interface Interface identifier for this shared buffer
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
* @param[in] element_size Size of each element in bytes
* Valid range: [1 .. UINT32_MAX]
* @param[in] buffer_size Total buffer size in bytes
* Valid range: [element_size .. UINT32_MAX]
* @param[in] lock_cb Callback function for acquiring buffer lock
* Valid value: non-null
* @param[in] unlock_cb Callback function for releasing buffer lock
* Valid value: non-null
*
* @retval PVA_SUCCESS Buffer initialized successfully
* @retval PVA_NOMEM Failed to allocate buffer memory
* @retval PVA_INVAL Invalid parameters or callback pointers
* @retval PVA_INTERNAL Failed to register buffer with resource system
*/
enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva, enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva,
uint8_t interface, uint8_t interface,
uint32_t element_size, uint32_t element_size,
@@ -37,14 +146,103 @@ enum pva_error pva_kmd_shared_buffer_init(struct pva_kmd_device *pva,
shared_buffer_lock_cb lock_cb, shared_buffer_lock_cb lock_cb,
shared_buffer_lock_cb unlock_cb); shared_buffer_lock_cb unlock_cb);
/**
* @brief Deinitialize a shared buffer and free associated resources
*
* @details This function performs the following operations:
* - Ensures the buffer is properly synchronized and no operations are pending
* - Unregisters the buffer memory from the device's resource management system
* - Frees the allocated device memory for buffer and header
* - Cleans up the buffer structure and callback associations
* - Invalidates the buffer for the specified interface identifier
* - Ensures proper cleanup of synchronization mechanisms
*
* After calling this function, the shared buffer becomes invalid and cannot
* be used for communication. Any pending operations should be completed
* before calling this function to avoid resource leaks or synchronization issues.
*
* @param[in, out] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null
* @param[in] interface Interface identifier for the buffer to deinitialize
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
*
* @retval PVA_SUCCESS Buffer deinitialized successfully
* @retval PVA_INVAL Invalid interface or device pointer
* @retval PVA_AGAIN Buffer still has pending operations
*/
enum pva_error pva_kmd_shared_buffer_deinit(struct pva_kmd_device *pva, enum pva_error pva_kmd_shared_buffer_deinit(struct pva_kmd_device *pva,
uint8_t interface); uint8_t interface);
/**
* @brief Process pending elements in the shared buffer
*
* @details This function performs the following operations:
* - Acquires the buffer lock using the configured lock callback
* - Checks for new elements available in the shared buffer
* - Processes each available element using the configured process callback
* - Updates buffer pointers to mark elements as consumed
* - Handles buffer wraparound and overflow conditions appropriately
* - Releases the buffer lock using the configured unlock callback
* - Maintains proper synchronization between KMD and firmware
*
* This function is typically called in response to notifications from
* firmware indicating that new data is available in the shared buffer.
* The processing continues until all available elements have been handled.
*
* @param[in] pva_dev Pointer to PVA device structure
* Valid value: non-null
* @param[in] interface Interface identifier for the buffer to process
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
*/
void pva_kmd_shared_buffer_process(void *pva_dev, uint8_t interface); void pva_kmd_shared_buffer_process(void *pva_dev, uint8_t interface);
/**
* @brief Bind a processing handler to a shared buffer interface
*
* @details This function performs the following operations:
* - Associates a processing callback with the specified shared buffer interface
* - Stores the provided context data for use during element processing
* - Configures the buffer to use the specified handler for incoming elements
* - Validates that the interface and handler are properly configured
* - Updates internal state to enable processing for this interface
*
* The bound handler will be called for each element that needs processing
* on the specified interface. The context data is passed to the handler
* to provide any necessary state or configuration information.
*
* @param[in] pva_dev Pointer to PVA device structure
* Valid value: non-null
* @param[in] interface Interface identifier for the buffer
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
* @param[in] data Context data to pass to the processing handler
* Valid value: can be null if no context needed
*
* @retval PVA_SUCCESS Handler bound successfully
* @retval PVA_INVAL Invalid interface or device pointer
* @retval PVA_INTERNAL Buffer not properly initialized
*/
enum pva_error pva_kmd_bind_shared_buffer_handler(void *pva_dev, enum pva_error pva_kmd_bind_shared_buffer_handler(void *pva_dev,
uint8_t interface, uint8_t interface,
void *data); void *data);
/**
* @brief Release the processing handler from a shared buffer interface
*
* @details This function performs the following operations:
* - Removes the processing callback association from the specified interface
* - Clears any stored context data for the interface
* - Disables element processing for the interface
* - Ensures proper cleanup of handler-related resources
* - Updates internal state to reflect the handler removal
*
* After calling this function, the shared buffer will no longer process
* elements for the specified interface until a new handler is bound using
* @ref pva_kmd_bind_shared_buffer_handler().
*
* @param[in] pva_dev Pointer to PVA device structure
* Valid value: non-null
* @param[in] interface Interface identifier for the buffer
* Valid range: [0 .. PVA_MAX_NUM_CCQ-1]
*/
void pva_kmd_release_shared_buffer_handler(void *pva_dev, uint8_t interface); void pva_kmd_release_shared_buffer_handler(void *pva_dev, uint8_t interface);
#endif #endif

View File

@@ -11,6 +11,7 @@
#include "pva_kmd_silicon_boot.h" #include "pva_kmd_silicon_boot.h"
#include "pva_kmd_shim_silicon.h" #include "pva_kmd_shim_silicon.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_kmd_limits.h"
static inline void pva_kmd_set_sema(struct pva_kmd_device *pva, static inline void pva_kmd_set_sema(struct pva_kmd_device *pva,
uint32_t sema_idx, uint32_t val) uint32_t sema_idx, uint32_t val)
@@ -20,21 +21,6 @@ static inline void pva_kmd_set_sema(struct pva_kmd_device *pva,
pva_kmd_write(pva, safe_addu32(PVA_REG_HSP_SS0_SET_ADDR, gap), val); pva_kmd_write(pva, safe_addu32(PVA_REG_HSP_SS0_SET_ADDR, gap), val);
} }
static void init_fw_print_buffer(struct pva_kmd_fw_print_buffer *print_buffer,
void *debug_buffer_va)
{
print_buffer->buffer_info = pva_offset_pointer(
debug_buffer_va,
FW_TRACE_BUFFER_SIZE + FW_CODE_COVERAGE_BUFFER_SIZE);
print_buffer->buffer_info->size =
FW_DEBUG_LOG_BUFFER_SIZE - sizeof(*print_buffer->buffer_info);
print_buffer->buffer_info->head = 0;
print_buffer->buffer_info->tail = 0;
print_buffer->buffer_info->flags = 0;
print_buffer->content = pva_offset_pointer(
print_buffer->buffer_info, sizeof(*print_buffer->buffer_info));
}
static void disable_sec_mission_error_reporting(struct pva_kmd_device *pva) static void disable_sec_mission_error_reporting(struct pva_kmd_device *pva)
{ {
pva_kmd_write(pva, PVA_REG_SEC_ERRSLICE0_MISSIONERR_ENABLE_ADDR, 0U); pva_kmd_write(pva, PVA_REG_SEC_ERRSLICE0_MISSIONERR_ENABLE_ADDR, 0U);
@@ -55,16 +41,17 @@ void pva_kmd_config_evp_seg_regs(struct pva_kmd_device *pva)
{ {
uint64_t seg_reg_value; uint64_t seg_reg_value;
/* EVP */ /* EVP */
pva_kmd_write(pva, PVA_REG_EVP_RESET_ADDR, EVP_RESET_VECTOR); pva_kmd_write(pva, PVA_REG_EVP_RESET_ADDR, PVA_EVP_RESET_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_UNDEF_ADDR, pva_kmd_write(pva, PVA_REG_EVP_UNDEF_ADDR,
EVP_UNDEFINED_INSTRUCTION_VECTOR); PVA_EVP_UNDEFINED_INSTRUCTION_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_SWI_ADDR, EVP_SVC_VECTOR); pva_kmd_write(pva, PVA_REG_EVP_SWI_ADDR, PVA_EVP_SVC_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_PREFETCH_ABORT_ADDR, pva_kmd_write(pva, PVA_REG_EVP_PREFETCH_ABORT_ADDR,
EVP_PREFETCH_ABORT_VECTOR); PVA_EVP_PREFETCH_ABORT_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_DATA_ABORT_ADDR, EVP_DATA_ABORT_VECTOR); pva_kmd_write(pva, PVA_REG_EVP_DATA_ABORT_ADDR,
pva_kmd_write(pva, PVA_REG_EVP_RSVD_ADDR, EVP_RESERVED_VECTOR); PVA_EVP_DATA_ABORT_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_IRQ_ADDR, EVP_IRQ_VECTOR); pva_kmd_write(pva, PVA_REG_EVP_RSVD_ADDR, PVA_EVP_RESERVED_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_FIQ_ADDR, EVP_FIQ_VECTOR); pva_kmd_write(pva, PVA_REG_EVP_IRQ_ADDR, PVA_EVP_IRQ_VECTOR);
pva_kmd_write(pva, PVA_REG_EVP_FIQ_ADDR, PVA_EVP_FIQ_VECTOR);
/* R5 regions are defined as: /* R5 regions are defined as:
* - PRIV1 region for firmware code and data. * - PRIV1 region for firmware code and data.
* - PRIV2 region for debug printf data. * - PRIV2 region for debug printf data.
@@ -109,7 +96,8 @@ void pva_kmd_config_evp_seg_regs(struct pva_kmd_device *pva)
void pva_kmd_config_scr_regs(struct pva_kmd_device *pva) void pva_kmd_config_scr_regs(struct pva_kmd_device *pva)
{ {
uint32_t scr_lock_mask = pva->is_silicon ? 0xFFFFFFFF : (~PVA_SCR_LOCK); uint32_t scr_lock_mask =
pva->is_silicon ? 0xFFFFFFFFU : (~PVA_SCR_LOCK);
pva_kmd_write(pva, PVA_REG_EVP_SCR_ADDR, pva_kmd_write(pva, PVA_REG_EVP_SCR_ADDR,
PVA_EVP_SCR_VAL & scr_lock_mask); PVA_EVP_SCR_VAL & scr_lock_mask);
@@ -133,8 +121,11 @@ void pva_kmd_config_sid(struct pva_kmd_device *pva)
uint32_t offset; uint32_t offset;
uint8_t priv1_sid; uint8_t priv1_sid;
uint8_t priv_sid; uint8_t priv_sid;
priv_sid = pva->stream_ids[PVA_R5_SMMU_CONTEXT_ID] & 0xFF; priv_sid = (uint8_t)(pva->stream_ids[PVA_R5_SMMU_CONTEXT_ID] &
priv1_sid = pva->stream_ids[pva->r5_image_smmu_context_id] & 0xFF; (uint8_t)U8_MAX);
priv1_sid = (uint8_t)(pva->stream_ids[pva->r5_image_smmu_context_id] &
(uint8_t)U8_MAX);
/* Priv SIDs */ /* Priv SIDs */
if (pva->load_from_gsc) { if (pva->load_from_gsc) {
pva_kmd_write(pva, pva->regspec.cfg_priv_sid, pva_kmd_write(pva, pva->regspec.cfg_priv_sid,
@@ -159,7 +150,7 @@ void pva_kmd_config_sid(struct pva_kmd_device *pva)
} }
/* User SIDs */ /* User SIDs */
offset = 0; offset = 0;
for (i = 1; i < pva->hw_consts.n_smmu_contexts - 1; i++) { for (i = 1U; i < (pva->hw_consts.n_smmu_contexts - 1U); i++) {
addr = safe_addu32(pva->regspec.cfg_user_sid_base, offset); addr = safe_addu32(pva->regspec.cfg_user_sid_base, offset);
pva_kmd_write(pva, addr, pva->stream_ids[i]); pva_kmd_write(pva, addr, pva->stream_ids[i]);
offset = safe_addu32(offset, 4U); offset = safe_addu32(offset, 4U);
@@ -173,7 +164,7 @@ static uint32_t get_syncpt_offset(struct pva_kmd_device *pva,
uint64_t offset; uint64_t offset;
offset = safe_subu64(syncpt_iova, pva_kmd_get_r5_iova_start()); offset = safe_subu64(syncpt_iova, pva_kmd_get_r5_iova_start());
ASSERT(offset <= UINT32_MAX); ASSERT(offset <= U32_MAX);
return (uint32_t)offset; return (uint32_t)offset;
} else { } else {
// This is only for SIM mode where syncpoints are not supported. // This is only for SIM mode where syncpoints are not supported.
@@ -188,7 +179,8 @@ enum pva_error pva_kmd_load_fw(struct pva_kmd_device *pva)
uint32_t boot_sema = 0; uint32_t boot_sema = 0;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
uint32_t checkpoint; uint32_t checkpoint;
uint32_t scr_lock_mask = pva->is_silicon ? 0xFFFFFFFF : (~PVA_SCR_LOCK); uint32_t scr_lock_mask =
pva->is_silicon ? 0xFFFFFFFFU : (~PVA_SCR_LOCK);
/* Load firmware */ /* Load firmware */
if (!pva->load_from_gsc) { if (!pva->load_from_gsc) {
@@ -210,7 +202,7 @@ enum pva_error pva_kmd_load_fw(struct pva_kmd_device *pva)
"pva_kmd_device_memory_alloc_map failed in pva_kmd_load_fw"); "pva_kmd_device_memory_alloc_map failed in pva_kmd_load_fw");
goto free_fw_mem; goto free_fw_mem;
} }
init_fw_print_buffer(&pva->fw_print_buffer, pva->fw_debug_mem->va); pva_kmd_init_fw_print_buffer(pva, pva->fw_debug_mem->va);
pva->debugfs_context.r5_ocd_stage_buffer = pva->fw_debug_mem->va; pva->debugfs_context.r5_ocd_stage_buffer = pva->fw_debug_mem->va;
/* Program SCRs */ /* Program SCRs */
@@ -253,9 +245,11 @@ enum pva_error pva_kmd_load_fw(struct pva_kmd_device *pva)
if (pva->bl_sector_pack_format == PVA_BL_XBAR_RAW) { if (pva->bl_sector_pack_format == PVA_BL_XBAR_RAW) {
boot_sema = PVA_BOOT_SEMA_USE_XBAR_RAW; boot_sema = PVA_BOOT_SEMA_USE_XBAR_RAW;
} }
#if SYSTEM_TESTS_ENABLED == 1
if (pva->test_mode) { if (pva->test_mode) {
boot_sema |= PVA_BOOT_SEMA_TEST_MODE; boot_sema |= PVA_BOOT_SEMA_TEST_MODE;
} }
#endif
pva_kmd_set_sema(pva, PVA_BOOT_SEMA, boot_sema); pva_kmd_set_sema(pva, PVA_BOOT_SEMA, boot_sema);
pva_kmd_set_sema(pva, PVA_RO_SYNC_BASE_SEMA, pva_kmd_set_sema(pva, PVA_RO_SYNC_BASE_SEMA,
@@ -294,7 +288,7 @@ enum pva_error pva_kmd_load_fw(struct pva_kmd_device *pva)
pva, pva->regspec.ccq_regs[PVA_PRIV_CCQ_ID] pva, pva->regspec.ccq_regs[PVA_PRIV_CCQ_ID]
.status[PVA_REG_CCQ_STATUS6_IDX]); .status[PVA_REG_CCQ_STATUS6_IDX]);
pva_kmd_log_err_hex32("Checkpoint value:", checkpoint); pva_kmd_log_err_hex32("Checkpoint value:", checkpoint);
pva_kmd_report_error_fsi(pva, err); pva_kmd_report_error_fsi(pva, (uint32_t)err);
goto free_sec_lic; goto free_sec_lic;
} }
@@ -303,7 +297,7 @@ enum pva_error pva_kmd_load_fw(struct pva_kmd_device *pva)
free_sec_lic: free_sec_lic:
pva_kmd_free_intr(pva, PVA_KMD_INTR_LINE_SEC_LIC); pva_kmd_free_intr(pva, PVA_KMD_INTR_LINE_SEC_LIC);
free_fw_debug_mem: free_fw_debug_mem:
pva_kmd_drain_fw_print(&pva->fw_print_buffer); pva_kmd_drain_fw_print(pva);
pva_kmd_freeze_fw(pva); pva_kmd_freeze_fw(pva);
pva_kmd_device_memory_free(pva->fw_debug_mem); pva_kmd_device_memory_free(pva->fw_debug_mem);
free_fw_mem: free_fw_mem:
@@ -335,7 +329,7 @@ void pva_kmd_freeze_fw(struct pva_kmd_device *pva)
void pva_kmd_unload_fw(struct pva_kmd_device *pva) void pva_kmd_unload_fw(struct pva_kmd_device *pva)
{ {
pva_kmd_free_intr(pva, PVA_KMD_INTR_LINE_SEC_LIC); pva_kmd_free_intr(pva, PVA_KMD_INTR_LINE_SEC_LIC);
pva_kmd_drain_fw_print(&pva->fw_print_buffer); pva_kmd_drain_fw_print(pva);
// FW so that we can free memory // FW so that we can free memory
pva_kmd_freeze_fw(pva); pva_kmd_freeze_fw(pva);

View File

@@ -9,27 +9,44 @@
/** /**
* @brief Configure EVP and Segment config registers * @brief Configure EVP and Segment config registers
* *
* This function configures the EVP and Segment config registers. * @details This function configures the Exception Vector Prefix (EVP) and
* Segment configuration registers for the PVA device. The EVP registers
* control the location of exception vectors for the embedded processor,
* while segment configuration registers define memory mapping and access
* permissions. This configuration is essential for proper firmware loading
* and execution on the PVA hardware.
* *
* @param pva Pointer to the PVA device. * @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*/ */
void pva_kmd_config_evp_seg_regs(struct pva_kmd_device *pva); void pva_kmd_config_evp_seg_regs(struct pva_kmd_device *pva);
/** /**
* @brief Configure SCR registers. * @brief Configure SCR (System Control Register) registers
* *
* This function configures the SCR registers. * @details This function configures the System Control Registers (SCR) for
* the PVA device. SCR registers control various system-level settings including
* cache policies, memory protection attributes, and processor modes. Proper
* SCR configuration is critical for secure and efficient operation of the
* embedded processor within the PVA hardware.
* *
* @param pva Pointer to the PVA device. * @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*/ */
void pva_kmd_config_scr_regs(struct pva_kmd_device *pva); void pva_kmd_config_scr_regs(struct pva_kmd_device *pva);
/** /**
* @brief Configure SID registers. * @brief Configure SID (Stream ID) registers
* *
* This function configures the SID registers. * @details This function configures the Stream ID (SID) registers for the PVA
* device. SID registers define the stream identifiers used by the SMMU (System
* Memory Management Unit) for memory access control and virtualization. Proper
* SID configuration ensures that PVA memory accesses are correctly identified
* and routed through the appropriate SMMU translation contexts for security
* and isolation.
* *
* @param pva Pointer to the PVA device. * @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*/ */
void pva_kmd_config_sid(struct pva_kmd_device *pva); void pva_kmd_config_sid(struct pva_kmd_device *pva);

View File

@@ -3,15 +3,12 @@
#include "pva_kmd_silicon_elf_parser.h" #include "pva_kmd_silicon_elf_parser.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_kmd_limits.h"
#ifndef max #ifndef max
#define max(a, b) (((a) > (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b))
#endif #endif
#ifndef UINT8_MAX
#define UINT8_MAX 0xFF
#endif
// CERT complains about casts from const uint8_t*, so do intermediate cast to void* // CERT complains about casts from const uint8_t*, so do intermediate cast to void*
static inline const void *uint_8_to_void(const uint8_t *const p) static inline const void *uint_8_to_void(const uint8_t *const p)
{ {
@@ -21,8 +18,8 @@ static inline const void *uint_8_to_void(const uint8_t *const p)
bool elf_header_check(const elf_ct e) bool elf_header_check(const elf_ct e)
{ {
const elfFileHeader *efh = (const elfFileHeader *)e; const elfFileHeader *efh = (const elfFileHeader *)e;
if ((ELFCLASS32 == efh->oclass) && if ((PVA_ELFCLASS32 == efh->oclass) &&
(ELFMAGIC_LSB == *(const elfWord *)e)) { (PVA_ELFMAGIC_LSB == *(const elfWord *)e)) {
return true; return true;
} }
return false; return false;
@@ -217,8 +214,8 @@ static const char *elf_string_at_offset(const elf_parser_ctx e,
const elfSectionHeader *eshstr, const elfSectionHeader *eshstr,
unsigned int offset) unsigned int offset)
{ {
const char *strtab; const char *string_table;
elfOff stroffset; elfOff string_offset;
if (SHT_STRTAB != eshstr->type) { if (SHT_STRTAB != eshstr->type) {
return NULL; return NULL;
@@ -226,13 +223,14 @@ static const char *elf_string_at_offset(const elf_parser_ctx e,
if (offset >= eshstr->size) { if (offset >= eshstr->size) {
return NULL; return NULL;
} }
strtab = (const char *)e.elf_file; string_table = (const char *)e.elf_file;
stroffset = eshstr->offset + offset; string_offset = eshstr->offset + offset;
if (stroffset < eshstr->offset) { // check that stroffset doesn't wrap if (string_offset <
eshstr->offset) { // check that string_offset doesn't wrap
return NULL; return NULL;
} }
strtab = &strtab[stroffset]; string_table = &string_table[string_offset];
return strtab; return string_table;
} }
const char *elf_section_name(const elf_parser_ctx e, const char *elf_section_name(const elf_parser_ctx e,
@@ -345,7 +343,7 @@ const elfSymbol *elf_symbol(const elf_parser_ctx e, unsigned int index)
if (index >= (esh->size / esh->entsize)) { if (index >= (esh->size / esh->entsize)) {
return NULL; return NULL;
} }
if (esh->addralign <= (uint8_t)UINT8_MAX) { if (esh->addralign <= (uint8_t)U8_MAX) {
align = (uint8_t)esh->addralign; align = (uint8_t)esh->addralign;
} else { } else {
return NULL; return NULL;
@@ -387,7 +385,7 @@ const char *elf_symbol_name(const elf_parser_ctx e, const elfSectionHeader *esh,
return NULL; return NULL;
} }
p = (const char *)e.elf_file; p = (const char *)e.elf_file;
if (esh->addralign <= (uint8_t)UINT8_MAX) { if (esh->addralign <= (uint8_t)U8_MAX) {
align = (uint8_t)esh->addralign; align = (uint8_t)esh->addralign;
} else { } else {
return NULL; return NULL;

View File

File diff suppressed because it is too large Load Diff

View File

@@ -12,8 +12,8 @@
#include "pva_math_utils.h" #include "pva_math_utils.h"
/** /**
* enum to identify different segments of VPU ELF * enum to identify different segments of VPU ELF
*/ */
enum pva_elf_seg_type { enum pva_elf_seg_type {
/** Code segment in VPU ELF */ /** Code segment in VPU ELF */
PVA_SEG_VPU_CODE = 0U, PVA_SEG_VPU_CODE = 0U,
@@ -26,16 +26,16 @@ enum pva_elf_seg_type {
}; };
/** Maximum number of characters in symbol name */ /** Maximum number of characters in symbol name */
#define ELF_MAXIMUM_SYMBOL_LENGTH 64U #define PVA_ELF_MAXIMUM_SYMBOL_LENGTH 64U
/** Maximum number of characters in section name */ /** Maximum number of characters in section name */
#define ELF_MAXIMUM_SECTION_NAME 64 #define PVA_ELF_MAXIMUM_SECTION_NAME 64
/** Section name of EXPORTS section */ /** Section name of EXPORTS section */
#define ELF_EXPORTS_SECTION "EXPORTS" #define PVA_ELF_EXPORTS_SECTION "EXPORTS"
/** Section name of EXPORTS section name length */ /** Section name of EXPORTS section name length */
#define ELF_EXPORTS_SECTION_NAME_LENGTH 7 #define PVA_ELF_EXPORTS_SECTION_NAME_LENGTH 7
/** Alignment needed for Data section of ELFs */ /** Alignment needed for Data section of ELFs */
#define DATA_SECTION_ALIGNMENT 32U #define DATA_SECTION_ALIGNMENT 32U
@@ -44,7 +44,7 @@ enum pva_elf_seg_type {
#define TEXT_SECTION_ALIGNMENT 128U #define TEXT_SECTION_ALIGNMENT 128U
/** VPU icache size: 16KB */ /** VPU icache size: 16KB */
#define VPU_ICACHE_SIZE (16U * 1024U) #define VPU_ICACHE_SIZE (16UL * 1024UL)
/** This value indicates the that current symbol can be ignored in the VPU ELF */ /** This value indicates the that current symbol can be ignored in the VPU ELF */
#define SYM_IGNORE 1 #define SYM_IGNORE 1
@@ -62,9 +62,9 @@ static uint32_t change_byte_order(uint32_t word)
} }
/* /*
* Define mapping from VPU data, rodata and program sections into * Define mapping from VPU data, rodata and program sections into
* corresponding segment types. * corresponding segment types.
*/ */
static const struct pack_rule { static const struct pack_rule {
const char *elf_sec_name; const char *elf_sec_name;
int32_t pva_type; int32_t pva_type;
@@ -82,14 +82,14 @@ static const struct pack_rule {
} }; } };
/** /**
* \brief Compares the \a section_name with all * \brief Compares the \a section_name with all
* vpu elf section names until it finds a match and * vpu elf section names until it finds a match and
* then return corresponding segment type. * then return corresponding segment type.
* If the segment type is \ref PVA_SEG_VPU_DATA, then it further * If the segment type is \ref PVA_SEG_VPU_DATA, then it further
* checks if its PVA_SEG_VPU_IN_PARAMS. * checks if its PVA_SEG_VPU_IN_PARAMS.
* \param[in] section_name Name of the section to be searched for, in VPU ELF * \param[in] section_name Name of the section to be searched for, in VPU ELF
* \return returns corresponding value from enum pva_elf_seg_type. * \return returns corresponding value from enum pva_elf_seg_type.
*/ */
static int32_t find_pva_ucode_segment_type(const char *section_name) static int32_t find_pva_ucode_segment_type(const char *section_name)
{ {
uint32_t i; uint32_t i;
@@ -105,14 +105,14 @@ static int32_t find_pva_ucode_segment_type(const char *section_name)
} }
if (ret == (int32_t)PVA_SEG_VPU_DATA) { if (ret == (int32_t)PVA_SEG_VPU_DATA) {
uint64_t section_name_len = uint64_t section_name_len =
strnlen(section_name, ELF_MAXIMUM_SECTION_NAME); strnlen(section_name, PVA_ELF_MAXIMUM_SECTION_NAME);
uint64_t exports_section_name_len = uint64_t exports_section_name_len =
ELF_EXPORTS_SECTION_NAME_LENGTH; PVA_ELF_EXPORTS_SECTION_NAME_LENGTH;
// Check Export section present in DATA segment. Only support export sections. // Check Export section present in DATA segment. Only support export sections.
if ((section_name_len >= exports_section_name_len) && if ((section_name_len >= exports_section_name_len) &&
(strncmp((section_name + (strncmp((section_name +
(section_name_len - exports_section_name_len)), (section_name_len - exports_section_name_len)),
ELF_EXPORTS_SECTION, PVA_ELF_EXPORTS_SECTION,
(size_t)exports_section_name_len)) == 0) { (size_t)exports_section_name_len)) == 0) {
ret = (int32_t)PVA_SEG_VPU_IN_PARAMS; ret = (int32_t)PVA_SEG_VPU_IN_PARAMS;
} }
@@ -149,8 +149,8 @@ static int32_t validate_symbol(elf_parser_ctx elf, uint32_t symbol_entry_id,
*sym = elf_symbol(elf, symbol_entry_id); *sym = elf_symbol(elf, symbol_entry_id);
if ((*sym == NULL) || ((*sym)->size == 0U) || if ((*sym == NULL) || ((*sym)->size == 0U) ||
(ELF_ST_BIND(*sym) != STB_GLOBAL) || (PVA_ELF_ST_BIND(*sym) != STB_GLOBAL) ||
(ELF_ST_TYPE(*sym) == STT_FUNC)) { (PVA_ELF_ST_TYPE(*sym) == STT_FUNC)) {
err = SYM_IGNORE; err = SYM_IGNORE;
goto end; goto end;
} }
@@ -218,19 +218,19 @@ done:
} }
/** /**
* @brief updates symbol information (type, addr and size) from * @brief updates symbol information (type, addr and size) from
* VPU ELF PVA_SEG_VPU_IN_PARAMS segment. * VPU ELF PVA_SEG_VPU_IN_PARAMS segment.
* *
* Data about symbol information in EXPORTS section of ELF is present as follows. * Data about symbol information in EXPORTS section of ELF is present as follows.
* typedef struct { * typedef struct {
* uint32_t type; From VMEM_TYPE enums * uint32_t type; From VMEM_TYPE enums
* uint32_t addr_offset; Offset from VMEM base * uint32_t addr_offset; Offset from VMEM base
* uint32_t size; Size of VMEM region in bytes * uint32_t size; Size of VMEM region in bytes
* }; * };
* @param[in] elf pointer to const image of elf file. * @param[in] elf pointer to const image of elf file.
* @param[in] section_header pointer to VPU ELF PVA_SEG_VPU_IN_PARAMS section header * @param[in] section_header pointer to VPU ELF PVA_SEG_VPU_IN_PARAMS section header
* @param[in, out] symbol_info pointer to ELF image symbol which needs to be updated. * @param[in, out] symbol_info pointer to ELF image symbol which needs to be updated.
*/ */
static enum pva_error static enum pva_error
update_exports_symbol(elf_parser_ctx elf, update_exports_symbol(elf_parser_ctx elf,
const elfSectionHeader *section_header, const elfSectionHeader *section_header,
@@ -240,12 +240,19 @@ update_exports_symbol(elf_parser_ctx elf,
uint32_t symOffset = 0U; uint32_t symOffset = 0U;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
pva_math_error math_err = MATH_OP_SUCCESS; pva_math_error math_err = MATH_OP_SUCCESS;
uint32_t symbol_end;
uint32_t section_end;
/* Calculate symbol end address */
symbol_end = addu32(symbol_info->vmem_addr,
(uint32_t)SIZE_EXPORTS_TABLE_ENTRY, &math_err);
/* Calculate section end address */
section_end =
addu32(section_header->addr, section_header->size, &math_err);
if ((section_header == NULL) || if ((section_header == NULL) ||
(symbol_info->vmem_addr < section_header->addr) || (symbol_info->vmem_addr < section_header->addr) ||
(addu32(symbol_info->vmem_addr, (uint32_t)SIZE_EXPORTS_TABLE_ENTRY, (symbol_end > section_end)) {
&math_err) >
addu32(section_header->addr, section_header->size, &math_err))) {
err = PVA_INVAL; err = PVA_INVAL;
goto done; goto done;
} else { } else {
@@ -258,9 +265,10 @@ update_exports_symbol(elf_parser_ctx elf,
err = PVA_INVAL; err = PVA_INVAL;
goto done; goto done;
} }
symbol_info->symbol_type = *(uint8_t *)((uintptr_t)&data[symOffset]); symbol_info->symbol_type = (enum pva_symbol_type)(
if ((symbol_info->symbol_type == (uint8_t)PVA_SYM_TYPE_INVALID) || *(uint8_t *)((uintptr_t)&data[symOffset]));
(symbol_info->symbol_type >= (uint8_t)PVA_SYM_TYPE_MAX)) { if ((symbol_info->symbol_type == PVA_SYM_TYPE_INVALID) ||
(symbol_info->symbol_type >= PVA_SYM_TYPE_MAX)) {
pva_kmd_log_err("Invalid symbol type found"); pva_kmd_log_err("Invalid symbol type found");
err = PVA_INVAL; err = PVA_INVAL;
goto done; goto done;
@@ -403,10 +411,10 @@ done:
} }
/** /**
* The simplify caller's life: the input ptr should always be considered freed * The simplify caller's life: the input ptr should always be considered freed
* after this call. The returned new ptr should always be considered a new * after this call. The returned new ptr should always be considered a new
* allocation and it needs to be freed if not NULL. * allocation and it needs to be freed if not NULL.
*/ */
static void *pva_realloc(void *ptr, uint32_t old_size, uint32_t new_size) static void *pva_realloc(void *ptr, uint32_t old_size, uint32_t new_size)
{ {
void *new_buffer; void *new_buffer;
@@ -424,7 +432,7 @@ static void *pva_realloc(void *ptr, uint32_t old_size, uint32_t new_size)
goto out; goto out;
} }
memcpy(new_buffer, ptr, old_size); (void)memcpy(new_buffer, ptr, old_size);
out: out:
pva_kmd_free(ptr); pva_kmd_free(ptr);
@@ -439,6 +447,7 @@ static void *copy_text_section(const elf_parser_ctx elf,
uint32_t const *word; uint32_t const *word;
uint32_t *dst_word; uint32_t *dst_word;
uint32_t wi; uint32_t wi;
char *base;
/* The load address in section header is in words (uint32_t) */ /* The load address in section header is in words (uint32_t) */
uint32_t load_addr_bytes = uint32_t load_addr_bytes =
safe_mulu32(section_header->addr, (uint32_t)sizeof(uint32_t)); safe_mulu32(section_header->addr, (uint32_t)sizeof(uint32_t));
@@ -464,9 +473,14 @@ static void *copy_text_section(const elf_parser_ctx elf,
return NULL; return NULL;
} }
word = (uint32_t const *)elf_data; word = (uint32_t const *)(void const *)elf_data;
dst_word = (uint32_t *)((uintptr_t)out_buffer + load_addr_bytes); ASSERT(((uintptr_t)(void *)out_buffer % sizeof(uint32_t)) == 0U);
ASSERT((load_addr_bytes % sizeof(uint32_t)) == 0U);
/* Use byte pointer arithmetic to avoid INT36-C violation */
base = (char *)out_buffer;
dst_word = (uint32_t *)(void *)(base + load_addr_bytes);
for (wi = 0; wi < (section_header->size / sizeof(uint32_t)); wi++) { for (wi = 0; wi < (section_header->size / sizeof(uint32_t)); wi++) {
dst_word[wi] = change_byte_order(word[wi]); dst_word[wi] = change_byte_order(word[wi]);
} }
@@ -475,16 +489,16 @@ static void *copy_text_section(const elf_parser_ctx elf,
} }
/** /**
* @brief Aggregate all text sections into a single, dynamically * @brief Aggregate all text sections into a single, dynamically
* allocated buffer. * allocated buffer.
* *
* The placement of text sections needs to take into account of the loading * The placement of text sections needs to take into account of the loading
* addresses. * addresses.
* *
* The endianness of text section needs to be changed. * The endianness of text section needs to be changed.
* *
* Caller is responsible for freeing the returned buffer. * Caller is responsible for freeing the returned buffer.
*/ */
static void *aggregate_text_sections(const elf_parser_ctx elf, static void *aggregate_text_sections(const elf_parser_ctx elf,
uint32_t *out_size) uint32_t *out_size)
{ {
@@ -548,7 +562,7 @@ static void copy_data_section(const elf_parser_ctx elf,
ASSERT(elf_data != NULL); ASSERT(elf_data != NULL);
memcpy(dst, elf_data, section_header->size); (void)memcpy(dst, (const void *)elf_data, section_header->size);
*buffer_offset = safe_addu32(*buffer_offset, aligned_size); *buffer_offset = safe_addu32(*buffer_offset, aligned_size);
} }
@@ -601,14 +615,14 @@ out:
} }
/** /**
* @brief Aggregate all data sections into a single, dynamically * @brief Aggregate all data sections into a single, dynamically
* allocated buffer. * allocated buffer.
* *
* The offset of each data section must be aligned to DATA_SEGMENT_ALIGNMENT. * The offset of each data section must be aligned to DATA_SEGMENT_ALIGNMENT.
* *
* The caller must free the returned data buffer and out_section_infos. * The caller must free the returned data buffer and out_section_infos.
* *
*/ */
static void * static void *
aggregate_data_sections(const elf_parser_ctx elf, uint32_t n_data_sections, aggregate_data_sections(const elf_parser_ctx elf, uint32_t n_data_sections,
uint32_t total_sections_size, uint32_t total_sections_size,
@@ -664,12 +678,12 @@ err_out:
} }
/** /**
* @brief layout text and data sections in a single continuous buffer that is * @brief layout text and data sections in a single continuous buffer that is
* mapped to PVA IOVA space (user SID). * mapped to PVA IOVA space (user SID).
* *
* We need to pad text size by an entire VPU icache size to avoid SMMU fault * We need to pad text size by an entire VPU icache size to avoid SMMU fault
* when prefetching. * when prefetching.
*/ */
static struct pva_kmd_device_memory * static struct pva_kmd_device_memory *
load_sections(struct pva_kmd_device *pva, uint8_t smmu_id, load_sections(struct pva_kmd_device *pva, uint8_t smmu_id,
const void *text_section_buf, uint32_t text_size, const void *text_section_buf, uint32_t text_size,
@@ -683,19 +697,19 @@ load_sections(struct pva_kmd_device *pva, uint8_t smmu_id,
ASSERT(TEXT_SECTION_ALIGNMENT >= DATA_SECTION_ALIGNMENT); ASSERT(TEXT_SECTION_ALIGNMENT >= DATA_SECTION_ALIGNMENT);
/* This is guaranteed to be true as TEXT_SECTION_ALIGNMENT is more strict */ /* This is guaranteed to be true as TEXT_SECTION_ALIGNMENT is more strict */
ASSERT(data_begin % DATA_SECTION_ALIGNMENT == 0); ASSERT(data_begin % DATA_SECTION_ALIGNMENT == 0U);
/* Map it as read-only. TODO: when VPU debugger is supported, we may /* Map it as read-only. TODO: when VPU debugger is supported, we may
* need to map text as READ_WRITE conditionally. */ * need to map text as READ_WRITE conditionally. */
dev_mem = pva_kmd_device_memory_alloc_map(alloc_size, pva, dev_mem = pva_kmd_device_memory_alloc_map(alloc_size, pva,
PVA_ACCESS_RO, smmu_id); PVA_ACCESS_RO, smmu_id);
if (dev_mem == NULL) { if (dev_mem == NULL) {
goto out; goto out;
} }
memcpy(dev_mem->va, text_section_buf, text_size); (void)memcpy(dev_mem->va, text_section_buf, text_size);
memcpy(pva_offset_pointer(dev_mem->va, data_begin), data_section_buf, (void)memcpy(pva_offset_pointer(dev_mem->va, data_begin),
data_size); data_section_buf, data_size);
*out_data_begin_offset = data_begin; *out_data_begin_offset = data_begin;
out: out:
@@ -744,14 +758,17 @@ load_metainfo(struct pva_kmd_device *pva, uint64_t section_iova,
iova_hi(addu64(section_iova, data_begin_off, &math_err)); iova_hi(addu64(section_iova, data_begin_off, &math_err));
metainfo->data_section_addr_lo = metainfo->data_section_addr_lo =
iova_lo(addu64(section_iova, data_begin_off, &math_err)); iova_lo(addu64(section_iova, data_begin_off, &math_err));
metainfo->num_data_sections = n_data_sections; /* CERT INT31-C: n_data_sections is constrained by ELF structure,
* practically always fits in uint8_t, safe to cast */
metainfo->num_data_sections = (uint8_t)n_data_sections;
metainfo->num_vmem_buffers = n_symbols; metainfo->num_vmem_buffers = n_symbols;
data_sections_mem = pva_offset_pointer(metainfo, sizeof(*metainfo)); data_sections_mem = pva_offset_pointer(metainfo, sizeof(*metainfo));
if (n_data_sections > 0U && section_infos != NULL) { if (n_data_sections > 0U && section_infos != NULL) {
memcpy(data_sections_mem, section_infos, (void)memcpy(data_sections_mem, section_infos,
mulu32(n_data_sections, (uint32_t)sizeof(*section_infos), mulu32(n_data_sections,
&math_err)); (uint32_t)sizeof(*section_infos),
&math_err));
} }
vmem_buffers_mem = pva_offset_pointer( vmem_buffers_mem = pva_offset_pointer(
@@ -776,6 +793,77 @@ out:
return dev_mem; return dev_mem;
} }
/**
* Validate ELF, count symbols and allocate symbol table
*/
static enum pva_error
validate_and_prepare_symbols(elf_parser_ctx elf,
struct pva_kmd_exec_symbol_table *out_symbol_table)
{
enum pva_error err = PVA_SUCCESS;
pva_math_error math_err = MATH_OP_SUCCESS;
uint32_t num_symbols = 0;
err = validate_elf(elf);
if (err != PVA_SUCCESS) {
goto out;
}
err = count_symbols(elf, &num_symbols);
if (err != PVA_SUCCESS) {
goto out;
}
out_symbol_table->n_symbols = num_symbols;
if (num_symbols > 0U) {
out_symbol_table->symbols = pva_kmd_zalloc(
mulu32((uint32_t)sizeof(struct pva_symbol_info),
num_symbols, &math_err));
if (out_symbol_table->symbols == NULL) {
err = PVA_NOMEM;
goto out;
}
if (math_err != MATH_OP_SUCCESS) {
err = PVA_ERR_MATH_OP;
pva_kmd_log_err(
"pva_kmd_load_executable: validate_and_prepare_symbols math error");
}
}
out:
return err;
}
/**
* Process data sections and prepare data section buffer
*/
static enum pva_error
process_data_sections(elf_parser_ctx elf, uint32_t *n_data_sections,
uint32_t *total_data_section_size,
void **data_section_buf,
struct pva_fw_data_section_info **section_infos)
{
enum pva_error err = PVA_SUCCESS;
err = count_data_sections(elf, n_data_sections,
total_data_section_size);
if (err != PVA_SUCCESS) {
goto out;
}
/* It's OK to not have data sections */
if (*total_data_section_size != 0U) {
*data_section_buf =
aggregate_data_sections(elf, *n_data_sections,
*total_data_section_size,
section_infos);
ASSERT(*data_section_buf != NULL);
}
out:
return err;
}
enum pva_error enum pva_error
pva_kmd_load_executable(const void *executable_data, uint32_t executable_size, pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
struct pva_kmd_device *pva, uint8_t dma_smmu_id, struct pva_kmd_device *pva, uint8_t dma_smmu_id,
@@ -784,9 +872,7 @@ pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
struct pva_kmd_device_memory **out_sections) struct pva_kmd_device_memory **out_sections)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
pva_math_error math_err = MATH_OP_SUCCESS;
elf_parser_ctx elf = { 0 }; elf_parser_ctx elf = { 0 };
uint32_t num_symbols = 0;
uint32_t n_data_sections; uint32_t n_data_sections;
uint32_t total_data_section_size = 0; uint32_t total_data_section_size = 0;
struct pva_fw_data_section_info *section_infos = NULL; struct pva_fw_data_section_info *section_infos = NULL;
@@ -799,32 +885,12 @@ pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
elf.elf_file = executable_data; elf.elf_file = executable_data;
elf.size = executable_size; elf.size = executable_size;
err = validate_elf(elf);
err = validate_and_prepare_symbols(elf, out_symbol_table);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto err_out; goto err_out;
} }
err = count_symbols(elf, &num_symbols);
if (err != PVA_SUCCESS) {
goto err_out;
}
out_symbol_table->n_symbols = num_symbols;
if (num_symbols > 0) {
out_symbol_table->symbols = pva_kmd_zalloc(
mulu32((uint32_t)sizeof(struct pva_symbol_info),
num_symbols, &math_err));
if (out_symbol_table->symbols == NULL) {
err = PVA_NOMEM;
goto err_out;
}
if (math_err != MATH_OP_SUCCESS) {
err = PVA_ERR_MATH_OP;
pva_kmd_log_err("pva_kmd_load_executable math error");
goto err_out;
}
}
err = fill_symbol_table(elf, out_symbol_table, err = fill_symbol_table(elf, out_symbol_table,
pva->hw_consts.n_vmem_regions, pva->hw_consts.n_vmem_regions,
pva->vmem_regions_tab); pva->vmem_regions_tab);
@@ -837,25 +903,17 @@ pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
/* Must have text sections */ /* Must have text sections */
if (text_section_buf == NULL) { if (text_section_buf == NULL) {
pva_kmd_log_err( pva_kmd_log_err(
"pva_kmd_load_executable aggregate_text_sections error"); "pva_kmd_load_executable: aggregate_text_sections error");
goto free_syms; goto free_syms;
} }
err = count_data_sections(elf, &n_data_sections, err = process_data_sections(elf, &n_data_sections,
&total_data_section_size); &total_data_section_size, &data_section_buf,
&section_infos);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto free_text_buf; goto free_text_buf;
} }
/* It's OK to not have data sections */
if (total_data_section_size != 0) {
data_section_buf =
aggregate_data_sections(elf, n_data_sections,
total_data_section_size,
&section_infos);
ASSERT(data_section_buf != NULL);
}
sections_mem = load_sections(pva, dma_smmu_id, text_section_buf, sections_mem = load_sections(pva, dma_smmu_id, text_section_buf,
total_text_section_size, data_section_buf, total_text_section_size, data_section_buf,
total_data_section_size, &data_begin_off); total_data_section_size, &data_begin_off);
@@ -863,29 +921,23 @@ pva_kmd_load_executable(const void *executable_data, uint32_t executable_size,
goto free_data_buf; goto free_data_buf;
} }
metainfo_mem = metainfo_mem = load_metainfo(pva, sections_mem->iova,
load_metainfo(pva, sections_mem->iova, total_text_section_size, total_text_section_size, data_begin_off,
data_begin_off, total_data_section_size, total_data_section_size, section_infos,
section_infos, n_data_sections, n_data_sections, out_symbol_table->symbols,
out_symbol_table->symbols, num_symbols); out_symbol_table->n_symbols);
if (metainfo_mem == NULL) { if (metainfo_mem == NULL) {
goto free_sec_mem; goto free_sec_mem;
} }
/* Success. Now clean up temporary allocations */
if (data_section_buf != NULL) {
pva_kmd_free(data_section_buf);
}
if (section_infos != NULL) {
pva_kmd_free(section_infos);
}
pva_kmd_free(text_section_buf);
/* Success - set outputs and fall through to cleanup */
*out_metainfo = metainfo_mem; *out_metainfo = metainfo_mem;
*out_sections = sections_mem; *out_sections = sections_mem;
goto free_data_buf;
return PVA_SUCCESS;
free_sec_mem: free_sec_mem:
pva_kmd_device_memory_free(sections_mem); pva_kmd_device_memory_free(sections_mem);
free_data_buf: free_data_buf:
if (data_section_buf != NULL) { if (data_section_buf != NULL) {
pva_kmd_free(data_section_buf); pva_kmd_free(data_section_buf);
@@ -896,7 +948,9 @@ free_data_buf:
free_text_buf: free_text_buf:
pva_kmd_free(text_section_buf); pva_kmd_free(text_section_buf);
free_syms: free_syms:
pva_kmd_free(out_symbol_table->symbols); if (err != PVA_SUCCESS) {
pva_kmd_free(out_symbol_table->symbols);
}
err_out: err_out:
return err; return err;
} }

View File

@@ -16,19 +16,20 @@ int pva_kmd_hwpm_ip_reg_op(void *ip_dev, uint32_t reg_op,
{ {
struct pva_kmd_device *pva = ip_dev; struct pva_kmd_device *pva = ip_dev;
if (reg_offset > UINT32_MAX) if (reg_offset > U32_MAX)
return PVA_INVAL; return PVA_INVAL;
switch (reg_op) { switch (reg_op) {
case TEGRA_SOC_HWPM_IP_REG_OP_READ: case TEGRA_SOC_HWPM_IP_REG_OP_READ:
*reg_data = *reg_data =
pva_kmd_read(pva, safe_addu32(pva->regspec.cfg_perf_mon, pva_kmd_read(pva, safe_addu32(pva->regspec.cfg_perf_mon,
reg_offset)); (uint32_t)reg_offset));
break; break;
case TEGRA_SOC_HWPM_IP_REG_OP_WRITE: case TEGRA_SOC_HWPM_IP_REG_OP_WRITE:
pva_kmd_write( pva_kmd_write(pva,
pva, safe_addu32(pva->regspec.cfg_perf_mon, reg_offset), safe_addu32(pva->regspec.cfg_perf_mon,
*reg_data); (uint32_t)reg_offset),
*reg_data);
break; break;
default: default:
pva_kmd_log_err("Invalid HWPM operation"); pva_kmd_log_err("Invalid HWPM operation");

View File

@@ -1,42 +1,97 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ /* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_SILICON_HWPM_H #ifndef PVA_KMD_SILICON_HWPM_H
#define PVA_KMD_SILICON_HWPM_H #define PVA_KMD_SILICON_HWPM_H
#include "pva_kmd.h" #include "pva_kmd.h"
#include "pva_kmd_shim_debugfs.h" #include "pva_kmd_shim_debugfs.h"
#if PVA_ENABLE_HWPM == 1
/** /**
* @brief pva_hwpm_ip_pm * @brief PVA hardware performance monitoring power management control
* *
* This function called from Tegra HWPM driver to * @details This function is called from the Tegra HWPM (Hardware Performance
* poweron/off pva device. * Monitoring) driver to control the power state of the PVA device for
* * performance monitoring operations. It manages the power-on/power-off
* @param ip_dev Pointer to PVA device * sequence of the PVA device to enable or disable hardware performance
* @param disable disable/enable power management. PVA is * monitoring capabilities. When disable is false, the PVA device is powered
* powered on when false. * on to allow HWPM register access and monitoring operations.
* @param reg_offset offset of register relative to PVA HWP base *
* @return 0 on Success or negative error code * @param[in] ip_dev Pointer to PVA device instance
* * Valid value: typically @ref pva_kmd_device pointer
*/ * @param[in] disable Power management control flag
* Valid values:
* - true: Disable power management (power off PVA)
* - false: Enable power management (power on PVA)
*
* @retval 0 Power management operation completed successfully
* @retval -EINVAL Invalid device pointer or parameter
* @retval -ENODEV Device not available or not initialized
* @retval -ETIMEDOUT Timeout during power state transition
* @retval -EIO Hardware error during power management operation
*/
int pva_kmd_hwpm_ip_pm(void *ip_dev, bool disable); int pva_kmd_hwpm_ip_pm(void *ip_dev, bool disable);
/** /**
* @brief pva_hwpm_ip_reg_op * @brief PVA hardware performance monitoring register access operation
* *
* This function called from Tegra HWPM driver to * @details This function is called from the Tegra HWPM (Hardware Performance
* access PVA HWPM registers. * Monitoring) driver to perform read or write operations on PVA HWPM registers.
* * It provides controlled access to performance monitoring registers within the
* @param ip_dev Pointer to PVA device * PVA device, supporting both read and write operations. The function validates
* @param reg_op access operation and can be one of * the register offset, performs the requested operation, and manages data
* TEGRA_SOC_HWPM_IP_REG_OP_READ * transfer to/from the specified register location.
* TEGRA_SOC_HWPM_IP_REG_OP_WRITE *
* @param inst_element_index element index within PVA instance * @param[in] ip_dev Pointer to PVA device instance
* @param reg_offset offset of register relative to PVA HWP base * Valid value: typically @ref pva_kmd_device pointer
* @param reg_data pointer to where data is to be placed or read. * @param[in] reg_op Register operation type
* @return 0 on Success or negative error code * Valid values:
* * - TEGRA_SOC_HWPM_IP_REG_OP_READ: Read operation
*/ * - TEGRA_SOC_HWPM_IP_REG_OP_WRITE: Write operation
* @param[in] inst_element_index Element index within PVA instance
* Valid range: [0 .. PVA_MAX_ELEMENTS-1]
* @param[in] reg_offset Register offset relative to PVA HWPM base address
* Valid range: [0 .. PVA_HWPM_REGISTER_SPACE_SIZE-4]
* Must be 4-byte aligned
* @param[in,out] reg_data Pointer to register data
* For read: buffer to store read data (output)
* For write: buffer containing data to write (input)
* Valid value: non-null, must point to valid 32-bit storage
*
* @retval 0 Register operation completed successfully
* @retval -EINVAL Invalid device pointer, operation type, or register offset
* @retval -ENODEV Device not available or not initialized
* @retval -EACCES Access denied to specified register
* @retval -ETIMEDOUT Timeout during register access
* @retval -EIO Hardware error during register operation
*/
int pva_kmd_hwpm_ip_reg_op(void *ip_dev, uint32_t reg_op, int pva_kmd_hwpm_ip_reg_op(void *ip_dev, uint32_t reg_op,
uint32_t inst_element_index, uint64_t reg_offset, uint32_t inst_element_index, uint64_t reg_offset,
uint32_t *reg_data); uint32_t *reg_data);
#else /* PVA_ENABLE_HWPM */
/* Dummy inline functions when HWPM is disabled */
static inline int pva_kmd_hwpm_ip_pm(void *ip_dev, bool disable)
{
(void)ip_dev;
(void)disable;
return 0;
}
static inline int pva_kmd_hwpm_ip_reg_op(void *ip_dev, uint32_t reg_op,
uint32_t inst_element_index,
uint64_t reg_offset,
uint32_t *reg_data)
{
(void)ip_dev;
(void)reg_op;
(void)inst_element_index;
(void)reg_offset;
(void)reg_data;
return -1; /* Return error to indicate HWPM not supported */
}
#endif /* PVA_ENABLE_HWPM */
#endif //PVA_KMD_SILICON_HWPM_H #endif //PVA_KMD_SILICON_HWPM_H

View File

@@ -6,6 +6,7 @@
#include "pva_fw_hyp.h" #include "pva_fw_hyp.h"
#include "pva_kmd_msg.h" #include "pva_kmd_msg.h"
#include "pva_kmd_abort.h" #include "pva_kmd_abort.h"
#include "pva_kmd_limits.h"
struct pva_fw_msg { struct pva_fw_msg {
uint8_t len; uint8_t len;
@@ -20,9 +21,9 @@ static void read_hyp_msg(struct pva_kmd_device *pva, struct pva_fw_msg *msg)
msg->len = PVA_EXTRACT(msg->data[0], PVA_FW_MSG_LEN_MSB, msg->len = PVA_EXTRACT(msg->data[0], PVA_FW_MSG_LEN_MSB,
PVA_FW_MSG_LEN_LSB, uint8_t); PVA_FW_MSG_LEN_LSB, uint8_t);
ASSERT(msg->len <= PVA_ARRAY_SIZE(msg->data)); ASSERT(msg->len <= PVA_ARRAY_SIZE(msg->data));
for (i = 1; i < msg->len; i++) { for (i = 1U; i < msg->len; i++) {
msg->data[i] = pva_kmd_read_mailbox( msg->data[i] = pva_kmd_read_mailbox(
pva, PVA_FW_MBOX_TO_HYP_BASE + i - 1); pva, PVA_FW_MBOX_TO_HYP_BASE + i - 1U);
} }
} }
@@ -43,21 +44,21 @@ void pva_kmd_hyp_isr(void *data, enum pva_kmd_intr_line intr_line)
h1x_val = PVA_EXTRACT(intr_status, PVA_REG_SEC_LIC_INTR_H1X_MSB, h1x_val = PVA_EXTRACT(intr_status, PVA_REG_SEC_LIC_INTR_H1X_MSB,
PVA_REG_SEC_LIC_INTR_H1X_LSB, uint32_t); PVA_REG_SEC_LIC_INTR_H1X_LSB, uint32_t);
if (wdt_val != 0) { if (wdt_val != 0U) {
/* Clear interrupt status */ /* Clear interrupt status */
pva_kmd_write(pva, pva->regspec.sec_lic_intr_status, wdt_val); pva_kmd_write(pva, pva->regspec.sec_lic_intr_status, wdt_val);
pva_kmd_log_err("PVA watchdog timeout!"); pva_kmd_log_err("PVA watchdog timeout!");
pva_kmd_abort_fw(pva, PVA_ERR_WDT_TIMEOUT); pva_kmd_abort_fw(pva, PVA_ERR_WDT_TIMEOUT);
} }
if (h1x_val != 0) { if (h1x_val != 0U) {
pva_kmd_log_err_u64("Host1x errors", h1x_val); pva_kmd_log_err_u64("Host1x errors", h1x_val);
/* Clear interrupt status */ /* Clear interrupt status */
pva_kmd_write(pva, pva->regspec.sec_lic_intr_status, h1x_val); pva_kmd_write(pva, pva->regspec.sec_lic_intr_status, h1x_val);
pva_kmd_abort_fw(pva, PVA_ERR_HOST1X_ERR); pva_kmd_abort_fw(pva, PVA_ERR_HOST1X_ERR);
} }
if (hsp_val != 0) { if (hsp_val != 0U) {
struct pva_fw_msg msg = { 0 }; struct pva_fw_msg msg = { 0 };
read_hyp_msg(pva, &msg); read_hyp_msg(pva, &msg);
@@ -90,7 +91,15 @@ void pva_kmd_isr(void *data, enum pva_kmd_intr_line intr_line)
{ {
struct pva_kmd_device *pva = data; struct pva_kmd_device *pva = data;
uint32_t intr_status; uint32_t intr_status;
uint8_t intr_interface = intr_line - PVA_KMD_INTR_LINE_CCQ0; uint8_t intr_interface;
/* Convert interrupt line to interface index (CCQ0=1 -> interface=0, etc.) */
if (intr_line >= PVA_KMD_INTR_LINE_CCQ0) {
intr_interface = (uint8_t)((uint8_t)intr_line -
(uint8_t)PVA_KMD_INTR_LINE_CCQ0);
} else {
intr_interface = 0U; /* Fallback for invalid input */
}
intr_status = read_ccq_status(pva, intr_interface, 2) & intr_status = read_ccq_status(pva, intr_interface, 2) &
PVA_REG_CCQ_STATUS2_INTR_ALL_BITS; PVA_REG_CCQ_STATUS2_INTR_ALL_BITS;
@@ -100,7 +109,7 @@ void pva_kmd_isr(void *data, enum pva_kmd_intr_line intr_line)
*/ */
write_ccq_status(pva, intr_interface, 2, intr_status); write_ccq_status(pva, intr_interface, 2, intr_status);
if (intr_status & PVA_REG_CCQ_STATUS2_INTR_STATUS8_BIT) { if ((intr_status & PVA_REG_CCQ_STATUS2_INTR_STATUS8_BIT) != 0U) {
pva_kmd_shared_buffer_process(pva, intr_interface); pva_kmd_shared_buffer_process(pva, intr_interface);
} }
} }
@@ -109,12 +118,16 @@ enum pva_error pva_kmd_bind_shared_buffer_handler(void *pva_dev,
uint8_t interface, void *data) uint8_t interface, void *data)
{ {
struct pva_kmd_device *pva = (struct pva_kmd_device *)pva_dev; struct pva_kmd_device *pva = (struct pva_kmd_device *)pva_dev;
uint8_t base_line = (uint8_t)PVA_KMD_INTR_LINE_CCQ0;
uint8_t target_line = safe_addu8(base_line, interface);
return pva_kmd_bind_intr_handler( return pva_kmd_bind_intr_handler(
pva, PVA_KMD_INTR_LINE_CCQ0 + interface, pva_kmd_isr, data); pva, (enum pva_kmd_intr_line)target_line, pva_kmd_isr, data);
} }
void pva_kmd_release_shared_buffer_handler(void *pva_dev, uint8_t interface) void pva_kmd_release_shared_buffer_handler(void *pva_dev, uint8_t interface)
{ {
struct pva_kmd_device *pva = (struct pva_kmd_device *)pva_dev; struct pva_kmd_device *pva = (struct pva_kmd_device *)pva_dev;
pva_kmd_free_intr(pva, PVA_KMD_INTR_LINE_CCQ0 + interface); uint8_t base_line = (uint8_t)PVA_KMD_INTR_LINE_CCQ0;
uint8_t target_line = safe_addu8(base_line, interface);
pva_kmd_free_intr(pva, (enum pva_kmd_intr_line)target_line);
} }

View File

@@ -1,13 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ /* SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_SILICON_ISR_H #ifndef PVA_KMD_SILICON_ISR_H
#define PVA_KMD_SILICON_ISR_H #define PVA_KMD_SILICON_ISR_H
#include "pva_kmd_silicon_utils.h" #include "pva_kmd_silicon_utils.h"
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
/**
* @brief Hypervisor interrupt service routine for PVA device
*
* @details This function handles hypervisor-level interrupts from the PVA
* device. It processes interrupts that require hypervisor privileges and
* performs necessary actions such as error handling, security validation,
* and inter-VM communication. The function identifies the interrupt source
* and dispatches appropriate handling routines based on the interrupt line.
*
* @param[in] data Pointer to device-specific data context
* Valid value: typically @ref pva_kmd_device pointer
* @param[in] intr_line Interrupt line that triggered the handler
* Valid values: @ref pva_kmd_intr_line enumeration values
*/
void pva_kmd_hyp_isr(void *data, enum pva_kmd_intr_line intr_line); void pva_kmd_hyp_isr(void *data, enum pva_kmd_intr_line intr_line);
/* CCQ interrupt handler */ /**
* @brief Main interrupt service routine for PVA device
*
* @details This function serves as the primary interrupt handler for PVA
* device interrupts, particularly handling CCQ (Command and Control Queue)
* interrupts and other device-level events. It processes hardware interrupts,
* identifies the interrupt source, performs necessary acknowledgment, and
* dispatches appropriate handling routines. The function ensures proper
* interrupt handling and maintains device state consistency.
*
* @param[in] data Pointer to device-specific data context
* Valid value: typically @ref pva_kmd_device pointer
* @param[in] intr_line Interrupt line that triggered the handler
* Valid values: @ref pva_kmd_intr_line enumeration values
*/
void pva_kmd_isr(void *data, enum pva_kmd_intr_line intr_line); void pva_kmd_isr(void *data, enum pva_kmd_intr_line intr_line);
#endif // PVA_KMD_SILICON_ISR_H #endif // PVA_KMD_SILICON_ISR_H

View File

@@ -23,7 +23,7 @@ uint32_t pva_kmd_get_ccq_space(struct pva_kmd_device *pva, uint8_t ccq_id)
void pva_kmd_disable_all_interrupts_nosync(struct pva_kmd_device *pva) void pva_kmd_disable_all_interrupts_nosync(struct pva_kmd_device *pva)
{ {
for (int i = 0; i < PVA_KMD_INTR_LINE_COUNT; i++) { for (uint8_t i = 0; i < (uint8_t)PVA_KMD_INTR_LINE_COUNT; i++) {
pva_kmd_disable_intr_nosync(pva, (enum pva_kmd_intr_line)i); pva_kmd_disable_intr_nosync(pva, (enum pva_kmd_intr_line)i);
} }
} }

View File

@@ -8,6 +8,21 @@
#include "pva_kmd_shim_silicon.h" #include "pva_kmd_shim_silicon.h"
#include "pva_math_utils.h" #include "pva_math_utils.h"
/**
* @brief Write a 32-bit value to PVA device register
*
* @details This inline function writes a 32-bit value to a register within the
* PVA device address space. It uses the PVA cluster aperture for register
* access and includes debug logging for register write operations. The function
* provides a convenient interface for writing to PVA hardware registers.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] addr Register address offset within PVA address space
* Valid range: [0 .. PVA_REGISTER_SPACE_SIZE-1]
* @param[in] val 32-bit value to write to the register
* Valid range: [0 .. UINT32_MAX]
*/
static inline void pva_kmd_write(struct pva_kmd_device *pva, uint32_t addr, static inline void pva_kmd_write(struct pva_kmd_device *pva, uint32_t addr,
uint32_t val) uint32_t val)
{ {
@@ -15,6 +30,23 @@ static inline void pva_kmd_write(struct pva_kmd_device *pva, uint32_t addr,
pva_kmd_aperture_write(pva, PVA_KMD_APERTURE_PVA_CLUSTER, addr, val); pva_kmd_aperture_write(pva, PVA_KMD_APERTURE_PVA_CLUSTER, addr, val);
} }
/**
* @brief Read a 32-bit value from PVA device register
*
* @details This inline function reads a 32-bit value from a register within
* the PVA device address space. It uses the PVA cluster aperture for register
* access and returns the value read from the specified register address. The
* function provides a convenient interface for reading from PVA hardware
* registers.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] addr Register address offset within PVA address space
* Valid range: [0 .. PVA_REGISTER_SPACE_SIZE-1]
*
* @retval uint32_t Value read from the register
* Valid range: [0 .. UINT32_MAX]
*/
static inline uint32_t pva_kmd_read(struct pva_kmd_device *pva, uint32_t addr) static inline uint32_t pva_kmd_read(struct pva_kmd_device *pva, uint32_t addr)
{ {
uint32_t val; uint32_t val;
@@ -23,6 +55,22 @@ static inline uint32_t pva_kmd_read(struct pva_kmd_device *pva, uint32_t addr)
return val; return val;
} }
/**
* @brief Write a value to HSP shared mailbox register
*
* @details This inline function writes a value to a specific HSP (Hardware
* Synchronization Primitive) shared mailbox register. It calculates the
* appropriate register address based on the mailbox index and writes the
* value to the corresponding mailbox register. Mailboxes are used for
* communication between different processing units.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] mailbox_idx Index of the mailbox to write to
* Valid range: [0 .. MAX_MAILBOX_COUNT-1]
* @param[in] val 32-bit value to write to the mailbox
* Valid range: [0 .. UINT32_MAX]
*/
static inline void pva_kmd_write_mailbox(struct pva_kmd_device *pva, static inline void pva_kmd_write_mailbox(struct pva_kmd_device *pva,
uint32_t mailbox_idx, uint32_t val) uint32_t mailbox_idx, uint32_t val)
{ {
@@ -32,6 +80,23 @@ static inline void pva_kmd_write_mailbox(struct pva_kmd_device *pva,
pva_kmd_write(pva, addr, val); pva_kmd_write(pva, addr, val);
} }
/**
* @brief Read a value from HSP shared mailbox register
*
* @details This inline function reads a value from a specific HSP (Hardware
* Synchronization Primitive) shared mailbox register. It calculates the
* appropriate register address based on the mailbox index and reads the
* value from the corresponding mailbox register. Mailboxes are used for
* communication between different processing units.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
* @param[in] mailbox_idx Index of the mailbox to read from
* Valid range: [0 .. MAX_MAILBOX_COUNT-1]
*
* @retval uint32_t Value read from the mailbox register
* Valid range: [0 .. UINT32_MAX]
*/
static inline uint32_t pva_kmd_read_mailbox(struct pva_kmd_device *pva, static inline uint32_t pva_kmd_read_mailbox(struct pva_kmd_device *pva,
uint32_t mailbox_idx) uint32_t mailbox_idx)
{ {

View File

@@ -5,6 +5,7 @@
#include "pva_api_types.h" #include "pva_api_types.h"
#include "pva_kmd_utils.h" #include "pva_kmd_utils.h"
#include "pva_kmd_abort.h" #include "pva_kmd_abort.h"
#include "pva_kmd_limits.h"
void pva_kmd_submitter_init(struct pva_kmd_submitter *submitter, void pva_kmd_submitter_init(struct pva_kmd_submitter *submitter,
struct pva_kmd_queue *queue, struct pva_kmd_queue *queue,
@@ -150,7 +151,7 @@ enum pva_error pva_kmd_submitter_wait(struct pva_kmd_submitter *submitter,
} }
#endif #endif
while (*fence_addr < fence_val) { while (*fence_addr < fence_val) {
if (pva->recovery) { if (pva->fw_aborted) {
return PVA_ERR_FW_ABORTED; return PVA_ERR_FW_ABORTED;
} }
pva_kmd_sleep_us(poll_interval_us); pva_kmd_sleep_us(poll_interval_us);
@@ -180,7 +181,13 @@ enum pva_error pva_kmd_submit_cmd_sync(struct pva_kmd_submitter *submitter,
goto err_out; goto err_out;
} }
cmd_dst = pva_kmd_reserve_cmd_space(&builder, size); /* Validate that size fits in uint16_t before casting */
if (size > (uint64_t)U16_MAX) {
pva_kmd_log_err("Command size exceeds UINT16_MAX");
err = PVA_INVAL;
goto cancel_builder;
}
cmd_dst = pva_kmd_reserve_cmd_space(&builder, (uint16_t)size);
if (cmd_dst == NULL) { if (cmd_dst == NULL) {
err = PVA_INVAL; err = PVA_INVAL;
pva_kmd_log_err( pva_kmd_log_err(
@@ -188,7 +195,7 @@ enum pva_error pva_kmd_submit_cmd_sync(struct pva_kmd_submitter *submitter,
goto cancel_builder; goto cancel_builder;
} }
memcpy(cmd_dst, cmds, size); (void)memcpy(cmd_dst, cmds, size);
err = pva_kmd_submitter_submit(submitter, &builder, &fence_val); err = pva_kmd_submitter_submit(submitter, &builder, &fence_val);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
goto cancel_builder; goto cancel_builder;

View File

@@ -7,21 +7,88 @@
#include "pva_kmd_mutex.h" #include "pva_kmd_mutex.h"
#include "pva_kmd_queue.h" #include "pva_kmd_queue.h"
/** A thread-safe submitter utility */ /**
* @brief Thread-safe command buffer submission utility
*
* @details This structure provides a thread-safe interface for submitting
* command buffers to PVA queues. It manages submission synchronization,
* fence handling, and command buffer chunk allocation to ensure safe
* concurrent access from multiple threads while maintaining proper
* ordering and completion tracking.
*/
struct pva_kmd_submitter { struct pva_kmd_submitter {
/** The lock protects the submission to the queue, including /**
* incrementing the post fence */ * @brief Lock protecting submission operations and post fence increment
*
* @details The lock protects the submission to the queue, including
* incrementing the post fence
*/
pva_kmd_mutex_t *submit_lock; pva_kmd_mutex_t *submit_lock;
/**
* @brief Pointer to the target queue for submissions
*/
struct pva_kmd_queue *queue; struct pva_kmd_queue *queue;
/**
* @brief Virtual address of post fence value in memory
*/
uint32_t *post_fence_va; uint32_t *post_fence_va;
/**
* @brief Post fence configuration for submission completion tracking
*/
struct pva_fw_postfence post_fence; struct pva_fw_postfence post_fence;
/**
* @brief Next fence value to be assigned to submissions
* Valid range: [0 .. UINT32_MAX]
*/
uint32_t fence_future_value; uint32_t fence_future_value;
/** This lock protects the use of the chunk_pool*/ /**
* @brief Lock protecting chunk pool operations
*
* @details This lock protects the use of the chunk_pool
*/
pva_kmd_mutex_t *chunk_pool_lock; pva_kmd_mutex_t *chunk_pool_lock;
/**
* @brief Pointer to command buffer chunk pool for allocation
*/
struct pva_kmd_cmdbuf_chunk_pool *chunk_pool; struct pva_kmd_cmdbuf_chunk_pool *chunk_pool;
}; };
/**
* @brief Initialize a PVA command buffer submitter
*
* @details This function performs the following operations:
* - Initializes all fields of the submitter structure with provided parameters
* - Associates the submitter with the specified queue and synchronization primitives
* - Sets up fence management using the provided post fence configuration
* - Configures command buffer chunk allocation through the provided chunk pool
* - Prepares the submitter for thread-safe command buffer submissions
* - Establishes proper locking mechanisms for concurrent operation
*
* The submitter structure must be allocated before calling this function.
* After initialization, the submitter is ready for command buffer preparation
* and submission operations using the other submitter functions.
*
* @param[out] submitter Pointer to @ref pva_kmd_submitter structure to initialize
* Valid value: non-null
* @param[in] queue Pointer to target @ref pva_kmd_queue for submissions
* Valid value: non-null, must be initialized
* @param[in] submit_lock Pointer to mutex for submission synchronization
* Valid value: non-null, must be initialized
* @param[in] chunk_pool Pointer to command buffer chunk pool
* Valid value: non-null, must be initialized
* @param[in] chunk_pool_lock Pointer to mutex for chunk pool synchronization
* Valid value: non-null, must be initialized
* @param[in] post_fence_va Virtual address of post fence memory location
* Valid value: non-null
* @param[in] post_fence Pointer to post fence configuration
* Valid value: non-null
*/
void pva_kmd_submitter_init(struct pva_kmd_submitter *submitter, void pva_kmd_submitter_init(struct pva_kmd_submitter *submitter,
struct pva_kmd_queue *queue, struct pva_kmd_queue *queue,
pva_kmd_mutex_t *submit_lock, pva_kmd_mutex_t *submit_lock,
@@ -30,35 +97,168 @@ void pva_kmd_submitter_init(struct pva_kmd_submitter *submitter,
uint32_t *post_fence_va, uint32_t *post_fence_va,
struct pva_fw_postfence const *post_fence); struct pva_fw_postfence const *post_fence);
/**
* @brief Prepare a command buffer builder for submission
*
* @details This function performs the following operations:
* - Acquires the chunk pool lock for thread-safe chunk allocation
* - Allocates command buffer chunks from the submitter's chunk pool
* - Initializes the command buffer builder with allocated chunks
* - Sets up the builder for command construction and submission
* - Configures chunk linking and memory management for the builder
* - Releases the chunk pool lock after successful preparation
*
* The prepared builder can be used to construct command sequences using
* the command buffer builder API. After command construction is complete,
* the builder should be submitted using @ref pva_kmd_submitter_submit().
*
* @param[in, out] submitter Pointer to @ref pva_kmd_submitter structure
* Valid value: non-null, must be initialized
* @param[out] builder Pointer to @ref pva_kmd_cmdbuf_builder to prepare
* Valid value: non-null
*
* @retval PVA_SUCCESS Builder prepared successfully
* @retval PVA_NOMEM Failed to allocate command buffer chunks
* @retval PVA_ENOSPC Chunk pool has no available chunks
*/
enum pva_error enum pva_error
pva_kmd_submitter_prepare(struct pva_kmd_submitter *submitter, pva_kmd_submitter_prepare(struct pva_kmd_submitter *submitter,
struct pva_kmd_cmdbuf_builder *builder); struct pva_kmd_cmdbuf_builder *builder);
/**
* @brief Submit a prepared command buffer to the queue
*
* @details This function performs the following operations:
* - Acquires the submission lock for thread-safe queue operations
* - Finalizes the command buffer and prepares submission information
* - Assigns a unique fence value for completion tracking
* - Submits the command buffer to the associated queue using @ref pva_kmd_queue_submit()
* - Updates the post fence future value for subsequent submissions
* - Returns the assigned fence value to the caller for synchronization
* - Releases the submission lock after successful submission
*
* The command buffer builder must be properly prepared using
* @ref pva_kmd_submitter_prepare() and populated with commands before
* calling this function. The returned fence value can be used with
* @ref pva_kmd_submitter_wait() to synchronize on completion.
*
* @param[in, out] submitter Pointer to @ref pva_kmd_submitter structure
* Valid value: non-null, must be initialized
* @param[in, out] builder Pointer to prepared @ref pva_kmd_cmdbuf_builder
* Valid value: non-null, must be prepared
* @param[out] out_fence_val Pointer to store the assigned fence value
* Valid value: non-null
*
* @retval PVA_SUCCESS Submission completed successfully
* @retval PVA_INVAL Invalid submitter or builder parameters
* @retval PVA_QUEUE_FULL Target queue has no space for submission
* @retval PVA_TIMEDOUT Failed to notify firmware of submission
*/
enum pva_error pva_kmd_submitter_submit(struct pva_kmd_submitter *submitter, enum pva_error pva_kmd_submitter_submit(struct pva_kmd_submitter *submitter,
struct pva_kmd_cmdbuf_builder *builder, struct pva_kmd_cmdbuf_builder *builder,
uint32_t *out_fence_val); uint32_t *out_fence_val);
/**
* @brief Wait for a submitted command buffer to complete
*
* @details This function performs the following operations:
* - Polls the post fence memory location for the specified fence value
* - Uses configurable polling intervals to balance CPU usage and latency
* - Implements timeout mechanisms to prevent indefinite blocking
* - Checks for fence value completion using memory-mapped reads
* - Returns success when the fence value is reached or timeout on failure
* - Provides blocking synchronization for submitted command buffers
*
* The fence value must be obtained from a previous call to
* @ref pva_kmd_submitter_submit(). The function will block until the
* command buffer associated with the fence value completes execution
* or the timeout period expires.
*
* @param[in] submitter Pointer to @ref pva_kmd_submitter structure
* Valid value: non-null, must be initialized
* @param[in] fence_val Fence value to wait for completion
* Valid range: [0 .. UINT32_MAX]
* @param[in] poll_interval_ms Polling interval in milliseconds
* Valid range: [1 .. UINT32_MAX]
* @param[in] timeout_ms Timeout period in milliseconds
* Valid range: [1 .. UINT32_MAX]
*
* @retval PVA_SUCCESS Fence value reached, command buffer completed
* @retval PVA_TIMEDOUT Timeout expired before fence value reached
*/
enum pva_error pva_kmd_submitter_wait(struct pva_kmd_submitter *submitter, enum pva_error pva_kmd_submitter_wait(struct pva_kmd_submitter *submitter,
uint32_t fence_val, uint32_t fence_val,
uint32_t poll_interval_ms, uint32_t poll_interval_ms,
uint32_t timeout_ms); uint32_t timeout_ms);
/**
* @brief Submit a command buffer with custom fence configuration
*
* @details This function performs the following operations:
* - Acquires the submission lock for thread-safe queue operations
* - Finalizes the command buffer using the provided custom fence configuration
* - Submits the command buffer to the associated queue with custom fence
* - Uses the provided fence instead of the submitter's default post fence
* - Enables custom synchronization mechanisms for specialized use cases
* - Releases the submission lock after successful submission
*
* This function allows for custom fence configurations that may differ
* from the submitter's default post fence. The custom fence can specify
* different syncpoint targets, fence values, or synchronization behavior
* for specialized submission requirements.
*
* @param[in, out] submitter Pointer to @ref pva_kmd_submitter structure
* Valid value: non-null, must be initialized
* @param[in, out] builder Pointer to prepared @ref pva_kmd_cmdbuf_builder
* Valid value: non-null, must be prepared
* @param[in] fence Pointer to custom @ref pva_fw_postfence configuration
* Valid value: non-null
*
* @retval PVA_SUCCESS Submission completed successfully
* @retval PVA_INVAL Invalid submitter, builder, or fence parameters
* @retval PVA_QUEUE_FULL Target queue has no space for submission
* @retval PVA_TIMEDOUT Failed to notify firmware of submission
*/
enum pva_error enum pva_error
pva_kmd_submitter_submit_with_fence(struct pva_kmd_submitter *submitter, pva_kmd_submitter_submit_with_fence(struct pva_kmd_submitter *submitter,
struct pva_kmd_cmdbuf_builder *builder, struct pva_kmd_cmdbuf_builder *builder,
struct pva_fw_postfence *fence); struct pva_fw_postfence *fence);
/* prepare submission */ /**
/* add cmd */ * @brief Submit commands synchronously and wait for completion
/* add cmd */ *
/* do submit -> fence value */ * @details This function performs the following operations:
/* wait for fence */ * - Prepares a command buffer builder with chunk allocation
* - Reserves space in the command buffer for the provided commands
/* prepare submission */ * - Copies the command data into the reserved buffer space
/* add cmd */ * - Submits the command buffer to the firmware via the queue
/* add cmd */ * - Waits for command execution to complete using fence synchronization
/* do submit with fence (provide a fence) */ * - Automatically cleans up allocated chunks upon completion or error
* - Provides a simplified interface for single-shot command submission
/* Helper function to submit several commands and wait for them to complete. *
Total size must be smaller than a chunk. */ * This is a convenience function that combines command buffer preparation,
* submission, and synchronous waiting into a single operation. The total
* command size must fit within a single chunk. For larger command sequences
* or asynchronous operation, use the individual submitter functions.
*
* @param[in] submitter Pointer to @ref pva_kmd_submitter structure
* Valid value: non-null, must be initialized
* @param[in] cmds Pointer to command data to submit
* Valid value: non-null
* @param[in] size Size of command data in bytes
* Valid range: [1 .. chunk_size]
* @param[in] poll_interval_us Polling interval for fence checking in microseconds
* Valid range: [1 .. UINT32_MAX]
* @param[in] timeout_us Maximum timeout for command completion in microseconds
* Valid range: [poll_interval_us .. UINT32_MAX]
*
* @retval PVA_SUCCESS Commands submitted and completed successfully
* @retval PVA_NOMEM Failed to allocate command buffer chunk
* @retval PVA_INVAL Command size exceeds chunk capacity
* @retval PVA_QUEUE_FULL Submission queue has no space available
* @retval PVA_TIMEDOUT Command execution or submission timed out
* @retval PVA_ERR_FW_ABORTED Firmware operation aborted during wait
*/
enum pva_error pva_kmd_submit_cmd_sync(struct pva_kmd_submitter *submitter, enum pva_error pva_kmd_submit_cmd_sync(struct pva_kmd_submitter *submitter,
void *cmds, uint32_t size, void *cmds, uint32_t size,
uint32_t poll_interval_us, uint32_t poll_interval_us,

View File

@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_t23x.h" #include "pva_kmd_t23x.h"
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_kmd_pfsd.h"
struct vmem_region vmem_regions_tab_t23x[PVA_VMEM_REGION_COUNT_T23X] = { struct vmem_region vmem_regions_tab_t23x[PVA_VMEM_REGION_COUNT_T23X] = {
{ .start = T23x_VMEM0_START, .end = T23x_VMEM0_END }, { .start = T23x_VMEM0_START, .end = T23x_VMEM0_END },
@@ -16,7 +17,7 @@ void pva_kmd_device_init_t23x(struct pva_kmd_device *pva)
pva->hw_consts.hw_gen = PVA_HW_GEN2; pva->hw_consts.hw_gen = PVA_HW_GEN2;
pva->hw_consts.n_smmu_contexts = PVA_NUM_SMMU_CONTEXTS_T23X; pva->hw_consts.n_smmu_contexts = PVA_NUM_SMMU_CONTEXTS_T23X;
pva->r5_image_smmu_context_id = PVA_NUM_SMMU_CONTEXTS_T23X - 1; pva->r5_image_smmu_context_id = PVA_NUM_SMMU_CONTEXTS_T23X - 1U;
pva->hw_consts.n_dma_descriptors = PVA_NUM_DMA_DESC_T23X; pva->hw_consts.n_dma_descriptors = PVA_NUM_DMA_DESC_T23X;
pva->hw_consts.n_user_dma_channels = PVA_DMA_NUM_CHANNELS_T23X - 1U; pva->hw_consts.n_user_dma_channels = PVA_DMA_NUM_CHANNELS_T23X - 1U;
pva->hw_consts.n_hwseq_words = PVA_NUM_HWSEQ_WORDS_T23X; pva->hw_consts.n_hwseq_words = PVA_NUM_HWSEQ_WORDS_T23X;
@@ -29,8 +30,10 @@ void pva_kmd_device_init_t23x(struct pva_kmd_device *pva)
PVA_KMD_PVA0_T23x_REG_BASE; PVA_KMD_PVA0_T23x_REG_BASE;
pva->reg_size[PVA_KMD_APERTURE_PVA_CLUSTER] = pva->reg_size[PVA_KMD_APERTURE_PVA_CLUSTER] =
PVA_KMD_PVA0_T23x_REG_SIZE; PVA_KMD_PVA0_T23x_REG_SIZE;
pva->reg_phy_base[PVA_KMD_APERTURE_VPU_DEBUG] = TEGRA_PVA0_VPU_DBG_BASE; pva->reg_phy_base[PVA_KMD_APERTURE_VPU_DEBUG] =
pva->reg_size[PVA_KMD_APERTURE_VPU_DEBUG] = TEGRA_PVA0_VPU_DBG_SIZE; TEGRA_PVA0_VPU_DBG_BASE_T23X;
pva->reg_size[PVA_KMD_APERTURE_VPU_DEBUG] =
TEGRA_PVA0_VPU_DBG_SIZE_T23X;
pva->regspec.sec_lic_intr_enable = 0x28064; pva->regspec.sec_lic_intr_enable = 0x28064;
pva->regspec.sec_lic_intr_status = 0x2806C; pva->regspec.sec_lic_intr_status = 0x2806C;
@@ -80,4 +83,11 @@ void pva_kmd_device_init_t23x(struct pva_kmd_device *pva)
#endif #endif
pva->tsc_to_ns_multiplier = PVA_NS_PER_TSC_TICK_T23X; pva->tsc_to_ns_multiplier = PVA_NS_PER_TSC_TICK_T23X;
pva->pfsd_info.vpu_elf_data = pva_pfsd_vpu_elf_t23x;
pva->pfsd_info.vpu_elf_size = PVA_ALIGN8(PVA_PFSD_VPU_ELF_SIZE_T23X);
pva->pfsd_info.ppe_elf_data = NULL;
pva->pfsd_info.ppe_elf_size = 0;
pva->pfsd_info.pfsd_dma_cfg = pfsd_dma_cfg_t23x;
pva->pfsd_info.register_cmd_buffer = &pva_kmd_pfsd_t23x_register_cmdbuf;
} }

View File

@@ -5,27 +5,106 @@
#define PVA_KMD_T23X_H #define PVA_KMD_T23X_H
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
/** Number of VMEM regions */ /**
* @brief Number of VMEM regions available in T23X platform
*
* @details Defines the total number of Vector Memory (VMEM) regions available
* in the T23X Tegra platform. VMEM regions are fast on-chip memory banks used
* by VPU for data processing operations.
*/
#define PVA_VMEM_REGION_COUNT_T23X 3U #define PVA_VMEM_REGION_COUNT_T23X 3U
/** Start Address of VMEM0 Bank in T23X */ /**
* @brief Start address of VMEM0 bank in T23X platform
*
* @details Base address of the first Vector Memory bank (VMEM0) in T23X Tegra
* platform. This region provides fast access memory for VPU operations.
* Value: 0x40 (64 bytes offset)
*/
#define T23x_VMEM0_START 0x40U #define T23x_VMEM0_START 0x40U
/** End Address of VMEM0 Bank in T23X */
/**
* @brief End address of VMEM0 bank in T23X platform
*
* @details End address (exclusive) of the first Vector Memory bank (VMEM0) in
* T23X Tegra platform. The usable range is from T23x_VMEM0_START to
* (T23x_VMEM0_END - 1).
* Value: 0x20000 (128KB)
*/
#define T23x_VMEM0_END 0x20000U #define T23x_VMEM0_END 0x20000U
/** Start Address of VMEM1 Bank in T23X */
/**
* @brief Start address of VMEM1 bank in T23X platform
*
* @details Base address of the second Vector Memory bank (VMEM1) in T23X Tegra
* platform. This region provides additional fast access memory for VPU
* operations.
* Value: 0x40000 (256KB offset)
*/
#define T23x_VMEM1_START 0x40000U #define T23x_VMEM1_START 0x40000U
/** End Address of VMEM1 Bank in T23X */
/**
* @brief End address of VMEM1 bank in T23X platform
*
* @details End address (exclusive) of the second Vector Memory bank (VMEM1) in
* T23X Tegra platform. The usable range is from T23x_VMEM1_START to
* (T23x_VMEM1_END - 1).
* Value: 0x60000 (384KB)
*/
#define T23x_VMEM1_END 0x60000U #define T23x_VMEM1_END 0x60000U
/** Start Address of VMEM2 Bank in T23X */
/**
* @brief Start address of VMEM2 bank in T23X platform
*
* @details Base address of the third Vector Memory bank (VMEM2) in T23X Tegra
* platform. This region provides additional fast access memory for VPU
* operations.
* Value: 0x80000 (512KB offset)
*/
#define T23x_VMEM2_START 0x80000U #define T23x_VMEM2_START 0x80000U
/** End Address of VMEM2 Bank in T23X */
/**
* @brief End address of VMEM2 bank in T23X platform
*
* @details End address (exclusive) of the third Vector Memory bank (VMEM2) in
* T23X Tegra platform. The usable range is from T23x_VMEM2_START to
* (T23x_VMEM2_END - 1).
* Value: 0xA0000 (640KB)
*/
#define T23x_VMEM2_END 0xA0000U #define T23x_VMEM2_END 0xA0000U
/** @brief Base address for PVA0 VPU Debug Register space (CSITE_PVA0VPU) */ /**
#define TEGRA_PVA0_VPU_DBG_BASE 0x24740000U * @brief Base address for PVA0 VPU Debug Register space (CSITE_PVA0VPU)
/** @brief Size (in bytes) of the PVA0 VPU Debug Register space (CSITE_PVA0VPU) */ *
#define TEGRA_PVA0_VPU_DBG_SIZE 0x40000U * @details Physical base address of the PVA0 VPU debug register space in T23X
* platform. This address space provides access to VPU debug and monitoring
* registers through the CoreSight interface.
* Value: 0x24740000
*/
#define TEGRA_PVA0_VPU_DBG_BASE_T23X 0x24740000U
/**
* @brief Size (in bytes) of the PVA0 VPU Debug Register space (CSITE_PVA0VPU)
*
* @details Size of the PVA0 VPU debug register space in T23X platform. This
* defines the extent of the debug register address space accessible through
* the CoreSight interface.
* Value: 0x40000 (256KB)
*/
#define TEGRA_PVA0_VPU_DBG_SIZE_T23X 0x40000U
/**
* @brief Initialize PVA device for T23X platform
*
* @details This function performs T23X-specific initialization of the PVA
* device. It configures platform-specific parameters, sets up memory regions,
* initializes hardware-specific features, and prepares the device for operation
* on the T23X Tegra platform. This includes setting up VMEM regions, debug
* interfaces, and other platform-specific configurations.
*
* @param[in,out] pva Pointer to @ref pva_kmd_device structure to initialize
* Valid value: non-null, must be pre-allocated
*/
void pva_kmd_device_init_t23x(struct pva_kmd_device *pva); void pva_kmd_device_init_t23x(struct pva_kmd_device *pva);
#endif // PVA_KMD_T23X_H #endif // PVA_KMD_T23X_H

View File

@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "pva_kmd_t26x.h" #include "pva_kmd_t26x.h"
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_kmd_pfsd.h"
struct vmem_region vmem_regions_tab_t26x[PVA_VMEM_REGION_COUNT_T26X] = { struct vmem_region vmem_regions_tab_t26x[PVA_VMEM_REGION_COUNT_T26X] = {
{ .start = T26x_VMEM0_START, .end = T26x_VMEM0_END }, { .start = T26x_VMEM0_START, .end = T26x_VMEM0_END },
@@ -17,7 +18,7 @@ void pva_kmd_device_init_t26x(struct pva_kmd_device *pva)
pva->hw_consts.hw_gen = PVA_HW_GEN3; pva->hw_consts.hw_gen = PVA_HW_GEN3;
pva->hw_consts.n_smmu_contexts = PVA_NUM_SMMU_CONTEXTS_T26X; pva->hw_consts.n_smmu_contexts = PVA_NUM_SMMU_CONTEXTS_T26X;
pva->r5_image_smmu_context_id = PVA_NUM_SMMU_CONTEXTS_T26X - 1; pva->r5_image_smmu_context_id = PVA_NUM_SMMU_CONTEXTS_T26X - 1U;
pva->hw_consts.n_dma_descriptors = PVA_NUM_DMA_DESC_T26X; pva->hw_consts.n_dma_descriptors = PVA_NUM_DMA_DESC_T26X;
pva->hw_consts.n_user_dma_channels = PVA_DMA_NUM_CHANNELS_T26X - 1U; pva->hw_consts.n_user_dma_channels = PVA_DMA_NUM_CHANNELS_T26X - 1U;
pva->hw_consts.n_hwseq_words = PVA_NUM_HWSEQ_WORDS_T26X; pva->hw_consts.n_hwseq_words = PVA_NUM_HWSEQ_WORDS_T26X;
@@ -30,8 +31,10 @@ void pva_kmd_device_init_t26x(struct pva_kmd_device *pva)
PVA_KMD_PVA0_T26x_REG_BASE; PVA_KMD_PVA0_T26x_REG_BASE;
pva->reg_size[PVA_KMD_APERTURE_PVA_CLUSTER] = pva->reg_size[PVA_KMD_APERTURE_PVA_CLUSTER] =
PVA_KMD_PVA0_T26x_REG_SIZE; PVA_KMD_PVA0_T26x_REG_SIZE;
pva->reg_phy_base[PVA_KMD_APERTURE_VPU_DEBUG] = TEGRA_PVA0_VPU_DBG_BASE; pva->reg_phy_base[PVA_KMD_APERTURE_VPU_DEBUG] =
pva->reg_size[PVA_KMD_APERTURE_VPU_DEBUG] = TEGRA_PVA0_VPU_DBG_SIZE; TEGRA_PVA0_VPU_DBG_BASE_T26X;
pva->reg_size[PVA_KMD_APERTURE_VPU_DEBUG] =
TEGRA_PVA0_VPU_DBG_SIZE_T26X;
pva->regspec.sec_lic_intr_enable = 0x28064; pva->regspec.sec_lic_intr_enable = 0x28064;
pva->regspec.sec_lic_intr_status = 0x2806C; pva->regspec.sec_lic_intr_status = 0x2806C;
@@ -75,4 +78,11 @@ void pva_kmd_device_init_t26x(struct pva_kmd_device *pva)
} }
pva->bl_sector_pack_format = PVA_BL_TEGRA_RAW; pva->bl_sector_pack_format = PVA_BL_TEGRA_RAW;
pva->tsc_to_ns_multiplier = PVA_NS_PER_TSC_TICK_T26X; pva->tsc_to_ns_multiplier = PVA_NS_PER_TSC_TICK_T26X;
pva->pfsd_info.vpu_elf_data = pva_pfsd_vpu_elf_t26x;
pva->pfsd_info.vpu_elf_size = PVA_ALIGN8(PVA_PFSD_VPU_ELF_SIZE_T26X);
pva->pfsd_info.ppe_elf_data = pva_pfsd_ppe_elf_t26x;
pva->pfsd_info.ppe_elf_size = PVA_ALIGN8(PVA_PFSD_PPE_ELF_SIZE_T26X);
pva->pfsd_info.pfsd_dma_cfg = pfsd_dma_cfg_t26x;
pva->pfsd_info.register_cmd_buffer = &pva_kmd_pfsd_t26x_register_cmdbuf;
} }

View File

@@ -5,34 +5,147 @@
#define PVA_KMD_T26X_H #define PVA_KMD_T26X_H
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
/**
* @brief PVA0 register base address for T26X platform
*
* @details Physical base address of the PVA0 register space in T26X Tegra
* platform. This address space provides access to all PVA0 control and
* status registers for device configuration and operation.
* Value: 0x818c000000
*/
#define PVA_KMD_PVA0_T26x_REG_BASE 0x818c000000 #define PVA_KMD_PVA0_T26x_REG_BASE 0x818c000000
/**
* @brief PVA0 register space size for T26X platform
*
* @details Size of the PVA0 register address space in T26X Tegra platform.
* This defines the extent of the register space accessible for PVA0 device
* configuration and control operations.
* Value: 0x900000 (9MB)
*/
#define PVA_KMD_PVA0_T26x_REG_SIZE 0x900000 #define PVA_KMD_PVA0_T26x_REG_SIZE 0x900000
/** Number of VMEM regions in T26X */ /**
* @brief Number of VMEM regions available in T26X platform
*
* @details Defines the total number of Vector Memory (VMEM) regions available
* in the T26X Tegra platform. VMEM regions are fast on-chip memory banks used
* by VPU for data processing operations. T26X has one additional VMEM region
* compared to T23X.
*/
#define PVA_VMEM_REGION_COUNT_T26X 4U #define PVA_VMEM_REGION_COUNT_T26X 4U
/** Start Address of VMEM0 Bank in T26X */ /**
* @brief Start address of VMEM0 bank in T26X platform
*
* @details Base address of the first Vector Memory bank (VMEM0) in T26X Tegra
* platform. This region provides fast access memory for VPU operations.
* Value: 0x40 (64 bytes offset)
*/
#define T26x_VMEM0_START 0x40U #define T26x_VMEM0_START 0x40U
/** End Address of VMEM0 Bank in T26X */
/**
* @brief End address of VMEM0 bank in T26X platform
*
* @details End address (exclusive) of the first Vector Memory bank (VMEM0) in
* T26X Tegra platform. The usable range is from T26x_VMEM0_START to
* (T26x_VMEM0_END - 1).
* Value: 0x20000 (128KB)
*/
#define T26x_VMEM0_END 0x20000U #define T26x_VMEM0_END 0x20000U
/** Start Address of VMEM1 Bank in T26X */
/**
* @brief Start address of VMEM1 bank in T26X platform
*
* @details Base address of the second Vector Memory bank (VMEM1) in T26X Tegra
* platform. This region provides additional fast access memory for VPU
* operations.
* Value: 0x40000 (256KB offset)
*/
#define T26x_VMEM1_START 0x40000U #define T26x_VMEM1_START 0x40000U
/** End Address of VMEM1 Bank in T26X */
/**
* @brief End address of VMEM1 bank in T26X platform
*
* @details End address (exclusive) of the second Vector Memory bank (VMEM1) in
* T26X Tegra platform. The usable range is from T26x_VMEM1_START to
* (T26x_VMEM1_END - 1).
* Value: 0x60000 (384KB)
*/
#define T26x_VMEM1_END 0x60000U #define T26x_VMEM1_END 0x60000U
/** End Address of VMEM2 Bank in T26X */
/**
* @brief Start address of VMEM2 bank in T26X platform
*
* @details Base address of the third Vector Memory bank (VMEM2) in T26X Tegra
* platform. This region provides additional fast access memory for VPU
* operations.
* Value: 0x80000 (512KB offset)
*/
#define T26x_VMEM2_START 0x80000U #define T26x_VMEM2_START 0x80000U
/** End Address of VMEM2 Bank in T26X */
/**
* @brief End address of VMEM2 bank in T26X platform
*
* @details End address (exclusive) of the third Vector Memory bank (VMEM2) in
* T26X Tegra platform. The usable range is from T26x_VMEM2_START to
* (T26x_VMEM2_END - 1).
* Value: 0xA0000 (640KB)
*/
#define T26x_VMEM2_END 0xA0000U #define T26x_VMEM2_END 0xA0000U
/** End Address of VMEM3 Bank in T26X */
/**
* @brief Start address of VMEM3 bank in T26X platform
*
* @details Base address of the fourth Vector Memory bank (VMEM3) in T26X Tegra
* platform. This additional VMEM region (not available in T23X) provides
* extra fast access memory for VPU operations.
* Value: 0xC0000 (768KB offset)
*/
#define T26x_VMEM3_START 0xC0000U #define T26x_VMEM3_START 0xC0000U
/** End Address of VMEM3 Bank in T26X */
/**
* @brief End address of VMEM3 bank in T26X platform
*
* @details End address (exclusive) of the fourth Vector Memory bank (VMEM3) in
* T26X Tegra platform. The usable range is from T26x_VMEM3_START to
* (T26x_VMEM3_END - 1).
* Value: 0xE0000 (896KB)
*/
#define T26x_VMEM3_END 0xE0000U #define T26x_VMEM3_END 0xE0000U
/** @brief Base address for PVA0 VPU Debug Register space (CSITE_PVA0VPU) */ /**
#define TEGRA_PVA0_VPU_DBG_BASE 0x24740000U * @brief Base address for PVA0 VPU Debug Register space (CSITE_PVA0VPU)
/** @brief Size (in bytes) of the PVA0 VPU Debug Register space (CSITE_PVA0VPU) */ *
#define TEGRA_PVA0_VPU_DBG_SIZE 0x40000U * @details Physical base address of the PVA0 VPU debug register space in T26X
* platform. This address space provides access to VPU debug and monitoring
* registers through the CoreSight interface.
* Value: 0x10740000
*/
#define TEGRA_PVA0_VPU_DBG_BASE_T26X 0x10740000U
/**
* @brief Size (in bytes) of the PVA0 VPU Debug Register space (CSITE_PVA0VPU)
*
* @details Size of the PVA0 VPU debug register space in T26X platform. This
* defines the extent of the debug register address space accessible through
* the CoreSight interface.
* Value: 0x40000 (256KB)
*/
#define TEGRA_PVA0_VPU_DBG_SIZE_T26X 0x40000U
/**
* @brief Initialize PVA device for T26X platform
*
* @details This function performs T26X-specific initialization of the PVA
* device. It configures platform-specific parameters, sets up memory regions,
* initializes hardware-specific features, and prepares the device for operation
* on the T26X Tegra platform. This includes setting up all four VMEM regions,
* debug interfaces, and other platform-specific configurations unique to T26X.
*
* @param[in,out] pva Pointer to @ref pva_kmd_device structure to initialize
* Valid value: non-null, must be pre-allocated
*/
void pva_kmd_device_init_t26x(struct pva_kmd_device *pva); void pva_kmd_device_init_t26x(struct pva_kmd_device *pva);
#endif // PVA_KMD_T26X_H #endif // PVA_KMD_T26X_H

View File

@@ -9,6 +9,7 @@
#include "pva_kmd_constants.h" #include "pva_kmd_constants.h"
#include "pva_utils.h" #include "pva_utils.h"
#include "pva_kmd_tegra_stats.h" #include "pva_kmd_tegra_stats.h"
#include "pva_kmd_debugfs.h"
void pva_kmd_device_init_tegra_stats(struct pva_kmd_device *pva) void pva_kmd_device_init_tegra_stats(struct pva_kmd_device *pva)
{ {
@@ -24,7 +25,8 @@ void pva_kmd_device_init_tegra_stats(struct pva_kmd_device *pva)
err = pva_kmd_add_dram_buffer_resource(&pva->dev_resource_table, err = pva_kmd_add_dram_buffer_resource(&pva->dev_resource_table,
pva->tegra_stats_memory, pva->tegra_stats_memory,
&pva->tegra_stats_resource_id); &pva->tegra_stats_resource_id,
false);
ASSERT(err == PVA_SUCCESS); ASSERT(err == PVA_SUCCESS);
pva_kmd_update_fw_resource_table(&pva->dev_resource_table); pva_kmd_update_fw_resource_table(&pva->dev_resource_table);
} }
@@ -55,16 +57,26 @@ static uint64_t calc_vpu_utilization(uint64_t total_utilization,
} }
} }
enum pva_error static enum pva_error
pva_kmd_notify_fw_get_tegra_stats(struct pva_kmd_device *pva, notify_fw_get_tegra_stats(struct pva_kmd_device *pva,
struct pva_kmd_tegrastats *kmd_tegra_stats) struct pva_kmd_tegrastats *kmd_tegra_stats)
{ {
struct pva_cmd_get_tegra_stats cmd = { 0 }; struct pva_cmd_get_tegra_stats cmd = { 0 };
uint64_t buffer_offset = 0U; uint64_t buffer_offset = 0U;
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
struct pva_kmd_fw_tegrastats fw_tegra_stats = { 0 }; struct pva_kmd_fw_tegrastats fw_tegra_stats = { 0 };
bool stats_enabled = pva->debugfs_context.stats_enable;
uint64_t duration = 0U; uint64_t duration = 0U;
if (stats_enabled == false) {
pva_kmd_log_info("Tegra stats are disabled");
goto err_out;
}
if (!pva_kmd_device_maybe_on(pva)) {
goto out;
}
/* Power on PVA if not already */ /* Power on PVA if not already */
err = pva_kmd_device_busy(pva); err = pva_kmd_device_busy(pva);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -75,9 +87,10 @@ pva_kmd_notify_fw_get_tegra_stats(struct pva_kmd_device *pva,
pva_kmd_set_cmd_get_tegra_stats(&cmd, pva->tegra_stats_resource_id, pva_kmd_set_cmd_get_tegra_stats(&cmd, pva->tegra_stats_resource_id,
pva->tegra_stats_buf_size, pva->tegra_stats_buf_size,
buffer_offset, true); buffer_offset, stats_enabled);
err = pva_kmd_submit_cmd_sync(&pva->submitter, &cmd, sizeof(cmd), err = pva_kmd_submit_cmd_sync(&pva->submitter, &cmd,
(uint32_t)sizeof(cmd),
PVA_KMD_WAIT_FW_POLL_INTERVAL_US, PVA_KMD_WAIT_FW_POLL_INTERVAL_US,
PVA_KMD_WAIT_FW_TIMEOUT_US); PVA_KMD_WAIT_FW_TIMEOUT_US);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
@@ -90,6 +103,7 @@ pva_kmd_notify_fw_get_tegra_stats(struct pva_kmd_device *pva,
pva_kmd_device_idle(pva); pva_kmd_device_idle(pva);
out:
duration = sat_sub64(fw_tegra_stats.window_end_time, duration = sat_sub64(fw_tegra_stats.window_end_time,
fw_tegra_stats.window_start_time); fw_tegra_stats.window_start_time);
@@ -107,3 +121,78 @@ dev_idle:
err_out: err_out:
return err; return err;
} }
static int64_t print_vpu_stats(struct pva_kmd_tegrastats *kmd_tegra_stats,
uint8_t *out_buffer, uint64_t offset,
uint64_t len)
{
char kernel_buffer[256];
int64_t formatted_len;
formatted_len = snprintf(
kernel_buffer, sizeof(kernel_buffer),
"%llu\n%llu\n%llu\n%llu\n",
(long long unsigned int)(kmd_tegra_stats->window_start_time),
(long long unsigned int)(kmd_tegra_stats->window_end_time),
(long long unsigned int)
kmd_tegra_stats->average_vpu_utilization[0],
(long long unsigned int)
kmd_tegra_stats->average_vpu_utilization[1]);
if (formatted_len <= 0) {
return 0;
}
formatted_len++; //accounting for null terminating character
if (len < (uint64_t)formatted_len) {
return 0;
}
// Copy the formatted string from kernel buffer to user buffer
return pva_kmd_read_from_buffer_to_user(out_buffer, len, offset,
kernel_buffer,
(uint64_t)formatted_len);
}
static int64_t get_vpu_stats(struct pva_kmd_device *dev, void *file_data,
uint8_t *out_buffer, uint64_t offset,
uint64_t size)
{
struct pva_kmd_tegrastats kmd_tegra_stats;
// We don't support partial reads for vpu stats because we cannot mix two
// reads at different times together.
if (offset != 0U) {
return 0;
}
kmd_tegra_stats.window_start_time = 0;
kmd_tegra_stats.window_end_time = 0;
kmd_tegra_stats.average_vpu_utilization[0] = 0;
kmd_tegra_stats.average_vpu_utilization[1] = 0;
notify_fw_get_tegra_stats(dev, &kmd_tegra_stats);
return print_vpu_stats(&kmd_tegra_stats, out_buffer, offset, size);
}
enum pva_error pva_kmd_tegrastats_init_debugfs(struct pva_kmd_device *pva)
{
enum pva_error err;
pva_kmd_debugfs_create_bool(pva, "stats_enabled",
&pva->debugfs_context.stats_enable);
pva->debugfs_context.vpu_fops.read = &get_vpu_stats;
pva->debugfs_context.vpu_fops.write = NULL;
pva->debugfs_context.vpu_fops.pdev = pva;
err = pva_kmd_debugfs_create_file(pva, "vpu_stats",
&pva->debugfs_context.vpu_fops);
if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to create vpu_stats debugfs file");
return err;
}
return PVA_SUCCESS;
}

View File

@@ -1,26 +1,115 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ /* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef PVA_KMD_TEGRA_STATS_H #ifndef PVA_KMD_TEGRA_STATS_H
#define PVA_KMD_TEGRA_STATS_H #define PVA_KMD_TEGRA_STATS_H
#include "pva_kmd_device.h" #include "pva_kmd_device.h"
#if PVA_ENABLE_TEGRASTATS == 1
/** /**
* @brief Structure which holds vpu stats information * @brief Structure containing VPU utilization statistics for Tegra monitoring
*
* @details This structure holds performance statistics for VPU engines within
* the PVA device, providing utilization metrics and timing information for
* system monitoring and performance analysis. The statistics are collected
* over defined time windows and provide insights into VPU workload distribution
* and efficiency.
*/ */
struct pva_kmd_tegrastats { struct pva_kmd_tegrastats {
/** Holds vpu utilization as a percentage for each VPU in the PVA */ /**
* @brief Array of average VPU utilization percentages for each VPU engine
*
* @details Holds VPU utilization as a percentage for each VPU in the PVA cluster.
* Each entry represents the average utilization of a specific VPU engine
* during the measurement window.
* Valid range for each element: [0 .. 100] (percentage)
*/
uint64_t average_vpu_utilization[PVA_NUM_PVE]; uint64_t average_vpu_utilization[PVA_NUM_PVE];
/** Current state of pva_kmd_tegrastats */
/**
* @brief Start timestamp of the current statistics measurement window
*
* @details Timestamp marking the beginning of the current measurement window
* for statistics collection. Used to calculate measurement duration and
* normalize utilization metrics.
* Valid range: [0 .. UINT64_MAX]
*/
uint64_t window_start_time; uint64_t window_start_time;
/**
* @brief End timestamp of the current statistics measurement window
*
* @details Timestamp marking the end of the current measurement window
* for statistics collection. Used in conjunction with window_start_time
* to determine the measurement period.
* Valid range: [window_start_time .. UINT64_MAX]
*/
uint64_t window_end_time; uint64_t window_end_time;
}; };
/**
* @brief Initialize Tegra statistics collection for PVA device
*
* @details This function performs the following operations:
* - Initializes the Tegra statistics collection infrastructure
* - Sets up performance monitoring counters for VPU engines
* - Configures timing mechanisms for utilization measurement
* - Prepares data structures for statistics accumulation
* - Establishes baseline metrics for utilization calculation
* - Enables performance monitoring in firmware if needed
*
* The statistics collection provides valuable information for system
* monitoring tools like tegrastats to display PVA utilization metrics.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must be initialized
*/
void pva_kmd_device_init_tegra_stats(struct pva_kmd_device *pva); void pva_kmd_device_init_tegra_stats(struct pva_kmd_device *pva);
/**
* @brief Deinitialize Tegra statistics collection and clean up resources
*
* @details This function performs the following operations:
* - Stops statistics collection and performance monitoring
* - Disables performance monitoring counters
* - Cleans up statistics data structures and allocated memory
* - Frees resources associated with utilization tracking
* - Ensures proper cleanup of monitoring infrastructure
* - Resets statistics state for the device
*
* This function should be called during device shutdown to ensure
* proper cleanup of all statistics-related resources.
*
* @param[in] pva Pointer to @ref pva_kmd_device structure
* Valid value: non-null, must have been initialized with stats
*/
void pva_kmd_device_deinit_tegra_stats(struct pva_kmd_device *pva); void pva_kmd_device_deinit_tegra_stats(struct pva_kmd_device *pva);
enum pva_error /* Initialize Tegrastats debugfs nodes */
pva_kmd_notify_fw_get_tegra_stats(struct pva_kmd_device *pva, enum pva_error pva_kmd_tegrastats_init_debugfs(struct pva_kmd_device *pva);
struct pva_kmd_tegrastats *kmd_tegra_stats);
#else /* PVA_ENABLE_TEGRASTATS */
/* Dummy inline functions when Tegrastats is disabled */
static inline void pva_kmd_device_init_tegra_stats(struct pva_kmd_device *pva)
{
(void)pva;
}
static inline void pva_kmd_device_deinit_tegra_stats(struct pva_kmd_device *pva)
{
(void)pva;
}
/* Dummy initialization function when Tegrastats is disabled */
static inline enum pva_error
pva_kmd_tegrastats_init_debugfs(struct pva_kmd_device *pva)
{
(void)pva;
return PVA_SUCCESS;
}
#endif /* PVA_ENABLE_TEGRASTATS */
#endif #endif

View File

@@ -45,7 +45,9 @@ void *pva_kmd_zalloc(uint64_t size)
void pva_kmd_free(void *ptr) void pva_kmd_free(void *ptr)
{ {
free(ptr); if (ptr != NULL) {
free(ptr);
}
} }
void pva_kmd_fault(void) void pva_kmd_fault(void)
@@ -71,8 +73,12 @@ enum pva_error pva_kmd_sema_wait_timeout(pva_kmd_sema_t *sem,
ASSERT(ret == 0); ASSERT(ret == 0);
/* Add timeout (specified in milliseconds) to the current time */ /* Add timeout (specified in milliseconds) to the current time */
ts.tv_sec += timeout_ms / 1000; {
ts.tv_nsec += (timeout_ms % 1000) * 1000000; uint32_t sec_part = timeout_ms / 1000U;
uint32_t nsec_part = (timeout_ms % 1000U) * 1000000U;
ts.tv_sec += (time_t)sec_part;
ts.tv_nsec += (long)nsec_part;
}
/* Handle case where nanoseconds exceed 1 second */ /* Handle case where nanoseconds exceed 1 second */
if (ts.tv_nsec >= 1000000000) { if (ts.tv_nsec >= 1000000000) {
@@ -82,11 +88,12 @@ enum pva_error pva_kmd_sema_wait_timeout(pva_kmd_sema_t *sem,
wait_again: wait_again:
ret = sem_timedwait(sem, &ts); ret = sem_timedwait(sem, &ts);
if (ret != 0) { if (ret == -1) {
if (errno == ETIMEDOUT) { int saved_errno = errno;
if (saved_errno == ETIMEDOUT) {
pva_kmd_log_err("pva_kmd_sema_wait_timeout Timed out"); pva_kmd_log_err("pva_kmd_sema_wait_timeout Timed out");
return PVA_TIMEDOUT; return PVA_TIMEDOUT;
} else if (errno == EINTR) { } else if (saved_errno == EINTR) {
goto wait_again; goto wait_again;
} else { } else {
FAULT("Unexpected sem_timedwait error"); FAULT("Unexpected sem_timedwait error");
@@ -111,7 +118,7 @@ void pva_kmd_sema_post(pva_kmd_sema_t *sem)
struct pva_kmd_device_memory * struct pva_kmd_device_memory *
pva_kmd_device_memory_alloc_map(uint64_t size, struct pva_kmd_device *pva, pva_kmd_device_memory_alloc_map(uint64_t size, struct pva_kmd_device *pva,
uint32_t iova_access_flags, uint32_t iova_access_flags,
uint32_t smmu_ctx_idx) uint8_t smmu_ctx_idx)
{ {
struct pva_kmd_device_memory *mem; struct pva_kmd_device_memory *mem;
enum pva_error err; enum pva_error err;
@@ -142,24 +149,30 @@ err_out:
return NULL; return NULL;
} }
void pva_kmd_atomic_store(pva_kmd_atomic_t *atomic_val, int val) void pva_kmd_atomic_store(pva_kmd_atomic_t *a_var, int val)
{ {
atomic_store(atomic_val, val); atomic_store(a_var, val);
} }
int pva_kmd_atomic_fetch_add(pva_kmd_atomic_t *atomic_val, int val) int pva_kmd_atomic_fetch_add(pva_kmd_atomic_t *a_var, int val)
{ {
return atomic_fetch_add(atomic_val, val); /* MISRA Deviation: Atomic to non-atomic conversion is required for return value */
int result = (int)atomic_fetch_add(a_var, val);
return result;
} }
int pva_kmd_atomic_fetch_sub(pva_kmd_atomic_t *atomic_val, int val) int pva_kmd_atomic_fetch_sub(pva_kmd_atomic_t *a_var, int val)
{ {
return atomic_fetch_sub(atomic_val, val); /* MISRA Deviation: Atomic to non-atomic conversion is required for return value */
int result = (int)atomic_fetch_sub(a_var, val);
return result;
} }
int pva_kmd_atomic_load(pva_kmd_atomic_t *atomic_val) int pva_kmd_atomic_load(pva_kmd_atomic_t *a_var)
{ {
return atomic_load(atomic_val); /* MISRA Deviation: Atomic to non-atomic conversion is required for return value */
int result = (int)atomic_load(a_var);
return result;
} }
bool pva_kmd_device_maybe_on(struct pva_kmd_device *pva) bool pva_kmd_device_maybe_on(struct pva_kmd_device *pva)
@@ -167,7 +180,7 @@ bool pva_kmd_device_maybe_on(struct pva_kmd_device *pva)
bool device_on = false; bool device_on = false;
pva_kmd_mutex_lock(&pva->powercycle_lock); pva_kmd_mutex_lock(&pva->powercycle_lock);
if (pva->refcount > 0) { if (pva->refcount > 0U) {
device_on = true; device_on = true;
} }
pva_kmd_mutex_unlock(&pva->powercycle_lock); pva_kmd_mutex_unlock(&pva->powercycle_lock);

View File

@@ -9,18 +9,3 @@ void *pva_kmd_zalloc_nofail(uint64_t size)
ASSERT(ptr != NULL); ASSERT(ptr != NULL);
return ptr; return ptr;
} }
void pva_kmd_log_err(const char *msg)
{
pva_kmd_print_str(msg);
}
void pva_kmd_log_err_u64(const char *msg, uint64_t val)
{
pva_kmd_print_str_u64(msg, val);
}
void pva_kmd_log_err_hex32(const char *msg, uint32_t val)
{
pva_kmd_print_str_hex32(msg, val);
}

View File

@@ -11,11 +11,38 @@
#include "pva_plat_faults.h" #include "pva_plat_faults.h"
#include "pva_math_utils.h" #include "pva_math_utils.h"
/**
* @brief Size of a 4KB memory page in bytes
*
* @details This macro defines the standard 4KB page size commonly used in
* memory management and allocation operations. It is calculated as 4 * 1024
* bytes and is used for memory alignment and size calculations.
*/
#define SIZE_4KB (4 * 1024) #define SIZE_4KB (4 * 1024)
void pva_kmd_log_err(const char *msg); /**
void pva_kmd_log_err_u64(const char *msg, uint64_t val); * @brief Allocate zero-initialized memory that cannot fail
void pva_kmd_log_err_hex32(const char *msg, uint32_t val); *
* @details This function performs the following operations:
* - Allocates memory of the specified size for KMD internal use
* - Initializes all allocated memory to zero
* - Uses platform-appropriate memory allocation mechanisms
* - Guarantees that the allocation will not fail - if memory cannot be
* allocated, the system will halt or take appropriate recovery action
* - Returns a pointer to the allocated and zero-initialized memory region
* - Ensures memory is properly aligned for the target platform
*
* This function is designed for critical memory allocations where failure
* is not acceptable. The allocated memory must be freed using the appropriate
* platform-specific deallocation function to prevent memory leaks. The
* "nofail" designation means the function will either succeed or take
* system-level action to handle the out-of-memory condition.
*
* @param[in] size Size of memory to allocate in bytes
* Valid range: [1 .. UINT64_MAX]
*
* @retval non-null Pointer to allocated and zero-initialized memory
*/
void *pva_kmd_zalloc_nofail(uint64_t size); void *pva_kmd_zalloc_nofail(uint64_t size);
#endif // PVA_KMD_UTILS_H #endif // PVA_KMD_UTILS_H

View File

@@ -33,7 +33,7 @@ enum pva_error pva_kmd_init_vpu_app_auth(struct pva_kmd_device *pva, bool ena)
err = pva_kmd_mutex_init(&pva_auth->allow_list_lock); err = pva_kmd_mutex_init(&pva_auth->allow_list_lock);
if (err != PVA_SUCCESS) { if (err != PVA_SUCCESS) {
pva_kmd_log_err("Failed to initialize allow list lock"); pva_kmd_log_err("Failed to initialize allow list lock");
goto free; goto cleanup_free;
} }
default_path_len = strnlen(default_path, ALLOWLIST_FILE_LEN); default_path_len = strnlen(default_path, ALLOWLIST_FILE_LEN);
@@ -45,7 +45,7 @@ enum pva_error pva_kmd_init_vpu_app_auth(struct pva_kmd_device *pva, bool ena)
return PVA_SUCCESS; return PVA_SUCCESS;
free: cleanup_free:
pva_kmd_free(pva_auth); pva_kmd_free(pva_auth);
error: error:
pva->pva_auth = NULL; pva->pva_auth = NULL;
@@ -62,7 +62,7 @@ error:
* \ref PVA_SUCCESS Success. Passed in key matched wth calculated key. * \ref PVA_SUCCESS Success. Passed in key matched wth calculated key.
* \ref -EACCES. Passed in Key doesn't match with calcualted key. * \ref -EACCES. Passed in Key doesn't match with calcualted key.
*/ */
static enum pva_error is_key_match(uint8_t *dataptr, size_t size, static enum pva_error is_key_match(const uint8_t *dataptr, size_t size,
struct shakey key) struct shakey key)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
@@ -108,8 +108,8 @@ static enum pva_error is_key_match(uint8_t *dataptr, size_t size,
* - -EACCES if no match found. * - -EACCES if no match found.
*/ */
static enum pva_error static enum pva_error
check_all_keys_for_match(struct shakey *pallkeys, uint8_t *dataptr, size_t size, check_all_keys_for_match(struct shakey *pallkeys, const uint8_t *dataptr,
const struct vpu_hash_vector *match_hash) size_t size, const struct vpu_hash_vector *match_hash)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
uint32_t idx; uint32_t idx;
@@ -172,7 +172,7 @@ static int32_t compare_hash_value(const struct vpu_hash_vector *pkey,
* @param[in] len length (in bytes) of data at @ref buf. * @param[in] len length (in bytes) of data at @ref buf.
* @retval value of calculated crc32. * @retval value of calculated crc32.
*/ */
static uint32_t pva_crc32(uint32_t crc, uint8_t *buf, size_t len) static uint32_t pva_crc32(uint32_t crc, const uint8_t *buf, size_t len)
{ {
int32_t k; int32_t k;
size_t count; size_t count;
@@ -233,7 +233,7 @@ binary_search(const struct vpu_hash_vector *key,
static enum pva_error static enum pva_error
pva_kmd_vpu_check_sha256_key(struct vpu_hash_key_pair *vpu_hash_keys, pva_kmd_vpu_check_sha256_key(struct vpu_hash_key_pair *vpu_hash_keys,
uint8_t *dataptr, size_t size) const uint8_t *dataptr, size_t size)
{ {
enum pva_error err = PVA_SUCCESS; enum pva_error err = PVA_SUCCESS;
struct vpu_hash_vector cal_Hash; struct vpu_hash_vector cal_Hash;
@@ -287,8 +287,7 @@ enum pva_error pva_kmd_verify_exectuable_hash(struct pva_kmd_device *pva,
if (err == PVA_SUCCESS) { if (err == PVA_SUCCESS) {
err = pva_kmd_vpu_check_sha256_key( err = pva_kmd_vpu_check_sha256_key(
pva_auth->vpu_hash_keys, (uint8_t *)dataptr, pva_auth->vpu_hash_keys, dataptr, size);
size);
if (err == PVA_SUCCESS) { if (err == PVA_SUCCESS) {
pva_dbg_printf( pva_dbg_printf(
"App authentication successfull\n"); "App authentication successfull\n");
@@ -382,12 +381,14 @@ void pva_kmd_deinit_vpu_app_auth(struct pva_kmd_device *pva)
{ {
struct pva_vpu_auth *pva_auth; struct pva_vpu_auth *pva_auth;
if (pva == NULL) if (pva == NULL) {
return; return;
}
pva_auth = pva->pva_auth; pva_auth = pva->pva_auth;
if (pva_auth == NULL) if (pva_auth == NULL) {
return; return;
}
pva_kmd_allowlist_destroy(pva_auth); pva_kmd_allowlist_destroy(pva_auth);
pva_kmd_mutex_deinit(&pva_auth->allow_list_lock); pva_kmd_mutex_deinit(&pva_auth->allow_list_lock);

Some files were not shown because too many files have changed in this diff Show More