This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

[ARMv7] question about writel & barrier

Hi Sirs,

I got a question about the way Linux 3.18 defines the "writel()".

In linux-3.18/arch/arm64/include/asm/io.h, it describes:

/*

* I/O memory access primitives. Reads are ordered relative to any

* following Normal memory access. Writes are ordered relative to any prior

* Normal memory access.

*/

And we can see the definition of writel():

#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })

As you can see from the comment and the definition, when you call "writel()", the ARMv7 CPU would probably just sent as wmb and execute the instruction of "writel_relaxed()".

But...WHY?

Why put the barrier in front of the write_relaxed?

It just make sure that write would not be merged into CPU cluster's interior write buffer with previous data that haven't been write to exterior memory or IO device.

But we can not make sure after calling the "writel()", the write behavior has been done, isn't it? Since there is no instruction to drain the write buffer after writel_relaxed.

// I got this question because when tracing some driver, they use writel() to config the register.

// And I'm not sure it can make write be done with a short delay.

訊息由此人編輯:hcbamboo

  • Hi,

    Just a heads up that you're mentioning an "ARMv7" CPU, but then refer to /arch/arm64/, which corresponds to the ARMv8-A AArch64 port of the Linux kernel, not ARMv7-A. You should be looking in /arch/arm/ for ARMv7-A and earlier.

    It just make sure that write would not be merged into CPU cluster's interior write buffer with previous data that haven't been write to exterior memory or IO device.

    Not quite. __iowmb() collapses to a 'DSB ST' instruction. This ensures that all previous stores before the DSB in program-order have completed (not just been drained from the write buffer) before execution can continue past the barrier.

    To answer your question as to why it's there, there are no ordering requirements between accesses to Normal-type memory and accesses to Device-type memory, even if the region of memory is marked as nR (no reordering) as this only affects ordering between multiple accesses to the same peripheral. From the comment in the code:

    Writes are ordered relative to any prior Normal memory access.

    The 'DSB ST' instruction ensures this (well, more accurately it ensures all prior writes to other Normal-type and Device-type regions have completed).

    But we can not make sure after calling the "writel()", the write behavior has been done, isn't it? Since there is no instruction to drain the write buffer after writel_relaxed.

    (Just another quick reminder not to think of the barrier as simply draining the write buffer; it does more than that).

    If for whatever reason you need to guarantee that the store resulting from calling writel() has completed, you'd need to insert your own barrier. Using a 'DSB SY' would guarantee completion from the perspective of the full system for both loads and stores (as opposed to 'DSB ST' which only guarantees completion of prior stores).

    Hope that helps.

    Ash.

  • @Ash Wilding

    Just a heads up that you're mentioning an "ARMv7" CPU, but then refer to /arch/arm64/, which corresponds to the ARMv8-A AArch64 port of the Linux kernel, not ARMv7-A. You should be looking in /arch/arm/ for ARMv7-A and earlier.

    Hi Sir,

    Sorry I just choose the wrong SDK.

    It should be Linux-3.4, and the path is linux-3.4/arch/arm/include/asm/io.h.

    The definition of writel() remains the same, however.

    (And the CPU we use in that project is dual core of Cortex-A9, anyway.)

    Thanks for your answering.