Back to home page

OSCL-LXR

 
 

    


0001 ==============================================
0002 Ordering I/O writes to memory-mapped addresses
0003 ==============================================
0004 
0005 On some platforms, so-called memory-mapped I/O is weakly ordered.  On such
0006 platforms, driver writers are responsible for ensuring that I/O writes to
0007 memory-mapped addresses on their device arrive in the order intended.  This is
0008 typically done by reading a 'safe' device or bridge register, causing the I/O
0009 chipset to flush pending writes to the device before any reads are posted.  A
0010 driver would usually use this technique immediately prior to the exit of a
0011 critical section of code protected by spinlocks.  This would ensure that
0012 subsequent writes to I/O space arrived only after all prior writes (much like a
0013 memory barrier op, mb(), only with respect to I/O).
0014 
0015 A more concrete example from a hypothetical device driver::
0016 
0017                 ...
0018         CPU A:  spin_lock_irqsave(&dev_lock, flags)
0019         CPU A:  val = readl(my_status);
0020         CPU A:  ...
0021         CPU A:  writel(newval, ring_ptr);
0022         CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
0023                 ...
0024         CPU B:  spin_lock_irqsave(&dev_lock, flags)
0025         CPU B:  val = readl(my_status);
0026         CPU B:  ...
0027         CPU B:  writel(newval2, ring_ptr);
0028         CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
0029                 ...
0030 
0031 In the case above, the device may receive newval2 before it receives newval,
0032 which could cause problems.  Fixing it is easy enough though::
0033 
0034                 ...
0035         CPU A:  spin_lock_irqsave(&dev_lock, flags)
0036         CPU A:  val = readl(my_status);
0037         CPU A:  ...
0038         CPU A:  writel(newval, ring_ptr);
0039         CPU A:  (void)readl(safe_register); /* maybe a config register? */
0040         CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
0041                 ...
0042         CPU B:  spin_lock_irqsave(&dev_lock, flags)
0043         CPU B:  val = readl(my_status);
0044         CPU B:  ...
0045         CPU B:  writel(newval2, ring_ptr);
0046         CPU B:  (void)readl(safe_register); /* maybe a config register? */
0047         CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
0048 
0049 Here, the reads from safe_register will cause the I/O chipset to flush any
0050 pending writes before actually posting the read to the chipset, preventing
0051 possible data corruption.