下面介绍了 UE 挂起检测的步骤 1 到 14。 这些步骤对应于 UE 挂起检测和恢复流中显示的关系图。
此示例使用 OID_SET_POWER。
NDIS 接收系统电源 IRP 或 NIC 活动引用数减少至 0。
NDIS 向 WDI 驱动程序发送 OID_SET_POWER D3。
WDI 为 WDI 命令(M1)设置计时器,其中包括在将 WDI OID 发送到 LE 之前的一项任务。 如果命令是任务,则还会设置该任务的附加计时器。 这两个计时器都可以超时,但最多只有一个能触发重置恢复。
WDI 将 WDI 命令发送到 LE。 建议 LE 将 WDI OID 记入适配器结构中,如果需要通过固件命令来完成 OID。 当固件完成 WDI OID 的作业时,LE 将完成 OID 并将其从适配器结构中删除。 由于 WDI 将 OID 序列化为 LE,LE 只需要一个插槽来记住挂起的 WDI OID。 如果固件命令挂起,LE 可以随时返回 OID,但不迟于步骤 17 的意外删除(可以在意外删除的情境中),此时固件已被禁用。 对于任何其他情况,LE 只需在固件完成相应的作业时完成 WDI OID,而不管它是在诊断回调之前还是之后。 如果 LE 需要在诊断后记住 WDI OID,则需要另一个存储空间来记住它。 但是,对于诊断后收到的 OID,LE 不应触摸固件以避免级联挂起。
LE 向固件发送命令。
如果固件命令超时,可能是由于固件挂起或运行时间过长。
- 如果固件在超时后完成命令的时间过长,LE 可以完成 WDI 命令。 UE 适当地处理它。
- 如果固件停止响应,则 WDI 命令不会及时完成。 重置硬件时,LE 必须在步骤 16 的突发移除中完成操作,因此在潜在的争用条件下可以安全地完成,无需特殊处理。
WDI 计时器触发以生成 WDI 诊断命令。 此 WDI 命令是对 LE 驱动程序 MiniportWdiAdapterHangDiagnose(而不是 WDI OID)的调用。
LE 收集硬件控制寄存器状态,还可以选择完整固件状态。
- IHV 驱动程序应收集限制为 1KB 的硬件注册内容,并在函数返回中返回它。 此外,在预生产环境中,LE 还应尝试将固件上下文转储到文件中,以便 IHV 可以彻底执行事后调试。 该开关可以作为注册表项实现,以控制硬件寄存器和固件映像的集合。
- LE 还会标记要取消的当前命令。 如果命令完成的速度超过诊断,那么 LE 对于该命令无动于衷是可以接受的。
- 在此命令待处理的情况下,UE 可能会由于重置而发送进一步的 WDI 命令。 这些是执行中的命令或清理指令。 诊断过程后,LE 应该处理这些问题,而无需修改固件。
WDI 接收控制寄存器状态。
WDI 标记挂起的 WDI 命令,以便 LE 稍后指示它。
WDI 在未完成自身操作的情况下返回 NDIS 命令(即完成 NDIS 命令)。 这是安全的,因为 WDI 对 NDIS 命令进行双缓冲处理。
WDI 调用 NDIS 进行重置,然后调用 NdisWriteErrorLogEntry,使用 错误代码NDIS_ERROR_CODE_HARDWARE_FAILURE(0xc000138a)。 这会导致系统事件日志中记录的事件,其模块名称为 LE。 错误事件 ID 自动弹出为 (0xc000138a | 0xffff) – 0n5002。 如果 LE 也使用相同的错误代码来编写错误日志,则数据的第一个 DWORD 应包含高位集(0x80000000),以便通过 LE 轻松分隔事件。 WDI 使用 0x00000000 到 0x7fffffff 作为第一个 DWORD 数据的范围。
调用返回。
NDIS 完成 IRP。
在这一点之后,NDIS 调用公共汽车来意外删除并重新枚举我们。 请务必注意,WDI 对 NDIS 命令进行双重缓冲,这样就不需要等待 WDI 命令返回即可完成 NDIS 命令。 这样就无需 LE 执行取消逻辑,而逻辑则非常复杂。
必须完成 NDIS OID_SET_POWER 以避免 PnP 操作的死锁。 序列化所有 PnP 和电源状态更改事件。 这意味着,如果 Set power OID 未返回,NDIS 将无法返回 Set power IRP,这意味着重置恢复将与 Surprise-Remove IRP 锁住。