Re: question on memory barrier

From: linux-os (Dick Johnson)
Date: Wed Aug 24 2005 - 13:23:48 EST



On Wed, 24 Aug 2005, moreau francis wrote:

>
> --- "linux-os (Dick Johnson)" <linux-os@xxxxxxxxxxxx> a écrit :
>
>>
>> On Wed, 24 Aug 2005, moreau francis wrote:
>>
>>> Hi,
>>>
>>> I'm currently trying to write a USB driver for Linux. The device must be
>>> configured by writing some values into the same register but I want to be
>>> sure that the writing order is respected by either the compiler and the
>> cpu.
>>>
>>> For example, here is a bit of driver's code:
>>>
>>> """
>>> #include <asm/io.h>
>>>
>>> static inline void dev_out(u32 *reg, u32 value)
>>> {
>>> writel(value, regs);
>>> }
>>>
>>> void config_dev(void)
>>> {
>>> dev_out(reg_a, 0x0); /* first io */
>>> dev_out(reg_a, 0xA); /* second io */
>>> }
>>>
>>
>> This should be fine. The effect of the first bit of code
>> plus all side-effects (if any) should be complete at the
>> first effective sequence-point (;) but you need to
>
> sorry but I'm not sure to understand you...Do you mean that the first write
> into reg_a pointer will be completed before the second write because they're
> separated by a (;) ?

Yes. The compiler must make sure that every effect of all previous
code and all side-effects are complete at a "sequence-point". There
are several sequence-points and the most obvious is a ";".

The compiler is free to reorder anything in a compound statement
as long as it complies with presidence rules, but it can't re-order
the statements themselves.

In other words:

volatile unsigned int *hardware = virtual(MY_DEVICE);

*hardware = 1;
*hardware = 2;
*hardware = 4;
*hardware = 8;

.. happens exactly as shown above. If it didn't, you couldn't
write device drivers. An example of the code above:

.file "xxx.c"
.text
.globl foo
.type foo, @function
foo:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $305419896, -4(%ebp) // init the pointer
movl -4(%ebp), %eax // Get pointer
movl $1, (%eax) // *hardware = 1;
movl -4(%ebp), %eax // Get pointer
movl $2, (%eax) // *hardware = 2;
movl -4(%ebp), %eax // Get pointer
movl $4, (%eax) // *hardware = 4;
movl -4(%ebp), %eax // Get pointer
movl $8, (%eax) // *hardware = 8;
movl $0, %eax
leave
ret
.size foo, .-foo
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.3.3 20040412 (Red Hat Linux 3.3.3-7)"

Because of the necessary 'volatile' keyword, even the pointer is
obtained over again each time. This wastes CPU cycles. One
could do:

movl $1, (%eax)
movl $2, (%eax)
movl $4, (%eax)
movl $8, (%eax)

.. after the pointer is loaded. Unfortunately, 'C' doesn't have
a keyword that would accommodate that.

When communicating across a PCI/Bus, the writes are cached.
They don't necessarily occur __now__. It will take a (perhaps
dummy) read of the PCI/Bus to make them get to the hardware
now. Even then, they will still get there in order, all 4 writes,
because the interface is a FIFO. A read on the PCI/Bus will force
all pending writes to be written).

Some arcitectures do write-combining which means that, for instance
on an Intel Pentium P6, it's possible for all writes of adjacent
words may be condensed into a single quadword write. This may not be
what you want. If you have such a situation, one would execute
WBINVD after the critical writes. No not do this just to "make sure".
It wastes a lot of bandwidth.

See http://developer.intel.com/design/PentiumII/applnots/24442201.pdf



> Or because writes are encapsulated inside an inline function, therefore
> compiler
> must execute every single writes before returning from the inline function ?
>

In-line doesn't care. It's not as complicated as many expect.

> Thanks.
>
> Francis
>

Cheers,
Dick Johnson
Penguin : Linux version 2.6.12.5 on an i686 machine (5537.79 BogoMips).
Warning : 98.36% of all statistics are fiction.

****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to DeliveryErrors@xxxxxxxxxxxx - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/