UE 挂起检测:第 1-14 步

下面介绍了 UE 挂起检测的步骤 1 到 14。 这些步骤对应于 UE 挂起检测和恢复流中显示的关系图。

此示例使用 OID_SET_POWER。

  1. NDIS 接收系统电源 IRP 或 NIC 活动引用数减少至 0。

  2. NDIS 向 WDI 驱动程序发送 OID_SET_POWER D3。

  3. WDI 为 WDI 命令(M1)设置计时器,其中包括在将 WDI OID 发送到 LE 之前的一项任务。 如果命令是任务,则还会设置该任务的附加计时器。 这两个计时器都可以超时,但最多只有一个能触发重置恢复。

  4. 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 不应触摸固件以避免级联挂起。

  5. LE 向固件发送命令。

  6. 如果固件命令超时,可能是由于固件挂起或运行时间过长。

    • 如果固件在超时后完成命令的时间过长,LE 可以完成 WDI 命令。 UE 适当地处理它。
    • 如果固件停止响应,则 WDI 命令不会及时完成。 重置硬件时,LE 必须在步骤 16 的突发移除中完成操作,因此在潜在的争用条件下可以安全地完成,无需特殊处理。
  7. WDI 计时器触发以生成 WDI 诊断命令。 此 WDI 命令是对 LE 驱动程序 MiniportWdiAdapterHangDiagnose(而不是 WDI OID)的调用。

  8. LE 收集硬件控制寄存器状态,还可以选择完整固件状态。

    • IHV 驱动程序应收集限制为 1KB 的硬件注册内容,并在函数返回中返回它。 此外,在预生产环境中,LE 还应尝试将固件上下文转储到文件中,以便 IHV 可以彻底执行事后调试。 该开关可以作为注册表项实现,以控制硬件寄存器和固件映像的集合。
    • LE 还会标记要取消的当前命令。 如果命令完成的速度超过诊断,那么 LE 对于该命令无动于衷是可以接受的。
    • 在此命令待处理的情况下,UE 可能会由于重置而发送进一步的 WDI 命令。 这些是执行中的命令或清理指令。 诊断过程后,LE 应该处理这些问题,而无需修改固件。
  9. WDI 接收控制寄存器状态。

  10. WDI 标记挂起的 WDI 命令,以便 LE 稍后指示它。

  11. WDI 在未完成自身操作的情况下返回 NDIS 命令(即完成 NDIS 命令)。 这是安全的,因为 WDI 对 NDIS 命令进行双缓冲处理。

  12. WDI 调用 NDIS 进行重置,然后调用 NdisWriteErrorLogEntry,使用 错误代码NDIS_ERROR_CODE_HARDWARE_FAILURE(0xc000138a)。 这会导致系统事件日志中记录的事件,其模块名称为 LE。 错误事件 ID 自动弹出为 (0xc000138a | 0xffff) – 0n5002。 如果 LE 也使用相同的错误代码来编写错误日志,则数据的第一个 DWORD 应包含高位集(0x80000000),以便通过 LE 轻松分隔事件。 WDI 使用 0x00000000 到 0x7fffffff 作为第一个 DWORD 数据的范围。

  13. 调用返回。

  14. NDIS 完成 IRP。

在这一点之后,NDIS 调用公共汽车来意外删除并重新枚举我们。 请务必注意,WDI 对 NDIS 命令进行双重缓冲,这样就不需要等待 WDI 命令返回即可完成 NDIS 命令。 这样就无需 LE 执行取消逻辑,而逻辑则非常复杂。

必须完成 NDIS OID_SET_POWER 以避免 PnP 操作的死锁。 序列化所有 PnP 和电源状态更改事件。 这意味着,如果 Set power OID 未返回,NDIS 将无法返回 Set power IRP,这意味着重置恢复将与 Surprise-Remove IRP 锁住。

MiniportWdiAdapterHangDiagnose

重置(意外移除):步骤 15-20

UE 卡死检测和恢复流程