概述&背景
在 Linux 环境下,310P 驱动通常采用 SBR 方式实现热复位。由于 Windows 系统的架构限制,Windows 驱动无法获取上级 PCI 桥控制器的权限,因此无法通过 SBR 方式触发复位。故当前310P Windows 驱动通过传统 PCIE 方式进行 Hot Reset 不可行,驱动徽标认证受阻。
解决方法
本文介绍了基于 IPC(Inter-Process Communication)的消息机制实现热复位方案:Host 端通过消息机制发送复位命令,Device 端(大核/泰山核)接收到命令后,向 LP 核(小核/R52核)发送复位消息,最终由 LP 核写入安全寄存器来触发 SOC 的软复位操作。
程序调用流程
从 host 到 device,一次完整的热复位流程如下:

host 侧保持不变
关键接口
--HiNpuEvtDevD0Exit
--D0EntryPostResoureFree
--HiNpuUninitAllModules
--HiNpuNotifyDevOnline
device 侧修改
泰山核(大核)接收 host 侧消息通信
大核(drv_pcie)通过接收 Windows驱动消息检测设备离线状态,并通过回调机制通知 ascend_lpm 发送 IPC 指令。
关键接口
--agentdrv_admin_queue_cmd_proc
--agentdrv_notify_dev_online
--agentdrv_dev_online_proc
- drv_pcie检测到设备离线,触发热复位
在 src/drv_pcie_device/pcie_slave/agentdrv_pci.c 的 agentdrv_dev_online_proc() 函数中,当检测到设备离线状态为DEVDRV_DEV_OFFLINE时,触发热复位回调函数:
#define HOT_RESET_REASON_NORMAL 0x1
#define LPM_SOC_ID 8
STATIC void agentdrv_dev_online_proc(struct agentdrv_msg_dev *msg_dev, u32 online_devid, u32 status)
{
/* ... */
if (status == DEVDRV_DEV_OFFLINE) {
msg_dev->dev_status = DEVDRV_DEV_OFFLINE;
/* ... */
/* 热复位触发时,通过回调通知 ascend_lpm 发送 IPC */
if (g_hot_reset_callback != NULL) {
u32 reset_reason = HOT_RESET_REASON_NORMAL;
ret = g_hot_reset_callback(dev_id, LPM_SOC_ID, &reset_reason);
if (ret != 0) {
devdrv_err("Failed to send hot reset to LP core. (dev_id=%d; ret=%d)\n", dev_id, ret);
}
}
}
}
消息拼装&转发给 LP 核(小核)
由于原设计架构中 ascend_lpm 依赖 drv_pcie,因此采用回调方式。
1. drv_pcie 定义回调接口
在 src/drv_pcie_device/pcie_slave/agentdrv_pci.h 中定义:
typedef int (*agentdrv_hot_reset_callback_t)(u32 dev_id, u32 core_id, u32 *reset_reason);
int agentdrv_register_hot_reset_callback(agentdrv_hot_reset_callback_t callback);
void agentdrv_unregister_hot_reset_callback(void);
2. drv_pcie 实现注册接口
在 src/drv_pcie_device/pcie_slave/agentdrv_pci.c 中实现:
static agentdrv_hot_reset_callback_t g_hot_reset_callback = NULL;
int agentdrv_register_hot_reset_callback(agentdrv_hot_reset_callback_t callback)
{
if (callback == NULL) {
devdrv_err("Invalid callback function.\n");
return -EINVAL;
}
g_hot_reset_callback = callback;
return 0;
}
EXPORT_SYMBOL(agentdrv_register_hot_reset_callback);
void agentdrv_unregister_hot_reset_callback(void)
{
g_hot_reset_callback = NULL;
}
EXPORT_SYMBOL(agentdrv_unregister_hot_reset_callback);
3. ascend_lpm 注册回调
在 src/ascend_lpm/lpm/dms_lpm.c 中,使用外部申明函数,驱动初始化时把lpm_set_hot_reset_from_ipc() 函数注册到drv_pcie,退出时注销:
typedef int (*agentdrv_hot_reset_callback_t)(u32 dev_id, u32 core_id, u32 *reset_reason);
extern int agentdrv_register_hot_reset_callback(agentdrv_hot_reset_callback_t callback);
extern void agentdrv_unregister_hot_reset_callback(void);
int __init dms_lpm_init(void)
{
CALL_INIT_MODULE(DMS_LPM_CMD_NAME);
lpm_dms_info_from_devinfo_init();
#ifndef CFG_SOC_PLATFORM_MDC_V51
lpm_scan_init();
#endif
agentdrv_register_hot_reset_callback(lpm_set_hot_reset_from_ipc);
return 0;
}
void __exit dms_lpm_exit(void)
{
CALL_EXIT_MODULE(DMS_LPM_CMD_NAME);
#ifndef CFG_SOC_PLATFORM_MDC_V51
lpm_scan_uninit();
#endif
lpm_dms_info_from_devinfo_uninit();
agentdrv_unregister_hot_reset_callback();
}
4. IPC 发送接口实现
在 src/ascend_lpm/lpm/dms_lpm_info_from_ipc.c 中,lpm_set_hot_reset_from_ipc() 函数会先进行参数校验,然后组装 struct devdrv_dev_info 结构体,并通过 lpm_get_info_from_ipc() 接口发送 IPC消息:
#ifdef CFG_FEATURE_HOT_RESET_SUPPORT
int lpm_set_hot_reset_from_ipc(u32 dev_id, u32 core_id, u32 *reset_reason)
{
int ret;
u32 len = sizeof(struct devdrv_dev_info);
struct devdrv_dev_info *reset_arg = NULL;
ret = dms_lpm_id_check(dev_id, core_id);
if (ret != 0) {
lpm_err("Parameter error. (dev_id=%u; ret=%d)\n", dev_id, ret);
return ret;
}
reset_arg = (struct devdrv_dev_info *)reset_reason;
ret = lpm_get_info_from_ipc(dev_id, LPM_HOT_RESET, core_id, (u8 *)reset_reason, &len);
if (ret != 0) {
lpm_err("Failed to send hot reset to ipc. (dev_id=%u; core_id=%u; ret=%d)\n",
dev_id, core_id, ret);
return ret;
}
lpm_info("Hot reset sent successfully. (dev_id=%u; core_id=%u; reason=0x%x)\n",
dev_id, core_id, reset_arg->data1);
return 0;
}
EXPORT_SYMBOL(lpm_set_hot_reset_from_ipc);
#endif
LP 核接收消息
LP 核(R52 核)接收到 device 端通过 IPC 发送的热复位指令后,需通过查询(query)模块来解析并处理该指令。
1. IPC 格式列表配置
在 src/ascend_lpm/ipc/dms_ipc_from_lp.c 中,将热复位的 IPC 格式配置加入到 IPC 格式列表 g_ipc_format_list 中:
/* hot reset */
{LPM_HOT_RESET, LPM_SOC_ID, MSG_HEADS_WORD, MSG_TOTAL_WORD,
0, 0, NO_REPEATS, IPC_OBJ_LP, DMS_LP_Q_TX_RPID4_ACPU0,
NULL, lp_ack_check_privte, NULL,
{SUB_CMD_HOT_RESET, CMD_INQUIRY, LPR52_TARGET_ID, LPR52_SOURECE_ID}},
其中:
- 枚举类型:LPM_HOT_RESET
- 子命令:SUB_CMD_HOT_RESET = 106
- IPC 对象:IPC_OBJ_LP,队列:DMS_LP_Q_TX_RPID4_ACPU0
LP侧修改
- 在LP核初始化时,会调用LpQueryInit()函数,该函数里面调用InquiryCmdFunc()——>LpQuery(),然后根据不同的Ipc消息,注册不同的查询函数。
- LpQuery()中,当前基于已有的策略,新增命令字25,调用QueryHotResetInit(),该函数中通过写寄存器实现热复位。
1. LP 查询函数注册与枚举定义
在 LP 核的查询模块 lpr52/driver/query/query_lp.h 中,添加对应的枚举定义:SUBSYS_QUERY_HOT_RESET_INIT = 25
enum {
/* ... */
#ifdef AS610VER2
SUBSYS_QUERY_QOS_BW_INIT = 25,
SUBSYS_QUERY_QOS_BW_DEINIT = 26,
#endif
#ifdef PRODUCT_DC
SUBSYS_QUERY_HOT_RESET_INIT = 25,
#endif
QUERY_MAX_NUM,
};
其中:
SUBSYS_QUERY_HOT_RESET_INIT = SUB_CMD_HOT_RESET - SUB_CMD_QUERY_SOC_TEMP = 25
2/driver/query/query_lp.c 中,首先声明查询函数QueryHotResetInit():
static void(* const g_queryFunc[QUERY_MAX_NUM])(struct IpcMsg *) = {
/* ... */
#ifdef AS610VER2
[SUBSYS_QUERY_QOS_BW_INIT] = QueryQosBandInit,
[SUBSYS_QUERY_QOS_BW_DEINIT] = QueryQosBandDeinit,
#endif
#ifdef PRODUCT_DC
static void QueryHotResetInit(struct IpcMsg *txMsg);
#endif
};
然后在函数指针数组 g_queryFunc 中进行注册,将新增的查询命令字与对应的处理函数关联起来:
[SUBSYS_QUERY_HOT_RESET_INIT] = QueryHotResetInit,
2. LP 核写安全寄存器&执行复位
当 LP 核的 QueryHotResetInit() 函数被调用后,会执行具体的 SOC 软复位操作。该操作通过向复位控制寄存器写入固定值来完成。具体实现代码位于 lpr52/driver/query/query_lp.c 中:
#ifdef PRODUCT_DC
/*
* @brief : SOC热复位
* @param [in] : NA
* @param [out] txMsg : 未使用,保留参数用于接口一致性
* @return : void
*/
#define SC_SYSSOFTRST_CTRL 0x800002C0U
#define SC_SYSSOFTRST_VAL 0x55555555
static void QueryHotResetInit(struct IpcMsg *txMsg)
{
(void)txMsg;
__asm__ volatile("isb");
__asm__ volatile("dsb");
WRITEL(SC_SYSSOFTRST_VAL, SC_SYSSOFTRST_CTRL);
__asm__ volatile("isb");
__asm__ volatile("dsb");
}
#endif
3. 关键执行步骤说明:
- 寄存器定义:
- 软复位控制寄存器地址:SC_SYSSOFTRST_CTRL = 0x800002C0U
- 复位触发值:SC_SYSSOFTRST_VAL = 0x55555555
- 同步指令保障:
- 在写入复位寄存器之前和之后,分别使用 isb和 dsb确保指令流和数据流的完全同步,保证复位操作在硬件层面能够可靠、准确地触发 SOC 软复位。
上机验证
1. 构建产物
- 大核修改与产物:大核主要修改了 device 侧驱动,编译产物为两个 .ko 文件(ascend_lpm.ko 和 drv_pcie.ko),打包在filesystem-le.cpio.gz压缩包中,该压缩包存在于驱动包目录:driver\device\filesystem-le.cpio.gz。
- 小核修改与产物:小核主要修改了源码,编译产物为 bin 文件(lperika.bin)。该 bin 文件存在于驱动包目录:driver\device\lperika.b
2. 验证结果
在 Windows 设备管理器 中禁用设备之前 & 禁用-启用设备之后,npu-smi & 大小模型测试验证均通过。
npu-smi —— npu-smi info
小模型 —— resnet50
大模型 —— qwen2-7b-f16.gguf
概述&背景
在 Linux 环境下,310P 驱动通常采用 SBR 方式实现热复位。由于 Windows 系统的架构限制,Windows 驱动无法获取上级 PCI 桥控制器的权限,因此无法通过 SBR 方式触发复位。故当前310P Windows 驱动通过传统 PCIE 方式进行 Hot Reset 不可行,驱动徽标认证受阻。
解决方法
本文介绍了基于 IPC(Inter-Process Communication)的消息机制实现热复位方案:Host 端通过消息机制发送复位命令,Device 端(大核/泰山核)接收到命令后,向 LP 核(小核/R52核)发送复位消息,最终由 LP 核写入安全寄存器来触发 SOC 的软复位操作。
程序调用流程
从 host 到 device,一次完整的热复位流程如下:
host 侧保持不变
关键接口
--HiNpuEvtDevD0Exit
--D0EntryPostResoureFree
--HiNpuUninitAllModules
--HiNpuNotifyDevOnline
device 侧修改
泰山核(大核)接收 host 侧消息通信
大核(drv_pcie)通过接收 Windows驱动消息检测设备离线状态,并通过回调机制通知 ascend_lpm 发送 IPC 指令。
关键接口
--agentdrv_admin_queue_cmd_proc
--agentdrv_notify_dev_online
--agentdrv_dev_online_proc
在 src/drv_pcie_device/pcie_slave/agentdrv_pci.c 的 agentdrv_dev_online_proc() 函数中,当检测到设备离线状态为DEVDRV_DEV_OFFLINE时,触发热复位回调函数:
#define HOT_RESET_REASON_NORMAL 0x1
#define LPM_SOC_ID 8
STATIC void agentdrv_dev_online_proc(struct agentdrv_msg_dev *msg_dev, u32 online_devid, u32 status)
{
/* ... */
if (status == DEVDRV_DEV_OFFLINE) {
msg_dev->dev_status = DEVDRV_DEV_OFFLINE;
/* ... */
/* 热复位触发时,通过回调通知 ascend_lpm 发送 IPC */
if (g_hot_reset_callback != NULL) {
u32 reset_reason = HOT_RESET_REASON_NORMAL;
ret = g_hot_reset_callback(dev_id, LPM_SOC_ID, &reset_reason);
if (ret != 0) {
devdrv_err("Failed to send hot reset to LP core. (dev_id=%d; ret=%d)\n", dev_id, ret);
}
}
}
}
消息拼装&转发给 LP 核(小核)
由于原设计架构中 ascend_lpm 依赖 drv_pcie,因此采用回调方式。
1. drv_pcie 定义回调接口
在 src/drv_pcie_device/pcie_slave/agentdrv_pci.h 中定义:
typedef int (*agentdrv_hot_reset_callback_t)(u32 dev_id, u32 core_id, u32 *reset_reason);
int agentdrv_register_hot_reset_callback(agentdrv_hot_reset_callback_t callback);
void agentdrv_unregister_hot_reset_callback(void);
2. drv_pcie 实现注册接口
在 src/drv_pcie_device/pcie_slave/agentdrv_pci.c 中实现:
static agentdrv_hot_reset_callback_t g_hot_reset_callback = NULL;
int agentdrv_register_hot_reset_callback(agentdrv_hot_reset_callback_t callback)
{
if (callback == NULL) {
devdrv_err("Invalid callback function.\n");
return -EINVAL;
}
g_hot_reset_callback = callback;
return 0;
}
EXPORT_SYMBOL(agentdrv_register_hot_reset_callback);
void agentdrv_unregister_hot_reset_callback(void)
{
g_hot_reset_callback = NULL;
}
EXPORT_SYMBOL(agentdrv_unregister_hot_reset_callback);
3. ascend_lpm 注册回调
在 src/ascend_lpm/lpm/dms_lpm.c 中,使用外部申明函数,驱动初始化时把lpm_set_hot_reset_from_ipc() 函数注册到drv_pcie,退出时注销:
typedef int (*agentdrv_hot_reset_callback_t)(u32 dev_id, u32 core_id, u32 *reset_reason);
extern int agentdrv_register_hot_reset_callback(agentdrv_hot_reset_callback_t callback);
extern void agentdrv_unregister_hot_reset_callback(void);
int __init dms_lpm_init(void)
{
CALL_INIT_MODULE(DMS_LPM_CMD_NAME);
lpm_dms_info_from_devinfo_init();
#ifndef CFG_SOC_PLATFORM_MDC_V51
lpm_scan_init();
#endif
agentdrv_register_hot_reset_callback(lpm_set_hot_reset_from_ipc);
return 0;
}
void __exit dms_lpm_exit(void)
{
CALL_EXIT_MODULE(DMS_LPM_CMD_NAME);
#ifndef CFG_SOC_PLATFORM_MDC_V51
lpm_scan_uninit();
#endif
lpm_dms_info_from_devinfo_uninit();
agentdrv_unregister_hot_reset_callback();
}
4. IPC 发送接口实现
在 src/ascend_lpm/lpm/dms_lpm_info_from_ipc.c 中,lpm_set_hot_reset_from_ipc() 函数会先进行参数校验,然后组装 struct devdrv_dev_info 结构体,并通过 lpm_get_info_from_ipc() 接口发送 IPC消息:
#ifdef CFG_FEATURE_HOT_RESET_SUPPORT
int lpm_set_hot_reset_from_ipc(u32 dev_id, u32 core_id, u32 *reset_reason)
{
int ret;
u32 len = sizeof(struct devdrv_dev_info);
struct devdrv_dev_info *reset_arg = NULL;
ret = dms_lpm_id_check(dev_id, core_id);
if (ret != 0) {
lpm_err("Parameter error. (dev_id=%u; ret=%d)\n", dev_id, ret);
return ret;
}
reset_arg = (struct devdrv_dev_info *)reset_reason;
ret = lpm_get_info_from_ipc(dev_id, LPM_HOT_RESET, core_id, (u8 *)reset_reason, &len);
if (ret != 0) {
lpm_err("Failed to send hot reset to ipc. (dev_id=%u; core_id=%u; ret=%d)\n",
dev_id, core_id, ret);
return ret;
}
lpm_info("Hot reset sent successfully. (dev_id=%u; core_id=%u; reason=0x%x)\n",
dev_id, core_id, reset_arg->data1);
return 0;
}
EXPORT_SYMBOL(lpm_set_hot_reset_from_ipc);
#endif
LP 核接收消息
LP 核(R52 核)接收到 device 端通过 IPC 发送的热复位指令后,需通过查询(query)模块来解析并处理该指令。
1. IPC 格式列表配置
在 src/ascend_lpm/ipc/dms_ipc_from_lp.c 中,将热复位的 IPC 格式配置加入到 IPC 格式列表 g_ipc_format_list 中:
/* hot reset */
{LPM_HOT_RESET, LPM_SOC_ID, MSG_HEADS_WORD, MSG_TOTAL_WORD,
0, 0, NO_REPEATS, IPC_OBJ_LP, DMS_LP_Q_TX_RPID4_ACPU0,
NULL, lp_ack_check_privte, NULL,
{SUB_CMD_HOT_RESET, CMD_INQUIRY, LPR52_TARGET_ID, LPR52_SOURECE_ID}},
其中:
LP侧修改
1. LP 查询函数注册与枚举定义
在 LP 核的查询模块 lpr52/driver/query/query_lp.h 中,添加对应的枚举定义:SUBSYS_QUERY_HOT_RESET_INIT = 25
enum {
/* ... */
#ifdef AS610VER2
SUBSYS_QUERY_QOS_BW_INIT = 25,
SUBSYS_QUERY_QOS_BW_DEINIT = 26,
#endif
#ifdef PRODUCT_DC
SUBSYS_QUERY_HOT_RESET_INIT = 25,
#endif
QUERY_MAX_NUM,
};
其中:
SUBSYS_QUERY_HOT_RESET_INIT = SUB_CMD_HOT_RESET - SUB_CMD_QUERY_SOC_TEMP = 25
2/driver/query/query_lp.c 中,首先声明查询函数QueryHotResetInit():
static void(* const g_queryFunc[QUERY_MAX_NUM])(struct IpcMsg *) = {
/* ... */
#ifdef AS610VER2
[SUBSYS_QUERY_QOS_BW_INIT] = QueryQosBandInit,
[SUBSYS_QUERY_QOS_BW_DEINIT] = QueryQosBandDeinit,
#endif
#ifdef PRODUCT_DC
static void QueryHotResetInit(struct IpcMsg *txMsg);
#endif
};
然后在函数指针数组 g_queryFunc 中进行注册,将新增的查询命令字与对应的处理函数关联起来:
[SUBSYS_QUERY_HOT_RESET_INIT] = QueryHotResetInit,
2. LP 核写安全寄存器&执行复位
当 LP 核的 QueryHotResetInit() 函数被调用后,会执行具体的 SOC 软复位操作。该操作通过向复位控制寄存器写入固定值来完成。具体实现代码位于 lpr52/driver/query/query_lp.c 中:
#ifdef PRODUCT_DC
/*
* @brief : SOC热复位
* @param [in] : NA
* @param [out] txMsg : 未使用,保留参数用于接口一致性
* @return : void
*/
#define SC_SYSSOFTRST_CTRL 0x800002C0U
#define SC_SYSSOFTRST_VAL 0x55555555
static void QueryHotResetInit(struct IpcMsg *txMsg)
{
(void)txMsg;
__asm__ volatile("isb");
__asm__ volatile("dsb");
WRITEL(SC_SYSSOFTRST_VAL, SC_SYSSOFTRST_CTRL);
__asm__ volatile("isb");
__asm__ volatile("dsb");
}
#endif
3. 关键执行步骤说明:
上机验证
1. 构建产物
2. 验证结果
在 Windows 设备管理器 中禁用设备之前 & 禁用-启用设备之后,npu-smi & 大小模型测试验证均通过。
npu-smi —— npu-smi info
小模型 —— resnet50
大模型 —— qwen2-7b-f16.gguf