On 2/26/2018 12:04 PM, Arnd Bergmann wrote:
For the endianess, the key to understanding this is that readl/writel and
readq/writeq follow the convention of accessing data as little-endian because
that is what 99% of MMIO accesses on PCI are: you have a 32-bit or 64-bit
register value that gets copied between a register and the CPU, and it's
up to the device manufacturer to implement that convention in hardware.
The Linux implementation of writeq() on all architectures therefore puts the
LSB into the first byte of the output.
ok, so I interpret this as readx/writex() get a cpu-endian-based value,
and the routine compensates for cpu endianness as it puts it out on the
io bus (LSB=1st byte). All well and good.
In contrast, accessing memory using a pointer dereference is defined by
the CPU manufacturer, so in a big-endian CPU the first byte corresponds
to the MSB of the CPU register.
In your loop
for (i = 0; i < q->entry_size; i += sizeof(uint64_t))
writeq(*((uint64_t *)(tmp + i)), q->dpp_regaddr + i);
that ends up copying the first byte of 'tmp[]' to byte 7 of dpp_regaddr,
which makes no sense as the data in tmp is (presumably) just a stream of
bytes that we want to end up on a disk in the same order, regardless
of which mode the CPU happens to be in at the time we copy the data.
This is where I get a bit lost.
So what you're telling me is:
with
uint64_t a=5, *b;
*b=5;
that
writeq(a, regptr);
is not the same as
writeq(*b, regptr);
??
That doesn't make sense to me as "*ptr" should have resulted in a
cpu-endian value being given to writeq(), ignorant of how that value
came into existence (pointer/constant/value in register). Then writeq()
does it's thing to ensure LSB=1st byte
It would only make sense if writeq() can be a macro that such that it
can resolve into something that is essentially
*regport = *b;
thus it's treated as a bytestream starting at address b and does not
necessarily compensate for the cpu-endianness of the multi-byte quantity.
-- james