日期: 2026-03-21
系列: Qcom ARM平台Windows驱动开发
问题版本: BH202 v1043 (qcom-bh202-20250114 → bh202-debug-2025-0310)
适用: Windows ARM 驱动开发者、电源管理调试工程师
1. 问题概述
1.1 现象描述
| 项目 |
描述 |
| 问题 |
S4 Hibernate 测试过程中发生异常关机 (Abnormal Shutdown) |
| 发生概率 |
几乎 100% 必现 |
| 复现条件 |
即使没有 SD 卡在位也会发生 |
| 时间窗口 |
S4 开始后约 1 分钟内 |
1.2 问题背景
此问题的引入背景是为了修复以下问题:
- v1042 问题: 设备在 D0 状态保持,无法进入 D3
- v1042 问题: 快速插拔卡时不弹出卡
为了修复这些问题,v1043 进行了多项修改,但意外引入了 S4 Hibernate 异常关机的新问题。
2. 根因分析
2.1 核心问题定位
根本原因: pofx_request_d3 的 timeout 时间从 5 秒大幅降低到 1 秒
2.2 代码变更对比
v1042 版本 (有问题之前的版本):
1 2 3 4 5 6 7 8 9 10 11 12
| int pofx_request_d3(bht_dev_ext_t *pdx, int timeout){ int wait_time_s; if(timeout){ wait_time_s = timeout; util_init_waitloop(pdx, wait_time_s*1000, 0, &wait); } }
pofx_request_d3(pdx, 5);
|
v1043 版本 (引入问题的版本):
1 2 3 4 5 6 7 8 9 10
| int pofx_request_d3(bht_dev_ext_t *pdx, int timeout_ms){ if(timeout_ms){ util_init_waitloop(pdx, timeout_ms, 0, &wait); } }
pofx_request_d3(pdx, 1000);
|
2.3 问题分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| ┌─────────────────────────────────────────────────────────────────────┐ │ S4 Hibernate 异常关机根因分析 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ S4 Hibernate 过程中 Windows 需要做的事情: │ │ ────────────────────────────────────────────────────────── │ │ │ │ 1. 暂停所有应用程序 │ │ 2. 通知所有驱动程序准备进入 S4 │ │ 3. ★ 将内存内容写入 hiberfil.sys 文件 (最耗时!) │ │ 4. 等待所有驱动程序确认进入 D3 │ │ 5. 关闭电源 │ │ │ │ ────────────────────────────────────────────────────────────────── │ │ │ │ 问题时序: │ │ ───────── │ │ │ │ T0: Windows 开始 S4 hibernate │ │ │ │ │ ▼ │ │ T1: 调用 ScsiAdapterPower(StorPowerActionHibernate, D3) │ │ │ │ │ ▼ │ │ T2: 驱动调用 req_pre_enter_d3() │ │ │ │ │ ▼ │ │ T3: card_power_off() → pofx_request_d3(pdx, 1000) │ │ │ ★ 仅等待 1 秒 │ │ ▼ │ │ T4: ⏰ 1 秒 timeout! (StorPort 正在写 hiberfil.sys,还很忙) │ │ │ │ │ ▼ │ │ T5: card_request_d3 标志位被强制清 0 │ │ │ │ │ ▼ │ │ T6: 返回 -1 (失败) │ │ │ │ │ ▼ │ │ T7: 驱动认为已进入 D3,但 StorPort 还在等待确认 │ │ │ │ │ ▼ │ │ T8: 💥 Windows 电源管理器检测到状态不一致 │ │ │ │ │ ▼ │ │ T9: Abnormal Shutdown (异常关机) │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
2.4 代码证据链
证据 1: 超时后强制清标志位:
1 2 3 4 5 6
| if (os_atomic_read(&gHwResTbl.card_request_d3)){ PrintDebug("%s: timeout! card_request_d3 not response\n", __FUNCTION__); os_atomic_set(&gHwResTbl.card_request_d3, 0); return -1; }
|
证据 2: 第二次调用会直接返回:
1 2 3 4 5 6
| pofx_active = os_atomic_read(&pdx->pofx_active); if(!pofx_active){ PrintDebug("%s: pofx already idle, exit \n", __FUNCTION__); return 0; }
|
证据 3: S4 过程中有两次 card_power_off 调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void req_enter_d3(bht_dev_ext_t *pdx) { func_autotimer_stop(pdx); card_power_off(&(pdx->card), FALSE); }
void req_pre_enter_d3(bht_dev_ext_t *pdx) { if (card_stop_infinite(&pdx->card, FALSE, NULL) == FALSE) card_power_off(&(pdx->card), TRUE); }
|
3. 修复方案
3.1 推荐方案:动态调整 Timeout
根据系统电源状态使用不同的 timeout 值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
void card_power_off(sd_card_t *card, bool directly) { PrintDebug("Enter %s directy=%d\n", __FUNCTION__, directly);
if (directly) goto next;
if (card_resume_sleep(card, FALSE) == FALSE) goto next;
if (card_stop_infinite(card, FALSE, NULL) == FALSE) goto next;
next: if ((card->state != CARD_STATE_POWEROFF) || host_get_vdd1_state(card->host)) host_poweroff(card->host, card->card_type);
bht_dev_ext_t *pdx = card->host->pdx;
int timeout_ms = (pdx->pm_state.s3s4_entered || pdx->pm_state.rtd3_entered) ? 5000 : 1000;
pofx_request_d3(pdx, timeout_ms);
card->state = CARD_STATE_POWEROFF; card->has_built_inf = FALSE;
PrintDebug("Exit %s\n", __FUNCTION__); }
|
3.2 方案说明
| 场景 |
Timeout |
原因 |
| S3/S4 Hibernate |
5000 ms (5秒) |
系统电源管理需要更长时间协调 |
| Runtime D3 (RTD3) |
5000 ms (5秒) |
StorPort 可能正在处理请求 |
| 正常工作 |
1000 ms (1秒) |
快速响应,用户体验 |
3.3 状态检查条件
1 2 3 4 5 6 7
| typedef struct { bool s3s4_entered; bool rtd3_entered; bool rtd3_en; } pm_state_t;
|
4. 修复验证
4.1 测试用例
| 测试项 |
操作 |
预期结果 |
| S4 Hibernate |
进入 S4 → 观察 |
无异常关机,正常休眠 |
| S4 Resume |
S4 → 唤醒 |
正常恢复,卡功能正常 |
| RTD3 |
空闲 10 秒 |
进入 D3,无异常唤醒 |
| 快速插拔 |
快速插拔 SD 卡 |
正常识别,无卡住 |
4.2 日志验证点
修复后,在 S4 过程中应看到以下日志:
1 2 3 4 5
| [PM] Enter card_power_off directy=0 [PM] s3s4_entered=1, timeout_ms=5000 // ★ 使用 5 秒 timeout [PM] PoFxRequestD3: RefCount 1 -> 0 [PM] PoFxIdleComponent called [PM] Exit card_power_off
|
5. 问题总结
5.1 根因总结
| 项目 |
描述 |
| 根本原因 |
PoFx timeout 参数单位变更导致实际等待时间大幅缩短 |
| 触发条件 |
S4 Hibernate 过程中 StorPort 响应延迟 |
| 影响范围 |
所有 S4 测试场景 (100% 复现) |
| 问题定位 |
参数单位变更: 秒 → 毫秒 |
5.2 经验教训
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| ┌─────────────────────────────────────────────────────────────────────┐ │ 代码修改经验教训 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 1. ★ 参数单位变更必须配套修改所有调用处 │ │ ───────────────────────────────────────── │ │ 问题: timeout 参数从 int timeout 改为 int timeout_ms │ │ 后果: 调用处的 "5" 从 5 秒变成了 5 毫秒 │ │ │ │ 2. ★ 电源管理 timeout 必须考虑系统电源状态 │ │ ───────────────────────────────────────── │ │ S3/S4: StorPort 可能忙于写 hiberfil.sys │ │ Runtime: StorPort 可能有待处理请求 │ │ 正常: 快速响应即可 │ │ │ │ 3. ★ 修改前必须评估对所有调用路径的影响 │ │ ───────────────────────────────────────── │ │ card_power_off() 在多处被调用 │ │ 每处调用可能有不同的 timeout 需求 │ │ │ │ 4. ★ 添加参数单位到参数名中 │ │ ───────────────────────────────────────── │ │ 好: timeout_ms, timeout_s, wait_count │ │ 差: timeout, delay, wait │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
5.3 修复代码片段
完整修复代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
void card_power_off(sd_card_t *card, bool directly) {
bht_dev_ext_t *pdx = card->host->pdx;
int timeout_ms = (pdx->pm_state.s3s4_entered || pdx->pm_state.rtd3_entered) ? 5000 : 1000;
pofx_request_d3(pdx, timeout_ms);
}
|
6. 相关代码改动记录
6.1 v1042 → v1043 变更摘要
| 文件 |
变更 |
目的 |
副作用 |
cardinterface.c |
timeout 5→1秒 |
快速响应拔卡 |
引入 S4 问题 |
cardinterface.c |
timeout 参数名改为 _ms |
代码规范 |
配合参数变更 |
pmfunc.c |
D3 进入流程调整 |
改善 D0 卡住问题 |
无明显副作用 |
irqhandler.c |
中断检查移除 |
改善卡检测 |
无明显副作用 |
6.2 后续修复
| 版本 |
修复内容 |
| v1044+ |
恢复 timeout 5秒,添加 s3s4_entered 检查 |
7. 调试技巧
7.1 快速定位类似问题
当遇到 S4/S3 异常关机时,检查以下内容:
1 2 3 4 5
| 1. pofx_request_d3 的 timeout 设置 2. s3s4_entered 标志是否正确设置 3. StorPort 响应时间是否足够 4. 中断处理是否在 S4 过程中被正确处理
|
7.2 日志宏
1 2 3 4 5 6 7
| #if DBG DbgInfo("PoFx: s3s4_entered=%d, rtd3_entered=%d, timeout=%d\n", pdx->pm_state.s3s4_entered, pdx->pm_state.rtd3_entered, timeout_ms); #endif
|
8. 参考信息
8.1 相关文档
8.2 版本信息
| 版本 |
日期 |
描述 |
| qcom-bh202-20250114-rc1 |
2025-01-14 |
v1042,稳定版本 |
| bh202-debug-2025-0310-release |
2025-03-10 |
v1043,引入问题 |
| v1044+ |
2025-xx-xx |
修复版本 |
9. 总结
9.1 关键要点
| 要点 |
说明 |
| 单位一致性 |
参数单位变更必须同步修改所有调用处 |
| 场景感知 |
电源管理 timeout 应根据系统状态动态调整 |
| 测试覆盖 |
每次修改后测试 S3/S4/RTD3 所有场景 |
| 日志记录 |
添加关键路径日志便于问题定位 |
9.2 修复确认
文档生成日期: 2026-03-21
问题版本: BH202 v1043
修复版本: BH202 v1044+