原创翻译,转载请注明出处。安全
在一些平台,所谓的内存映射I/O在保序执行这方面是没有保障的。在这些平台,驱动写入器负责保证I/O写操做按照预期的顺序写到设备内存映射地址。翻译
表明性的作法是经过读取一个安全的设备或桥接寄存器,该寄存器能够致使I/O芯片在任何读操做发生前刷新全部带处理的写操做到设备上。rest
驱动一般在一退出由自旋锁保护的临界区代码时就使用这种技术。这就能够保证后发生的写操做只能在以前已有的写操做的后面执行,这个相似只对I/O操做使用一个内存屏障操做,mb()。
下面举一个具体例子,假设一个设备驱动:code
... 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) ...
以上例子会发生设备可能接收到newval2在newval以前,这样就会引发问题,须要以下修改才能正常:blog
... 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芯片在收到读操做以前刷新以前的未处理的写操做,从而防止数据污染。内存