Messages in this thread | | | Subject | Re: question on memory barrier | Date | Wed, 24 Aug 2005 14:22:32 -0400 | From | "linux-os \(Dick Johnson\)" <> |
| |
On Wed, 24 Aug 2005, moreau francis wrote:
> > --- "linux-os (Dick Johnson)" <linux-os@analogic.com> 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@analogic.com - 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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |