On 2/27/2018 12:58 AM, Arnd Bergmann wrote:
What you are describing above is not a byte stream but dealing with
a 64-bit integer. In both cases you obviously end up with the destination
data being 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00, there is no
difference.
The case that you have in the driver is more like
char *bytestream = "this is a byte stream";
u64 *tmp = (u64 *)bytestream;
writeq(*tmp, regptr);
writeq(*(tmp + 1), regptr + 1);
On a big-endian cpu, *tmp is the 64-bit number 0x7468697320697320,
and *(tmp +1) is 0x6120627974652073, as the access to the memory
location is performed using big-endian semantics.
When we write that to the PCI bus using little-endian semantics, the
buffer ends up being 0x20 0x73 0x69 0x20 0x73 0x69 0x68 0x74
0x20 0x73 0x20 0x65 0x74 0x79 0x62 0x20, or " si siht s etyb a".
ok - I get what you are saying...
The summary is: the writeX() routines take a cpu-endianness specific
int value and send it to the device in a byte order corresponding to LSB
to MSB. On LE cpu's using writex() to PCI (LE bus), LSB to MSB mirrors
byte order in memory. But on BE cpu's to PCI, LSB to MSB means the byte
order was effectively byteswapped as it is sent to the device.
So you point out a very real concern, as in most cases the source buffer
is a bytestream and the desire is to send the bytestream in the same
byte order as in memory. It turns out we're somewhat lucky as the
driver's source buffer wasn't a real bytestream, it was a cpu-endian
relative structure so writex behavior would be ok. However, the driver
is confused as it wants to use 64-bit copies, but the cpu-endian
structure was based on 32-bit's at a time when mapping to the hardware.
So things are ok if using writel, but not so ok if writeq.
As the code stands write now - this feature and the routine is only used
when x86, thus LE, thus the whole LSB conversion by writeX works. It's
a mute point.
Please accept the patch as proposed. We will address these other issues
as we include the "push" support for other architectures.
-- james