【问题标题】:Does NDIS spinlock serves as a memory barrier for DMA?NDIS 自旋锁是否用作 DMA 的内存屏障?
【发布时间】:2021-12-20 13:32:30
【问题描述】:

在 NDIS 驱动程序中,我需要将一些数据写入共享内存,然后通知硬件获取这些数据。写入共享内存受 NDIS 自旋锁保护。在写入共享内存和通知硬件数据已写入之间可能存在竞争。

自旋锁是否作为隐式内存屏障来防止这种竞争?还是应该显式添加内存屏障?

NdisAcquireSpinLock();
writeDataToSharedMem();
NdisReleaseSpinLock();

// MemoryBarrier(); // Is an explicit memory barrier needed?
NdisWriteRegisterUlong(); // Notify the HW that data was written

【问题讨论】:

    标签: memory dma spinlock barrier ndis


    【解决方案1】:

    NDIS 自旋锁为处理器之间的同步提供了完整的内存屏障。这个障碍确实等同于您的代码所暗示的MemoryBarrier() 例程。如果您只是多线程,那么您提供的代码示例将是足够的同步。

    (其实NdisWriteRegisterUlong()也提供了内存屏障,所以你的代码示例中存在冗余内存屏障。如果在释放自旋锁和寄存器访问之间没有其他代码,你可以通过切换到WRITE_REGISTER_NOFENCE_ULONG 来消除其中一个内存屏障。但稍后,我们将在那里添加一些代码,以便该屏障变得有意义。)

    但是,由于您在处理器和设备之间共享数据,因此理论上您还需要一个原语来同步设备对内存的访问。 KeFlushIoBuffers() 就是这么原始。请注意,某些 DMA 例程(BuildScatterGatherList 等)将在内部刷新缓冲区,因此您不必总是直接调用 KeFlushIoBuffers()。但是,如果您只是将命令写入环形缓冲区而不在每次写入后调用任何 DMA 例程,那么 DMA 不可能知道何时代表您刷新 IO 缓冲区。在这种情况下,您必须自己冲洗。

    沉迷于思想实验可能会有所帮助:如果您要(以某种方式)找到一个单处理器系统,MemoryBarrier() 可以实现为无操作。但是您仍然需要其他东西来在处理器和连接 PCIe 的网络适配器之间进行同步。 KeFlushIoBuffers() 是别的东西。

    KeFlushIoBuffers() 在 PCIe 总线是高速缓存一致性时是无操作的,例如,因为它在架构上需要在大多数 x86 和 x64 平台上。因此,如果您只在 x64 上测试您的代码,那么实际上很容易忘记包含 IO 刷新。这就是为什么您可能不会看到其他驱动程序使用此例程的次数与理论上应该使用的一样多。

    作为旁注,我建议使用 NT 同步原语(KeAcquireSpinLock 等)而不是 NDIS 同步原语。 NDIS 锁被设计为操作系统抽象层,因此可以为 Windows 9x、Windows CE、OS/2 和 Windows NT 重新编译相同的源代码。如今,大多数开发人员只需要担心 NT,就可以安全地直接使用 NT 例程。 NDIS 套路不会增加价值,如果你只使用 NT 套路,你的代码会被更多人理解。

    您的最终代码可能如下所示:

    KeAcquireSpinLock(&command_buffer_lock);
    write_to_command_buffer();
    KeReleaseSpinLock(&command_buffer_lock);
    
    KeFlushIoBuffers(command_buffer_mdl, FALSE, TRUE);
    
    WRITE_REGISTER_ULONG(&bar->command_buffer_doorbell);
    

    如果从来没有其他处理器竞相访问共享内存,那么您根本不需要自旋锁!例如,如果您只从专用线程中访问共享内存,那么您可以将代码更新为:

    write_to_command_buffer();
    
    KeFlushIoBuffers(command_buffer_mdl, FALSE, TRUE);
    
    WRITE_REGISTER_ULONG(&bar->command_buffer_doorbell);
    

    【讨论】:

    • 我相信这是一个全面而正确的答案。但是,作为新用户,我无法将其标记为此类。
    • 别担心,我很高兴我能把事情弄清楚一点。
    猜你喜欢
    • 2011-10-12
    • 1970-01-01
    • 2010-12-30
    • 1970-01-01
    • 2014-05-24
    • 2010-12-07
    • 2012-04-07
    • 2014-09-11
    • 1970-01-01
    相关资源
    最近更新 更多