Hi Jon,

The description of the ARM barrier operations is not entirely accurate.

The DMB does not guarantee completion of anything - it only enforces ordering.
I.e.
---
ldr <access to clear an interrupt source>
DMB
CPSIE i
---
does not guarantee that the interrupt line is not still live when the core re-enables interrupts.
That's what the DSB is for.
Likewise, DMB ST does not wait for stores, it orders stores.

So, a sequence like:
---
str
str
ldr
str
DMB
str
add
---
does not guarantee that any memory access has completed, or even started, before the add is executed - only
that the last str is guaranteed to be observed after all of the accesses preceding the DMB.

As for ISB, it has no effect on the data side - it's only for the instruction side.
Err, and also, it guarantees the completion of changes to system control registers and cp15 maintenance operations.
For self-generating code, it needs to be coupled with DSB (of course, userland can simply use _clear_cache()) -
Jacob did a good writeup on that bit at
http://blogs.arm.com/software-enablement/141-caches-and-self-modifying-code/

For something hopefully a bit more user-friendly than the ARM ARM, if a bit clunkier than yours, I wrote a summary about this some time back:
http://blogs.arm.com/software-enablement/594-memory-access-ordering-part-3-memory-access-ordering-in-the-arm-architecture/

/
    Leif