I'd like to propose an API change/cleanup for a long-standing problem
with architecture-independent code that people have hit and privately
discussed/cursed multiple times already, but no one really had time to
make the big change/fix yet. (Some earlier discussion among Chromium
people about this is available at http://crbug.com/451388
For doing MMIO accesses to registers, x86 code has traditionally used
a function with a signature like this:
void write32(unsigned long addr, u32 value); // equivalents for
read32(), write8(), etc.
While ARM (and based on that, ARM64) has been brought up with both of these:
void write32(u32 value, void *addr);
void writel(u32 value, void *addr);
There's two problems with this: first, the order of arguments (value
and address) is switched around between the two architectures, meaning
it is currently impossible to write any architecture-independent MMIO
code (which blocks important features like generalizing
src/lib/uart8250mem.c). Second, the x86 version is not type safe (it
takes addresses as integers instead of pointers), making it extremely
easy to accidentally swap address and value (especially due to all
this architecture confusion about which order is correct). Changing
the addresses to a pointer type will generate obvious compiler errors
for most of those screw-ups, which I think is a good thing that x86
could benefit from as well.
I want to unify all architectures under a single, type safe version of
these macros that will remove the confusion and allow writing
architecture-independent MMIO code in the future. For this, I plan to:
1. Switch all existing uses of write32() (and friends) in ARM(64) code
2. Remove write32() from all architectures but x86.
3. Add writel(u32 value, void *addr) which is compatible with other
architectures to x86.
4. Pronounce write32(unsigned long addr, u32 value) deprecated for x86
and slowly phase it out over time (at least from common/recent code).
After this we'll be converged on writel(u32 value, void *addr) as the
one and only way to do it across all architectures going forward. I
know that there are probably people who prefer the name write32()
aesthetically, or who have a strong preference for the
first-address-then-value parameter order. I personally don't really
like the way writel() looks myself, but at the end of the day it
doesn't make a huge difference. I think this is the best solution
because it has strong practical advantages and will allow us to solve
the issue with the least amount of changes: most ARM(64) code already
uses writel(), libpayload uses writel() across all architectures, and
it's the standard for U-Boot and a majority of the Linux kernel which
are popular import sources. Also, the amount of existing x86 code is
probably too large to ever change (and appropriately test) it all...
so it's useful to pick a solution that can leave the old untyped
write32() in place on x86 as a deprecated fallback.
Since the changes required for this would mostly affect ARM(64) SoCs
and boards, which are currently much more developed (and in flux) in
the Chromium tree, I'm planning to only change this there for now and
wait until it gets merged into coreboot mainline in the right order as
part of the current upstreaming process. I still wanted to float the
idea here first to give everyone a chance to chime in before it's all
said and done.