MI IPU CASCADE API¶
REVISION HISTORY¶
| Revision No. | Description |
Date |
|---|---|---|
| 1.0 | Initial release. | 01/07/2025 |
| 1.1 | 02/28/2026 |
1. 概述¶
1.1. 模块说明¶
IPU Cascade API 面向多IPU并行处理同一LLM大模型的应用场景,主要功能是在板端加速推演LLM大模型。IPU Cascade API 与通用 MI IPU 接口风格保持一致,便于在现有工程中扩展 PCIe 级联能力。
1.2. 基本结构¶
- RC 端应用:负责读取级联离线模型、创建设备/通道、准备输入输出 Tensor,控制EP端服务程序执行模型推理。
- EP 端服务:运行在基于PCIE总线外接的IPU板卡,负责响应RC指令,并调用IPU Cascade API完成模型推理。
1.3. 功能介绍¶
IPU Cascade API支持以下功能:
-
支持本端、远端IPU板卡实现级联模型的协同推理
-
支持控制远端IPU板卡实现非级联模型的推理
-
支持多通道
-
支持指定IPU推理任务的优先级
-
支持单次推理单张输入和单次推理多张输入
1.4. 应用场景¶
- 大模型级联:把级联大模型拆分为多个子网并分布到多颗 IPU,提升吞吐与容量。
- 远端推理加速:模型完全运行在 EP 上,RC 负责数据调度。
1.5. 工作原理¶
用户在调用IPU Cascade模块进行模型推演前,首先需要使用IPU SDK工具链将原始的大语言模型转换为硬件所支持的离线级联模型文件,然后通过调用IPU Cascade API在本地板端加载离线级联模型,控制远端板卡对离线级联模型推理进行加速。
1.6. 接口调用流程¶
MI_IPU_PCIECasWrapper_GetOfflineStaticInfoMI_IPU_PCIECasWrapper_CreateDeviceMI_IPU_PCIECasWrapper_CreateCHNMI_IPU_GetInOutTensorDescMI_IPU_PCIECasWrapper_SubNetInvokeMI_IPU_PCIECasWrapper_DestroyCHNMI_IPU_PCIECasWrapper_DestroyDevice
1.7. 示例¶
SDK 提供 sdk/release_feature/source/ipu/ipu_client/(RC)与 sdk/release_feature/source/ipu/ipu_service/(EP)示例,可直接参考其如何组织参数并调用公开 API。
-
ipu_client#include <fcntl.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/mman.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <pthread.h> #include <getopt.h> #include <stdbool.h> #include <stdlib.h> #include "mi_sys.h" #include "mi_ipu.h" #include "mi_ipu_pcie_cascade_datatype.h" #include "mi_ipu_pcie_cascade.h" #include "ipu_client.h" static void _showUsage(void) { printf("Usage: ./prog_ipu_ipu_client [-m] [-i][...]\n"); printf(" -m, model file\n"); printf(" -i, input tensor file\n"); printf(" -l, loop count, if not set, only invoke once\n"); printf(" -n, nbatch\n"); printf(" -j, subnet id\n"); printf(" -a, ipu affinity, multi core use\n"); printf(" -p, invoke priority, -10~39\n"); } static MI_S32 IPU_Client_GetInputTensorData(char *InputPath, void **pInput, int *filelen_in) { int fd1; void *pmem = NULL; off_t filelen1; if (!InputPath){ return -1; } fd1 = open(InputPath, O_RDONLY, 0644); if (fd1 < 0) return -1; filelen1 = lseek(fd1, 0L, SEEK_END); if (filelen1 <= 0){ return -1; } lseek(fd1, 0L, SEEK_SET); pmem = mmap(NULL, filelen1, PROT_READ, MAP_SHARED, fd1, 0); close(fd1); if (pmem == MAP_FAILED) return -1; *pInput = pmem; *filelen_in = filelen1; return MI_SUCCESS; } static MI_S32 IPU_Client_InsertInputNbatch(void *pInput, MI_IPU_SubNet_InputOutputDesc_t *pDesc, MI_IPU_BatchInvokeParam_t *pInvokeParam) { int cnt, batch_cnt; int total_cnt = 0; char *_pInput = (char *)pInput; for (batch_cnt = 0; batch_cnt < pInvokeParam->u32BatchN; batch_cnt++) { for (cnt = 0; cnt < pDesc->u32InputTensorCount; cnt++) { memcpy(pInvokeParam->astArrayTensors[total_cnt].ptTensorData[0], (void *)_pInput, pDesc->astMI_InputTensorDescs[cnt].s32AlignedBufSize); MI_SYS_FlushInvCache(pInvokeParam->astArrayTensors[total_cnt].ptTensorData[0], pDesc->astMI_InputTensorDescs[cnt].s32AlignedBufSize); _pInput += pDesc->astMI_InputTensorDescs[cnt].s32AlignedBufSize; total_cnt++; } } return MI_SUCCESS; } MI_S32 IPU_Client_AllocTensors(MI_IPU_SubNet_InputOutputDesc_t *pDesc, IpuClientTestParam_t *pstTestParam, IpuClientRunbufInfo_t *pstIpuRuntimeInfo, IpuClientTensorAddrInfo_t *pstTensorAddrInfo, EN_IpuBufType eBufType, MI_U32 u32DeviatonBytes) { int i, j, s32Ret; MI_U32 u32RequireBufSize = 0, u32Nbatch; MI_U32 u32InCnt; MI_PHY *pu64TensorPA; void **ppTensorVA; MI_PHY u64PABase; void *pVABase; u32Nbatch = pstTestParam->u32Nbatch; if (!u32Nbatch) { u32Nbatch = 1; } switch (eBufType) { case EN_INPUT_BUF: for (j = 0; j < u32Nbatch; j++) { for (i = 0; i < pDesc->u32InputTensorCount; i++) { u32RequireBufSize += pDesc->astMI_InputTensorDescs[i].s32AlignedBufSize; u32RequireBufSize += ALIGN_UP(u32DeviatonBytes, ALIGN_SIZE); u32RequireBufSize += u32DeviatonBytes; } } pu64TensorPA = &pstIpuRuntimeInfo->u64InTensorPA; ppTensorVA = &pstIpuRuntimeInfo->pInTensorVA; pstIpuRuntimeInfo->u32InTensorSize = u32RequireBufSize; break; case EN_OUTPUT_BUF: for (j = 0; j < u32Nbatch; j++) { for (i = 0; i < pDesc->u32OutputTensorCount; i++) { u32RequireBufSize += pDesc->astMI_OutputTensorDescs[i].s32AlignedBufSize; u32RequireBufSize += ALIGN_UP(u32DeviatonBytes, ALIGN_SIZE); u32RequireBufSize += u32DeviatonBytes; } } pu64TensorPA = &pstIpuRuntimeInfo->u64OutTensorPA; ppTensorVA = &pstIpuRuntimeInfo->pOutTensorVA; pstIpuRuntimeInfo->u32OutTensorSize = u32RequireBufSize; break; default: u32RequireBufSize = 0; printf("error: don't support tensor type: %d\n", eBufType); return -1; } s32Ret = MI_SYS_MMA_Alloc(0, NULL, u32RequireBufSize, pu64TensorPA); if (s32Ret != MI_SUCCESS) { printf("fail to allocate %s buffer\n", eBufType==EN_INPUT_BUF?"input":"output"); return -1; } s32Ret = MI_SYS_Mmap(*pu64TensorPA, u32RequireBufSize, ppTensorVA, TRUE); if (s32Ret != MI_SUCCESS) { printf("Error: fail to map %s address, error=%d\n", eBufType==EN_INPUT_BUF?"input":"output", s32Ret); return -1; } if (u32DeviatonBytes != 0) { u64PABase = ALIGN_UP(*pu64TensorPA, ALIGN_SIZE) + u32DeviatonBytes; } else { u64PABase = *pu64TensorPA; } pVABase = *ppTensorVA + (u64PABase - *pu64TensorPA); if (eBufType == EN_INPUT_BUF) { pstTensorAddrInfo->u32InCnt = pDesc->u32InputTensorCount * u32Nbatch; for (i = 0; i < u32Nbatch; i++) { for (j = 0; j < pDesc->u32InputTensorCount; j++) { pstTensorAddrInfo->astArrayTensors[i*pDesc->u32InputTensorCount+j].phyTensorAddr[0] = u64PABase; pstTensorAddrInfo->astArrayTensors[i*pDesc->u32InputTensorCount+j].ptTensorData[0] = pVABase; u64PABase += pDesc->astMI_InputTensorDescs[j].s32AlignedBufSize; if (u32DeviatonBytes != 0) { u64PABase = ALIGN_UP(u64PABase, ALIGN_SIZE) + u32DeviatonBytes; } pVABase = *ppTensorVA + (u64PABase - *pu64TensorPA); } } } else { u32InCnt = pDesc->u32InputTensorCount * u32Nbatch; pstTensorAddrInfo->u32OutCnt = pDesc->u32OutputTensorCount * u32Nbatch; for (i = 0; i < u32Nbatch; i++) { for (j = 0; j < pDesc->u32OutputTensorCount; j++) { pstTensorAddrInfo->astArrayTensors[u32InCnt+i*pDesc->u32OutputTensorCount+j].phyTensorAddr[0] = u64PABase; pstTensorAddrInfo->astArrayTensors[u32InCnt+i*pDesc->u32OutputTensorCount+j].ptTensorData[0] = pVABase; u64PABase += pDesc->astMI_OutputTensorDescs[j].s32AlignedBufSize; if (u32DeviatonBytes != 0) { u64PABase = ALIGN_UP(u64PABase, ALIGN_SIZE) + u32DeviatonBytes; } pVABase = *ppTensorVA + (u64PABase - *pu64TensorPA); } } } return 0; } void IPU_Client_FreeTensors(IpuClientRunbufInfo_t *pstIpuRuntimeInfo, EN_IpuBufType eBufType) { if (eBufType == EN_INPUT_BUF) { MI_SYS_Munmap(pstIpuRuntimeInfo->pInTensorVA, pstIpuRuntimeInfo->u32InTensorSize); MI_SYS_MMA_Free(0, pstIpuRuntimeInfo->u64InTensorPA); } else { MI_SYS_Munmap(pstIpuRuntimeInfo->pOutTensorVA, pstIpuRuntimeInfo->u32OutTensorSize); MI_SYS_MMA_Free(0, pstIpuRuntimeInfo->u64OutTensorPA); } } int main(int argc, char * argv[]) { int opt; int count = 0; double linux_time = 0, total_linux_time = 0, total_ipu_time = 0; MI_U64 total_bw = 0, total_bw_rd = 0, total_bw_wr = 0; int file_len_in = 0; void *pInput = NULL; MI_U32 u32ChnId; MI_S32 s32Ret; int cnt, batch_cnt; int total_cnt; struct timespec invoke_start, invoke_end; IpuClientTestParam_t stTestParam; MI_IPU_PCIECasDevAttr_t stCASDevAttr; MI_IPU_PCIECasOfflineModelStaticInfo_t stCASOfflineModelInfo; MI_IPU_ModelDesc_t *pstModelDesc; MI_IPU_SubNet_InputOutputDesc_t *pstTensorDesc; MI_IPU_SubNetBatchInvokeParam_t stSubNetInvokeParam; MI_IPU_BatchInvokeParam_t stInvokParam; MI_IPU_PCIECasSubNetBatchInvokeParam_t stIPUCASInvokeParam; MI_IPU_RuntimeInfo_t stRuntimeInfo; IpuClientTensorAddrInfo_t stTensorAddrInfo; IpuClientRunbufInfo_t stIpuRunBufInfo; MI_IPU_DevAttr_t stIPUDevAttr; MI_IPUChnAttr_t stIPUChnAttr; memset(&stTestParam, 0, sizeof(stTestParam)); while (true) { int option_index = 0; static struct option long_options[] = { {"model", required_argument, 0, 'm' }, {"input", required_argument, 0, 'i' }, {"loop_count", required_argument, 0, 'l' }, {"nbatch", required_argument, 0, 'n' }, {"sub_net_id", required_argument, 0, 'j' }, {"affinity", required_argument, 0, 'a' }, {"priority", required_argument, 0, 'p' } }; opt = getopt_long(argc, argv, "m:i:o:l:n:j:a:p", long_options, &option_index); if (opt == -1) { break; } switch (opt) { case 'm': stTestParam.ModelPath = optarg; break; case 'i': stTestParam.InputPath = optarg; break; break; case 'l': stTestParam.u32LoopCount = strtoul(optarg, NULL, 16); break; case 'n': stTestParam.u32Nbatch = strtoul(optarg, NULL, 16); break; case 'j': stTestParam.u32SubNetId = strtoul(optarg, NULL, 10); stTestParam.u32SubNetInvoke = 1; break; case 'a': stTestParam.u32IpuAffinity = strtoul(optarg, NULL, 10); break; case 'p': stTestParam.s32TaskPrio = strtoul(optarg, NULL, 10); break; default: _showUsage(); return 0; } } if (argc <= 2 || !stTestParam.ModelPath || !stTestParam.InputPath) { _showUsage(); goto SYS_EXIT; } if (stTestParam.u32LoopCount == 0) stTestParam.u32LoopCount = 1; if (stTestParam.u32Nbatch == 0) stTestParam.u32Nbatch = 1; if (stTestParam.u32SubNetInvoke == 0) stTestParam.u32SubNetInvoke = 1; MI_SYS_Init(0); s32Ret = MI_IPU_PCIECasWrapper_GetOfflineStaticInfo(NULL, stTestParam.ModelPath, &stCASOfflineModelInfo); if (s32Ret != MI_SUCCESS) { printf("fail to get %s static info\n", stTestParam.ModelPath); goto SYS_EXIT; } memset(&stIPUDevAttr, 0, sizeof(stIPUDevAttr)); memset(&stCASDevAttr, 0, sizeof(stCASDevAttr)); stIPUDevAttr.u32CoreMask = stTestParam.u32IpuAffinity; stIPUDevAttr.u32MaxVariableBufSize = stCASOfflineModelInfo.au32VariableBufferSize[E_MI_IPU_PCIE_CAS_LOCAL_VARIABLE_BUFFER_IDX]; memcpy(&stCASDevAttr.stIPUDevAttr, &stIPUDevAttr, sizeof(stIPUDevAttr)); memcpy(stCASDevAttr.au32MaxVariableBufSize, stCASOfflineModelInfo.au32VariableBufferSize, sizeof(MI_U32)*stCASOfflineModelInfo.u32SocNum); stCASDevAttr.u32SocNum = stCASOfflineModelInfo.u32SocNum; s32Ret = MI_IPU_PCIECasWrapper_CreateDevice(&stCASDevAttr, NULL, NULL, E_MI_IPU_PCIE_CAS_WORK_MODE_RC); if (s32Ret != MI_SUCCESS) { printf("Fail to Create Device, ret=%d\n", s32Ret); goto SYS_EXIT; } memset(&stIPUChnAttr, 0, sizeof(stIPUChnAttr)); stIPUChnAttr.u32InputBufDepth = 0; stIPUChnAttr.u32OutputBufDepth = 0; stIPUChnAttr.u32BatchMax = stTestParam.u32Nbatch; stIPUChnAttr.u32SubNetId = stTestParam.u32SubNetId; s32Ret = MI_IPU_PCIECasWrapper_CreateCHN(&u32ChnId, &stIPUChnAttr, NULL, stTestParam.ModelPath, E_MI_IPU_PCIE_CAS_WORK_MODE_RC); if (s32Ret != MI_SUCCESS) { printf("Fail to Create CHN, ret=%d\n", s32Ret); goto DESTROY_DEV; } pstModelDesc = malloc(sizeof(MI_IPU_ModelDesc_t)); if (!pstModelDesc) { printf("Fail to malloc model description\n"); goto DESTROY_CHN; } memset(pstModelDesc, 0, sizeof(MI_IPU_ModelDesc_t)); s32Ret = MI_IPU_GetSubNetDesc(u32ChnId, pstModelDesc); if (s32Ret != MI_SUCCESS) { printf("Get model desc failed!\n"); goto DESTROY_CHN; } if (stTestParam.u32SubNetId >= pstModelDesc->u32SubNetNum) { printf("This model(sub net num %u) not support sub net id %u!\n", pstModelDesc->u32SubNetNum, stTestParam.u32SubNetId); goto DESTROY_CHN; } pstTensorDesc = &pstModelDesc->astSubNetDesc[stTestParam.u32SubNetId].stSubNetInputOutputDesc; // allocate input/output buffers memset(&stIpuRunBufInfo, 0, sizeof(stIpuRunBufInfo)); s32Ret = IPU_Client_AllocTensors(pstTensorDesc, &stTestParam, &stIpuRunBufInfo, &stTensorAddrInfo, EN_INPUT_BUF, 0); if (s32Ret) { goto DESTROY_CHN; } s32Ret = IPU_Client_AllocTensors(pstTensorDesc, &stTestParam, &stIpuRunBufInfo, &stTensorAddrInfo, EN_OUTPUT_BUF, 0); if (s32Ret) { IPU_Client_FreeTensors(&stIpuRunBufInfo, EN_INPUT_BUF); goto DESTROY_CHN; } s32Ret = IPU_Client_GetInputTensorData(stTestParam.InputPath, &pInput, &file_len_in); if (s32Ret != MI_SUCCESS) { printf("Get input data failed!\n"); goto FREE_TENSOR; } memset(&stInvokParam, 0, sizeof(stInvokParam)); memset(&stSubNetInvokeParam, 0, sizeof(MI_IPU_SubNetBatchInvokeParam_t)); memset(&stIPUCASInvokeParam, 0, sizeof(MI_IPU_PCIECasSubNetBatchInvokeParam_t)); stInvokParam.u32BatchN = stTestParam.u32Nbatch; stInvokParam.s32TaskPrio = stTestParam.s32TaskPrio; stInvokParam.u32IpuAffinity = stTestParam.u32IpuAffinity; for (int i = 0; i < stTensorAddrInfo.u32InCnt + stTensorAddrInfo.u32OutCnt; i++) { stInvokParam.astArrayTensors[i] = stTensorAddrInfo.astArrayTensors[i]; } stSubNetInvokeParam.eBatchMode = E_IPU_BATCH_N_BUF_MODE; stSubNetInvokeParam.stInvokeParam = stInvokParam; stIPUCASInvokeParam.stSubnNetBatchInvokeParam = stSubNetInvokeParam; s32Ret = IPU_Client_InsertInputNbatch(pInput, pstTensorDesc, &stInvokParam); if (s32Ret != MI_SUCCESS) { printf("Insert input failed\n"); goto MUNMAP; } total_cnt = stInvokParam.u32BatchN * pstTensorDesc->u32InputTensorCount; // invalid output buffer for (batch_cnt = 0; batch_cnt < stInvokParam.u32BatchN; batch_cnt++) { for (cnt = 0; cnt < pstTensorDesc->u32OutputTensorCount; cnt++) { memset(stInvokParam.astArrayTensors[total_cnt].ptTensorData[0], 0, pstTensorDesc->astMI_OutputTensorDescs[cnt].s32AlignedBufSize); MI_SYS_FlushInvCache(stInvokParam.astArrayTensors[total_cnt].ptTensorData[0], pstTensorDesc->astMI_OutputTensorDescs[cnt].s32AlignedBufSize); total_cnt++; } } memset(&stRuntimeInfo, 0, sizeof(stRuntimeInfo)); while (count < stTestParam.u32LoopCount) { clock_gettime(CLOCK_MONOTONIC, &invoke_start); s32Ret = MI_IPU_PCIECasWrapper_SubNetInvoke(u32ChnId, &stIPUCASInvokeParam, &stRuntimeInfo, stTestParam.u32SubNetId, E_MI_IPU_PCIE_CAS_WORK_MODE_RC); if (s32Ret != MI_SUCCESS) { printf("Invoke failed\n"); goto FREE_TENSOR; } clock_gettime(CLOCK_MONOTONIC, &invoke_end); linux_time = (invoke_end.tv_sec * 1000000 + invoke_end.tv_nsec / 1000) - (invoke_start.tv_sec * 1000000 + invoke_start.tv_nsec / 1000); printf("Run model %s loop%d success, invoke time: %f us\n", stTestParam.ModelPath, count, linux_time); printf("============ Loop%d ipu_time=%lluus\n", count, stRuntimeInfo.u64IpuTime); total_linux_time += linux_time; total_ipu_time += stRuntimeInfo.u64IpuTime; total_bw += stRuntimeInfo.u64BandWidth; total_bw_rd += stRuntimeInfo.u64BandWidthRead; total_bw_wr += stRuntimeInfo.u64BandWidthWrite; count++; } printf("cycles=%lfus linux_fps=%lffps ipu_fps=%lffps bandwidth_total=%llubytes bandwidth_rd=%llubytes bandwidth_wr=%llubytes\n", total_ipu_time/stTestParam.u32LoopCount, 1/(total_linux_time/stTestParam.u32Nbatch/stTestParam.u32LoopCount/1000000), 1/(total_ipu_time/stTestParam.u32LoopCount/1000000), total_bw/stTestParam.u32LoopCount, total_bw_rd/stTestParam.u32LoopCount, total_bw_wr/stTestParam.u32LoopCount); MUNMAP: if (stTestParam.InputPath) munmap(pInput, file_len_in); FREE_TENSOR: IPU_Client_FreeTensors(&stIpuRunBufInfo, EN_INPUT_BUF); IPU_Client_FreeTensors(&stIpuRunBufInfo, EN_OUTPUT_BUF); DESTROY_CHN: MI_IPU_PCIECasWrapper_DestroyCHN(u32ChnId, E_MI_IPU_PCIE_CAS_WORK_MODE_RC); DESTROY_DEV: MI_IPU_PCIECasWrapper_DestroyDevice(E_MI_IPU_PCIE_CAS_WORK_MODE_RC); SYS_EXIT: MI_SYS_Exit(0); return s32Ret; } -
ipu_service#include <stdio.h> #include <stdlib.h> #include <error.h> #include <sys/mman.h> #include <fcntl.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <stdbool.h> #include <poll.h> #include <assert.h> #include <signal.h> #include <getopt.h> #include "mi_sys.h" #include "ipu_service.h" static MI_U32 g_u32MaxWorkThread = 0; static void _IPU_Service_ShowUsage(const char *progName) { printf("Usage: %s [options]\n", progName); printf("Options:\n"); printf(" -t show number of work thread\n"); printf(" -h show this help message\n"); } static MI_S32 _IPU_Service_ParseArgs(int argc, char *argv[]) { int opt; int option_index = 0; static struct option long_options[] = { {"t", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; while ((opt = getopt_long(argc, argv, "t:h", long_options, &option_index)) != -1) { switch (opt) { case 't': { MI_U32 u32ThreadCount = strtoul(optarg, NULL, 10); g_u32MaxWorkThread = u32ThreadCount; break; } case 'h': _IPU_Service_ShowUsage(argv[0]); return 1; // Signal to exit after showing help default: printf("Unknown option: %c\n", opt); _IPU_Service_ShowUsage(argv[0]); return -1; } } // Check for remaining non-option arguments if (optind < argc) { printf("Unknown arguments: "); for (int i = optind; i < argc; i++) { printf("%s ", argv[i]); } printf("\n"); _IPU_Service_ShowUsage(argv[0]); return -1; } return 0; } int main(int argc, char *argv[]) { MI_S32 s32Ret; MI_IPU_PCIECasServiceConfig_t stCasServiceCfg; // Parse command line arguments s32Ret = _IPU_Service_ParseArgs(argc, argv); if (s32Ret < 0) { return -1; } else if (s32Ret > 0) { return 0; // Help was shown, exit normally } printf("IPU Service starting with thread number: %u\n", g_u32MaxWorkThread); MI_SYS_Init(0); memset(&stCasServiceCfg, 0, sizeof(stCasServiceCfg)); stCasServiceCfg.u32MaxWorkThread = g_u32MaxWorkThread; if (MI_IPU_PCIECasWrapper_RunService(&stCasServiceCfg) != MI_SUCCESS) { printf("Failed to start EP service\n"); return -1; } MI_IPU_PCIECasWrapper_StopService(); MI_SYS_Exit(0); printf("Service exited cleanly\n"); return 0; }
2. API参考¶
2.1. 功能模块API¶
| API名 | 功能 |
|---|---|
| MI_IPU_PCIECasWrapper_GetOfflineStaticInfo | 读取级联离线模型的静态信息 |
| MI_IPU_PCIECasWrapper_CreateDevice | 创建级联设备 |
| MI_IPU_PCIECasWrapper_CreateCHN | 创建级联通道 |
| MI_IPU_PCIECasWrapper_SubNetInvoke | 触发级联模型推理 |
| MI_IPU_PCIECasWrapper_QueryRemoteInputBufInfo | 查询远端input buffer信息 |
| MI_IPU_PCIECasWrapper_SetRemoteInputBuf | 写入远端input buffer |
| MI_IPU_PCIECasWrapper_GetRemoteInputBuf | 读回远端input buffer |
| MI_IPU_PCIECasWrapper_DestroyCHN | 销毁级联通道 |
| MI_IPU_PCIECasWrapper_DestroyDevice | 销毁级联设备 |
| MI_IPU_PCIECasWrapper_RunService | 启动EP端服务 |
| MI_IPU_PCIECasWrapper_StopService | 停止EP端服务 |
2.2. MI_IPU_PCIECasWrapper_GetOfflineStaticInfo¶
-
功能
解析离线模型头信息,获取 SoC 数量、模型大小与变量缓冲需求。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_GetOfflineStaticInfo(SerializedReadFunc pReadFunc, char *pReadCtx, MI_IPU_PCIECasOfflineModelStaticInfo_t *pStaticInfo); -
形参
参数名称 描述 输入/输出 pReadFunc 用户自定义读取文件函数(设为NULL默认使用IPU Cascade API提供的文件读取函数) 输入 pReadCtx 模型路径 输入 pStaticInfo 离线级联模型静态信息结构体指针 输出 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasOfflineModelStaticInfo_t stStaticInfo; memset(&stStaticInfo, 0, sizeof(stStaticInfo)); if (MI_IPU_PCIECasWrapper_GetOfflineStaticInfo(NULL, stTestParam.ModelPath, &stStaticInfo) != MI_SUCCESS) { printf("fail to read cascade model info\n"); return -1; }
2.3. MI_IPU_PCIECasWrapper_CreateDevice¶
-
功能
创建级联设备,初始化级联运行环境。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_CreateDevice(MI_IPU_PCIECasDevAttr_t *pstIPUDevAttr, SerializedReadFunc pReadFunc, char *pReadCtx, MI_IPU_PCIECasWorkMode_e eWorkMode); -
形参
参数名称 描述 输入/输出 pstIPUDevAttr 级联设备属性,包含 SoC 数及各 SoC 变量区上限 输入 pReadFunc 可选固件读取函数 输入 pReadCtx 固件路径或上下文 输入 eWorkMode 工作模式: E_MI_IPU_PCIE_CAS_WORK_MODE_RC或E_MI_IPU_PCIE_CAS_WORK_MODE_EP输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasDevAttr_t stCasAttr; memset(&stCasAttr, 0, sizeof(stCasAttr)); stCasAttr.u32SocNum = stStaticInfo.u32SocNum; memcpy(stCasAttr.au32MaxVariableBufSize, stStaticInfo.au32VariableBufferSize, sizeof(stCasAttr.au32MaxVariableBufSize)); if (MI_IPU_PCIECasWrapper_CreateDevice(&stCasAttr, NULL, NULL, E_MI_IPU_PCIE_CAS_WORK_MODE_RC) != MI_SUCCESS) { printf("create cascade device failed\n"); return -1; }
2.4. MI_IPU_PCIECasWrapper_CreateCHN¶
-
功能
创建级联通道。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_CreateCHN(MI_IPU_CHN *ptChnId, MI_IPUChnAttr_t *pstChnAttr, SerializedReadFunc pReadFunc, char *pReadCtx, MI_IPU_PCIECasWorkMode_e eWorkMode); -
形参
参数名称 描述 输入/输出 ptChnId 返回建立成功的通道号 输出 pstChnAttr 通道属性(输入/输出队列深度、子网 ID 等) 输入 pReadFunc 模型读取函数,可为空 输入 pReadCtx RC:模型路径;EP:模型物理地址上下文 输入 eWorkMode 工作模式:RC/EP 输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_CHN u32ChnId = 0; MI_IPUChnAttr_t stChnAttr; memset(&stChnAttr, 0, sizeof(stChnAttr)); stChnAttr.u32InputBufDepth = 2; stChnAttr.u32OutputBufDepth = 2; if (MI_IPU_PCIECasWrapper_CreateCHN(&u32ChnId, &stChnAttr, NULL, stTestParam.ModelPath, E_MI_IPU_PCIE_CAS_WORK_MODE_RC) != MI_SUCCESS) { printf("create cascade channel failed\n"); return -1; }
2.5. MI_IPU_PCIECasWrapper_SubNetInvoke¶
-
功能
执行级联模型推理。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_SubNetInvoke(MI_IPU_CHN u32ChnId, MI_IPU_PCIECasSubNetBatchInvokeParam_t *pstInvokeParam, MI_IPU_RuntimeInfo_t *pstRuntimeInfo, MI_U32 u32SubNetId, MI_IPU_PCIECasWorkMode_e eWorkMode); -
形参
参数名称 描述 输入/输出 u32ChnId 待执行的通道号 输入 pstInvokeParam 级联批处理参数,包含输入/输出 Tensor 信息与共享输出位置 输入 pstRuntimeInfo 推理运行信息(时间、带宽等) 输出 u32SubNetId 目标子网 ID 输入 eWorkMode 工作模式:RC/EP 输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasSubNetBatchInvokeParam_t stInvokeParam; memset(&stInvokeParam, 0, sizeof(stInvokeParam)); stInvokeParam.stSubnNetBatchInvokeParam.u32BatchN = stTestParam.u32Nbatch; /* 根据模型填充输入/输出 Tensor */ if (MI_IPU_PCIECasWrapper_SubNetInvoke(u32ChnId, &stInvokeParam, &stRuntimeInfo, stTestParam.u32SubNetId, E_MI_IPU_PCIE_CAS_WORK_MODE_RC) != MI_SUCCESS) { printf("invoke cascade subnet failed\n"); return -1; }
2.6. MI_IPU_PCIECasWrapper_QueryRemoteInputBufInfo¶
-
功能
查询指定 EP 的input tensor buffer信息(数量、大小与物理地址)。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_QueryRemoteInputBufInfo(MI_IPU_CHN u32ChnId, MI_U32 u32EpId, MI_IPU_PCIECasInputDesc_t *pstCasInputDesc); -
形参
参数名称 描述 输入/输出 u32ChnId 待执行的通道号 ID 输入 u32EpId 目标 EP 板卡编号 输入 pstCasInputDesc 返回的远端输入 Tensor 描述指针,内含 u32TensorCount以及每个 Tensor 的缓冲大小/地址输出 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasInputDesc_t stRemoteInputDesc; memset(&stRemoteInputDesc, 0, sizeof(stRemoteInputDesc)); if (MI_IPU_PCIECasWrapper_QueryRemoteInputBufInfo(u32ChnId, 0, &stRemoteInputDesc) != MI_SUCCESS) { printf("query remote input buffer failed\n"); return -1; }
2.7. MI_IPU_PCIECasWrapper_SetRemoteInputBuf¶
-
功能
使用DMA linklist模式将本端 tensor 数据写入远端 EP 的input buffer。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_SetRemoteInputBuf(MI_IPU_CHN u32ChnId, MI_U32 u32EpId, MI_IPU_PCIECasTransferDesc_t *pstCasTransferDesc); -
形参
参数名称 描述 输入/输出 u32ChnId 待执行的通道号 输入 u32EpId 目标 EP 板卡编号 输入 pstCasTransferDesc linklist描述符,包含 u32LinklistCount以及至多MI_IPU_PCIE_CASCADE_MAX_LINKLIST_CNT个搬运节点输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasTransferDesc_t stTransferDesc; memset(&stTransferDesc, 0, sizeof(stTransferDesc)); stTransferDesc.u32LinklistCount = 1; stTransferDesc.astTransferLinklist[0].phySrcAddr = stLocalTensor.phyTensorAddr[0]; stTransferDesc.astTransferLinklist[0].phyDstAddr = stRemoteInputDesc.astInputTensroDesc[0].phyTensorAddr; stTransferDesc.astTransferLinklist[0].u64TransferSize = stRemoteInputDesc.astInputTensroDesc[0].u64TensorBufSize; if (MI_IPU_PCIECasWrapper_SetRemoteInputBuf(u32ChnId, 0, &stTransferDesc) != MI_SUCCESS) { printf("set remote input buffer failed\n"); return -1; }
2.8. MI_IPU_PCIECasWrapper_GetRemoteInputBuf¶
-
功能
使用DMA linklist模式从远端 EP input buffer读取数据。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_GetRemoteInputBuf(MI_IPU_CHN u32ChnId, MI_U32 u32EpId, MI_IPU_PCIECasTransferDesc_t *pstCasTransferDesc); -
形参
参数名称 描述 输入/输出 u32ChnId 待执行的通道号 输入 u32EpId 目标 EP 板卡编号 输入 pstCasTransferDesc linklist描述符。每个节点指定远端源地址、本地目标地址及传输大小 输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasTransferDesc_t stPullDesc; memset(&stPullDesc, 0, sizeof(stPullDesc)); stPullDesc.u32LinklistCount = 1; stPullDesc.astTransferLinklist[0].phySrcAddr = stRemoteInputDesc.astInputTensroDesc[0].phyTensorAddr; stPullDesc.astTransferLinklist[0].phyDstAddr = stLocalTensor.phyTensorAddr[0]; stPullDesc.astTransferLinklist[0].u64TransferSize = stRemoteInputDesc.astInputTensroDesc[0].u64TensorBufSize; if (MI_IPU_PCIECasWrapper_GetRemoteInputBuf(u32ChnId, 0, &stPullDesc) != MI_SUCCESS) { printf("get remote input buffer failed\n"); }
2.9. MI_IPU_PCIECasWrapper_DestroyCHN¶
-
功能
销毁指定级联通道。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_DestroyCHN(MI_IPU_CHN u32ChnId, MI_IPU_PCIECasWorkMode_e eWorkMode); -
形参
参数名称 描述 输入/输出 u32ChnId 待销毁的通道号 输入 eWorkMode 工作模式:RC/EP 输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasWrapper_DestroyCHN(u32ChnId, E_MI_IPU_PCIE_CAS_WORK_MODE_RC);
2.10. MI_IPU_PCIECasWrapper_DestroyDevice¶
-
功能
销毁级联设备。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_DestroyDevice(MI_IPU_PCIECasWorkMode_e eWorkMode); -
形参
参数名称 描述 输入/输出 eWorkMode 工作模式:RC/EP 输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasWrapper_DestroyDevice(E_MI_IPU_PCIE_CAS_WORK_MODE_RC);
2.11. MI_IPU_PCIECasWrapper_RunService¶
-
功能
在 EP 端启动级联服务,创建请求处理线程,监听RC端请求并处理。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_RunService(const MI_IPU_PCIECasServiceConfig_t *pstConfig); -
形参
参数名称 描述 输入/输出 pstConfig EP 服务配置,包含最大工作线程、PCIe ID、心跳超时阈值及心跳周期 输入 -
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
注意
pstConfig参数可设置为NULL,设置为NULL时EP端服务采用默认配置
-
举例
MI_IPU_PCIECasServiceConfig_t stServiceCfg = { .u32MaxWorkThread = 4, .u32PcieId = 0, .u32HeartbeatTimeoutCountThreshold = 30, .s32HeartbeatTimeoutMs = 1000, }; if (MI_IPU_PCIECasWrapper_RunService(&stServiceCfg) != MI_SUCCESS) { printf("run pcie cascade service failed\n"); return -1; }
2.12. MI_IPU_PCIECasWrapper_StopService¶
-
功能
关闭 EP 端服务线程并释放相关资源。
-
语法
MI_S32 MI_IPU_PCIECasWrapper_StopService(void); -
形参
无。
-
返回值
-
MI_SUCCESS 表示成功
-
非MI_SUCCESS失败,参照错误码
-
-
依赖
-
头文件:mi_ipu_pcie_cascade.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_PCIECasWrapper_StopService();
3. 数据类型¶
3.1. 数据类型定义¶
| 数据类型 | 功能 |
|---|---|
| MI_IPU_PCIECasWorkMode_e | 定义 RC/EP 工作模式 |
| MI_IPU_PCIECasOfflineModelStaticInfo_t | 定义IPU离线级联模型静态信息结构体 |
| MI_IPU_PCIECasDevAttr_t | 定义IPU级联设备属性结构体 |
| MI_IPU_PCIECasPosition_t | 定义模型输出的位置与偏移结构体 |
| MI_IPU_PCIECasSubNetBatchInvokeParam_t | 定义级联模型的子网批处理参数结构体 |
| MI_IPU_PCIECasServiceConfig_t | 定义EP服务运行参数结构体 |
| MI_IPU_PCIECasTensorDesc_t | 定义远端Tensor缓冲描述 |
| MI_IPU_PCIECasInputDesc_t | 定义远端输入Tensor集合描述 |
| MI_IPU_PCIECasTransferLinklist_t | 定义远端搬运链表节点结构体 |
| MI_IPU_PCIECasTransferDesc_t | 定义远端搬运链表描述结构体 |
3.2. MI_IPU_PCIECasWorkMode_e¶
-
说明
定义 IPU Cascade API 支持的工作模式,区分 RC 与 EP 两侧的接口调用。
-
语法
typedef enum { E_MI_IPU_PCIE_CAS_WORK_MODE_RC = 0, E_MI_IPU_PCIE_CAS_WORK_MODE_EP, } MI_IPU_PCIECasWorkMode_e; -
成员
成员名称 描述 E_MI_IPU_PCIE_CAS_WORK_MODE_RC 以 RC 模式调用 API E_MI_IPU_PCIE_CAS_WORK_MODE_EP 以 EP 模式调用 API
3.3. MI_IPU_PCIECasOfflineModelStaticInfo_t¶
-
说明
定义IPU离线级联模型静态信息结构体
-
语法
typedef struct MI_IPU_PCIECasOfflineModelStaticInfo_s { MI_U32 u32SocNum; MI_U64 u64OfflineModelSize; MI_U32 au32VariableBufferSize[SGS_MULTI_SOC_NUM]; } MI_IPU_PCIECasOfflineModelStaticInfo_t; -
成员
成员名称 描述 u32SocNum 运行离线级联模型需要的Soc数量 u64OfflineModelSize 离线级联模型大小 au32VariableBufferSize 各个Soc上离线模型需要的variable buffer size
3.4. MI_IPU_PCIECasDevAttr_t¶
-
说明
定义IPU级联设备属性结构体
-
语法
typedef struct MI_IPU_PCIECasDevAttr_s { MI_U32 u32SocNum; MI_U32 au32MaxVariableBufSize[SGS_MULTI_SOC_NUM]; MI_IPU_DevAttr_t stIPUDevAttr; MI_U32 au32Reserve[8]; } MI_IPU_PCIECasDevAttr_t; -
成员
成员名称 描述 u32SocNum 运行离线级联模型需要的Soc数量 au32MaxVariableBufSize 各个Soc上离线模型需要的variable buffer size stIPUDevAttr MI IPU 设备属性 au32Reserve 预留位
3.5. MI_IPU_PCIECasPosition_t¶
-
说明
定义级联离线模型输出偏移信息结构体
-
语法
typedef struct MI_IPU_PCIECasPosition_s { MI_U32 u32OutIndex; MI_U64 u64OffsetByBytes; } MI_IPU_PCIECasPosition_t; -
成员
成员名称 描述 u32OutIndex 需要偏移输出的下标 u64OffsetByBytes 相对于输出起始地址的字节偏移
3.6. MI_IPU_PCIECasSubNetBatchInvokeParam_t¶
-
说明
定义推理级联离线模型时的批处理参数信息
-
语法
typedef struct MI_IPU_PCIECasSubNetBatchInvokeParam_s { MI_IPU_SubNetBatchInvokeParam_t stSubnNetBatchInvokeParam; MI_IPU_PCIECasPosition_t * pstPosition; MI_U32 u32PositionNum; } MI_IPU_PCIECasSubNetBatchInvokeParam_t; -
成员
成员名称 描述 stSubnNetBatchInvokeParam 标准子网络批处理参数,继承自MI IPU pstPosition 离线级联模型输出偏移信息数组指针 u32PositionNum 离线级联模型需要偏移的输出数量
3.7. MI_IPU_PCIECasServiceConfig_t¶
-
说明
定义EP端服务运行配置。
-
语法
typedef struct MI_IPU_PCIECasServiceConfig_s { MI_U32 u32MaxWorkThread; MI_U32 u32PcieId; MI_U32 u32HeartbeatTimeoutCountThreshold; MI_S32 s32HeartbeatTimeoutMs; MI_U32 au32Reserve[8]; } MI_IPU_PCIECasServiceConfig_t; -
成员
成员名称 描述 u32MaxWorkThread EP 服务允许的最大工作线程数 u32PcieId 选用的 PCIe 设备ID u32HeartbeatTimeoutCountThreshold 心跳超时计数阈值,超过即判定 RC 断连 s32HeartbeatTimeoutMs 心跳间隔时间(毫秒) au32Reserve 预留字段
3.8. MI_IPU_PCIECasTensorDesc_t¶
-
说明
定义远端输入 Tensor 缓冲描述。
-
语法
typedef struct MI_IPU_PCIECasTensorDesc_s { MI_U64 u64TensorBufSize; MI_PHY phyTensorAddr; } MI_IPU_PCIECasTensorDesc_t; -
成员
成员名称 描述 u64TensorBufSize 当前 Tensor 缓冲大小(字节) phyTensorAddr 缓冲所在物理地址(远端 EP 视角)
3.9. MI_IPU_PCIECasInputDesc_t¶
-
说明
定义远端 EP 输入 Tensor 信息。
-
语法
typedef struct MI_IPU_PCIECasInputDesc_s { MI_U32 u32TensorCount; MI_IPU_PCIECasTensorDesc_t astInputTensroDesc[MI_IPU_MAX_TENSOR_CNT]; } MI_IPU_PCIECasInputDesc_t; -
成员
成员名称 描述 u32TensorCount 输入 Tensor 数量 astInputTensroDesc 每个输入 Tensor 的物理地址与大小
3.10. MI_IPU_PCIECasTransferLinklist_t¶
-
说明
定义一次DMA搬运操作的linklist节点。
-
语法
typedef struct MI_IPU_PCIECasTransferLinkList_s { MI_PHY phySrcAddr; MI_PHY phyDstAddr; MI_U64 u64TransferSize; } MI_IPU_PCIECasTransferLinklist_t; -
成员
成员名称 描述 phySrcAddr 源物理地址(RC 或 EP) phyDstAddr 目标物理地址(RC 或 EP) u64TransferSize 本节点传输字节数
3.11. MI_IPU_PCIECasTransferDesc_t¶
-
说明
定义一次或多次DMA搬运操作的linklist集合。
-
语法
typedef struct MI_IPU_PCIECasTransferDesc_s { MI_U32 u32LinklistCount; MI_IPU_PCIECasTransferLinklist_t astTransferLinklist[MI_IPU_PCIE_CASCADE_MAX_LINKLIST_CNT]; } MI_IPU_PCIECasTransferDesc_t; -
成员
成员名称 描述 u32LinklistCount 搬运节点数量,不超过 MI_IPU_PCIE_CASCADE_MAX_LINKLIST_CNTastTransferLinklist 搬运节点数组,依次描述每段搬运的源/目标地址及大小
4. 错误码¶
表4-1 IPU Cascade 错误码
| 错误代码 | 宏定义 | 描述 |
|---|---|---|
| 0 | MI_SUCCESS | Success |
| 1 | E_MI_IPU_PCIE_CAS_ERR_INVALID_PARAM | Invalid or missing parameter |
| 2 | E_MI_IPU_PCIE_CAS_ERR_NOMEM | Insufficient system memory |
| 3 | E_MI_IPU_PCIE_CAS_ERR_NOBUF | Cascade buffer unavailable or not allocated |
| 4 | E_MI_IPU_PCIE_CAS_ERR_TIMEOUT | Operation timeout |
| 5 | E_MI_IPU_PCIE_CAS_ERR_PCIE_INIT_FAIL | PCIe / communication initialization failure |
| 6 | E_MI_IPU_PCIE_CAS_ERR_MISMATCH_MODEL | Offline model mismatch with platform/mode |
| 7 | E_MI_IPU_PCIE_CAS_ERR_INVALID_SOC_NUM | Invalid SoC count declared by the model |
| 8 | E_MI_IPU_PCIE_CAS_ERR_RC_INVOKE_FAIL | RC-side inference failure |
| 9 | E_MI_IPU_PCIE_CAS_ERR_EP_INVOKE_FAIL | EP-side inference failure |
| 10 | E_MI_IPU_PCIE_CAS_ERR_FAIL | Unknown or general failure |
| 11 | E_MI_IPU_PCIE_CAS_ERR_FILE_OPERATION | File read/write failure |
| 12 | E_MI_IPU_PCIE_CAS_ERR_CONNECTION_FAIL | RC–EP connection failure |
| 13 | E_MI_IPU_PCIE_CAS_ERR_MISMATCH_MSG | Message type/content mismatch |
| 14 | E_MI_IPU_PCIE_CAS_ERR_CONNECTION_TIMEOUT | Heartbeat or connection timeout |
| 15 | E_MI_IPU_PCIE_CAS_ERR_RESPONSE_THREAD_FAIL | Response-thread creation/runtime failure |
| 16 | E_MI_IPU_PCIE_CAS_ERR_NO_ENOUGH_EP | Not enough active EPs |
| 17 | E_MI_IPU_PCIE_CAS_ERR_INVALID_CHNID | Invalid or nonexistent channel ID |
| 18 | E_MI_IPU_PCIE_CAS_ERR_INVALID_SUBNET_ID | Invalid subnet ID requested by RC |
| 19 | E_MI_IPU_PCIE_CAS_ERR_MODEL_CORRUPTED | Offline model is corrupted |
| 20 | E_MI_IPU_PCIE_CAS_ERR_MAP | Address mapping failure (MMU/MAP error) |
| 21 | E_MI_IPU_PCIE_CAS_ERR_DEVICE_NOT_READY | Device is not ready for the requested op |