4 ms·
Volatile is for memory mapped IO. Some processors may need extra instuctions or configuration but that doesn't replace the need for volatile with MMIO. On x86
by Avernar 11y ago
Volatile is for memory mapped IO. Some processors may need extra instuctions or configuration but that doesn't replace the need for volatile with MMIO.
On x86 the MTTR/PAT mechanisms is what disables caching, write combining and enables write through to MMIO address ranges.
- burfog 11y agoYes it does replace the need for volatile. The actual access is done via assembly language, either inline (better) or not. You could make volatile work, probably, by putting inline assembly both before and after it. In that case you could probably even skip marking things valatile, because the inline assembly will make the compiler behave. Why bother? This is more complicated than just doing the access from assembly. MTRR/PAT is often not enough, or it would only be enough if you killed performance elsewhere. (different types of MMIO in the same page) It's also not something you can rely on if you want to write portable code.
- Avernar 11y agoYes, you can use memory barriers for MMIO but you'd have to put them between every single statement that touches the MMIO address range. Not only will that bloat your code it would slow down access to all your regular variables as the compiler would have to reload everything constantly and the processor wouldn't be able to out of order anything. Why do you think volatile won't work for MMIO with the proper MTRR/PAT setup? The volatile keeps the compiler for messing with the read/writes and the MTRR/PAT makes the processor perform all reads and writes exactly in the order the instructions tell it to without any caching or write combining. "This is more complicated than just doing the access from assembly." and "It's also not something you can rely on if you want to write portable code." So in one paragraph you're telling me to do it in assembly and in another you want portable code. The linux kernel has gone above and beyond using volatile but in embedded it's how IO is done when using C.
- burfog 11y agoI make the assumption that you put the inline assembly in a macro. This keeps your C portable. The macro gets pulled in from a header file that is specific to the CPU. MTRR/PAT won't save you, at least without a huge performance loss, when you want write combining (etc.) for most of the addresses in a page of address space but not all of them. MTRR/PAT won't save you from reordering that happens in a PCI bridge. It's allowed and it is done.
- Avernar 11y agoWe're into semantics here. Portable requiring a CPU shim vs portable not requiring one. More complicated cpu/bus interfaces require the first one but if you can just use volatile for IO as done in embedded work you get much smaller and/or faster code. If a device has registers that are sensitive to multiple read/writes of the same address and ones that need caching and write combining for performance in the same 4K page then it was designed poorly. :) PCI bridges need to support legacy mode. Otherwise DOS programs and drivers wouldn't run correctly. The BIOS sets up a compatibility MTRR setup for this reason and you can see the Linux kernel print it out on boot. So I'm basically agreeing and disagreeing with you on this one. Once the hardware gets past a certain complexity you need to move from volatile to accessor functions/macros.
- burfog 11y agoVolatile also tempts you to break the aliasing rules. If you find yourself casting pointers, you are probably violating the C standard. You'll need something like -fno-strict-aliasing to enable a non-standard C dialect.
- Avernar 11y agoWhy would you need to alias pointers for MMIO? There's one pointer to a struct that defines all your IO registers for that memory range.