18c2ecf20Sopenharmony_ci==============================================
28c2ecf20Sopenharmony_ciOrdering I/O writes to memory-mapped addresses
38c2ecf20Sopenharmony_ci==============================================
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ciOn some platforms, so-called memory-mapped I/O is weakly ordered.  On such
68c2ecf20Sopenharmony_ciplatforms, driver writers are responsible for ensuring that I/O writes to
78c2ecf20Sopenharmony_cimemory-mapped addresses on their device arrive in the order intended.  This is
88c2ecf20Sopenharmony_citypically done by reading a 'safe' device or bridge register, causing the I/O
98c2ecf20Sopenharmony_cichipset to flush pending writes to the device before any reads are posted.  A
108c2ecf20Sopenharmony_cidriver would usually use this technique immediately prior to the exit of a
118c2ecf20Sopenharmony_cicritical section of code protected by spinlocks.  This would ensure that
128c2ecf20Sopenharmony_cisubsequent writes to I/O space arrived only after all prior writes (much like a
138c2ecf20Sopenharmony_cimemory barrier op, mb(), only with respect to I/O).
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciA more concrete example from a hypothetical device driver::
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci		...
188c2ecf20Sopenharmony_ci	CPU A:  spin_lock_irqsave(&dev_lock, flags)
198c2ecf20Sopenharmony_ci	CPU A:  val = readl(my_status);
208c2ecf20Sopenharmony_ci	CPU A:  ...
218c2ecf20Sopenharmony_ci	CPU A:  writel(newval, ring_ptr);
228c2ecf20Sopenharmony_ci	CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
238c2ecf20Sopenharmony_ci		...
248c2ecf20Sopenharmony_ci	CPU B:  spin_lock_irqsave(&dev_lock, flags)
258c2ecf20Sopenharmony_ci	CPU B:  val = readl(my_status);
268c2ecf20Sopenharmony_ci	CPU B:  ...
278c2ecf20Sopenharmony_ci	CPU B:  writel(newval2, ring_ptr);
288c2ecf20Sopenharmony_ci	CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
298c2ecf20Sopenharmony_ci		...
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciIn the case above, the device may receive newval2 before it receives newval,
328c2ecf20Sopenharmony_ciwhich could cause problems.  Fixing it is easy enough though::
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci		...
358c2ecf20Sopenharmony_ci	CPU A:  spin_lock_irqsave(&dev_lock, flags)
368c2ecf20Sopenharmony_ci	CPU A:  val = readl(my_status);
378c2ecf20Sopenharmony_ci	CPU A:  ...
388c2ecf20Sopenharmony_ci	CPU A:  writel(newval, ring_ptr);
398c2ecf20Sopenharmony_ci	CPU A:  (void)readl(safe_register); /* maybe a config register? */
408c2ecf20Sopenharmony_ci	CPU A:  spin_unlock_irqrestore(&dev_lock, flags)
418c2ecf20Sopenharmony_ci		...
428c2ecf20Sopenharmony_ci	CPU B:  spin_lock_irqsave(&dev_lock, flags)
438c2ecf20Sopenharmony_ci	CPU B:  val = readl(my_status);
448c2ecf20Sopenharmony_ci	CPU B:  ...
458c2ecf20Sopenharmony_ci	CPU B:  writel(newval2, ring_ptr);
468c2ecf20Sopenharmony_ci	CPU B:  (void)readl(safe_register); /* maybe a config register? */
478c2ecf20Sopenharmony_ci	CPU B:  spin_unlock_irqrestore(&dev_lock, flags)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciHere, the reads from safe_register will cause the I/O chipset to flush any
508c2ecf20Sopenharmony_cipending writes before actually posting the read to the chipset, preventing
518c2ecf20Sopenharmony_cipossible data corruption.
52