英文
对内存映射地址的 I/O 写入进行排序¶
在某些平台上,所谓的内存映射 I/O 的顺序性较弱。在此类平台上,驱动程序编写者有责任确保其设备上对内存映射地址的 I/O 写入按预期顺序到达。这通常通过读取一个“安全”设备或桥接寄存器来完成,从而使 I/O 芯片组在任何读取发布之前刷新待处理的写入到设备。驱动程序通常会在由自旋锁保护的关键代码段退出之前立即使用此技术。这将确保后续对 I/O 空间的写入仅在所有之前的写入之后到达(非常类似于内存屏障操作 mb(),但仅针对 I/O 而言)。
一个假设的设备驱动程序的更具体示例
...
CPU A: spin_lock_irqsave(&dev_lock, flags)
CPU A: val = readl(my_status);
CPU A: ...
CPU A: writel(newval, ring_ptr);
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
...
CPU B: spin_lock_irqsave(&dev_lock, flags)
CPU B: val = readl(my_status);
CPU B: ...
CPU B: writel(newval2, ring_ptr);
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
...
在上述情况下,设备可能会在收到 newval 之前收到 newval2,这可能会导致问题。不过,修复它相当容易
...
CPU A: spin_lock_irqsave(&dev_lock, flags)
CPU A: val = readl(my_status);
CPU A: ...
CPU A: writel(newval, ring_ptr);
CPU A: (void)readl(safe_register); /* maybe a config register? */
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
...
CPU B: spin_lock_irqsave(&dev_lock, flags)
CPU B: val = readl(my_status);
CPU B: ...
CPU B: writel(newval2, ring_ptr);
CPU B: (void)readl(safe_register); /* maybe a config register? */
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
在这里,对 safe_register 的读取将使 I/O 芯片组在实际将读取发布到芯片组之前刷新任何待处理的写入,从而防止可能的数据损坏。