[TG3]: Endianness bugfix.
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 18 Dec 2007 07:00:31 +0000 (23:00 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 20 Dec 2007 00:43:48 +0000 (16:43 -0800)
tg3_nvram_write_block_unbuffered() is reading data from nvram into
allocated buffer before overwriting a part of it with user-supplied
data.  Then it feeds the entire page back to nvram.  It should be
storing the words it had read as little-endian, not as host-endian.
Note that tg3_set_eeprom() does exactly that for padding the same
data to full words before it gets passed down to tg3_nvram_write_block()
and then to tg3_nvram_write_block_unbuffered().

Moreover, when we get to sending the entire thing back to nvram, we
go through it word-by-word, doing essentially
writel(swab32(le32_to_cpu(word)), ...)
so if we want them to reach the card in host-independent endianness,
we'd better really have all that buffer filled with fixed-endian.
For user-supplied part we obviously do have that (it's an array of
octets memcpy'd in), ditto for padding of user-supplied part to word
boundaries (taken care of in tg3_set_eeprom()).  The rest of the
buffer gets filled by tg3_nvram_write_block_unbuffered() and it would
damn better be consistent with that (and with tg3_get_eeprom(), while
we are at it - there we also convert the words read from nvram to
little-endian before returning the buffer to user).

The bug should get triggered on big-endian boxen when set_eeprom is done
for less than entire page.  Then the words that should've been unaffected
at all will actually get byteswapped in place in nvram.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tg3.c

index a76bb3dd30f7d893af4eb9bcf918ed524822400b..22eb7c8c1a256fc4a48a4c29b27f946b01fc6386 100644 (file)
@@ -10251,8 +10251,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                phy_addr = offset & ~pagemask;
 
                for (j = 0; j < pagesize; j += 4) {
-                       /* Almost certainly should be tg3_nvram_read_le */
-                       if ((ret = tg3_nvram_read(tp, phy_addr + j,
+                       if ((ret = tg3_nvram_read_le(tp, phy_addr + j,
                                                (__le32 *) (tmp + j))))
                                break;
                }