UE 挂起检测:步骤 1-14

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

此示例使用 OID_SET_POWER。

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

  2. NDIS 为 WDI 驱动程序生成OID_SET_POWER D3。

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

  4. WDI 将 WDI 命令发送到 LE。 如果 LE 需要固件命令来完成 OID,则建议在适配器结构中记住 WDI OID。 当固件完成 WDI OID 的作业时,LE 完成 OID 并将其从适配器结构中删除。 由于 WDI 将 OID 序列化为 LE,因此 LE 只需要一个槽来记住挂起的 WDI OID。 如果固件命令挂起,LE 可以随时返回 OID,但不得晚于意外删除 (当固件已禁用时,它可以在步骤 17 的意外删除) 上下文中返回 OID。 对于任何其他情况,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 返回 () 未完成 WDI 的 NDIS 命令。 这是安全的,因为 WDI 双缓冲区 NDIS 命令。

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

  13. 调用返回。

  14. NDIS 完成 IRP。

在此之后,NDIS 调用总线以意外删除并重新枚举我们。 请务必注意,WDI 对 NDIS 命令进行双重缓冲,以便它不必等待 WDI 命令返回以完成 NDIS 命令。 这样就无需 LE 执行取消逻辑,这些逻辑非常复杂。

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

MiniportWdiAdapterHangDiagnose

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

UE 挂起检测和恢复流