對記憶體對映地址的 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 晶片組在實際將讀取釋出到晶片組之前重新整理任何待處理的寫入,從而防止可能的資料損壞。