On Mon, 2020-04-27 at 11:13 +0200, Mateusz Holenko wrote: > As Gabriel Somlo <gsomlo@xxxxxxxxx> suggested to me, I could still use > readl/writel/ioread/iowrite() standard functions providing memory > barriers *and* have values in CPU native endianness by using the > following constructs: > > `le32_to_cpu(readl(addr))` > > and > > `writel(cpu_to_le32(value), addr)` > > as le32_to_cpu/cpu_to_le32(): > - does nothing on LE CPUs and > - reorders bytes on BE CPUs which in turn reverts swapping made by > readl() resulting in returning the original value. It's a bit sad... I don't understand why you need this. The HW has a fied endian has you have mentioned earlier (and that is a good design). The fact that you are trying to shove things into a "smaller pipe" than the actual register shouldn't affect at what address the MSB and LSB reside. And readl/writel (or ioread32/iowrite32) will always be LE as well, so will match the HW layout. Thus I don't see why you need to play swapping games here. This however would be avoided completely if the HW was a tiny bit smarter and would do the multi-beat access for you which shouldn't be terribly hard to implement. That said, it would be even clearer if you just open coded the 2 or 3 useful cases: 32/8, 32/16 and 32/32. The loop with calculated shifts (and no masks) makes the code hard to understand. Cheers, Ben.