Linux IO乱序

原创翻译,转载请注明出处。安全

 

在一些平台,所谓的内存映射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芯片在收到读操做以前刷新以前的未处理的写操做,从而防止数据污染。内存

相关文章
相关标签/搜索