On Mon, 2006-09-25 at 19:59 -0400, Jeff Garzik wrote:

> Seems like a better solution would be to remove the manual swap from the 
> caller of b44_read_eeprom().

No.

You're not looking at the problem from the right angle.

The thing is that Broadcom decided to store the EEPROM data as an array
of u16s:
  u16 eeprom_data_as_stored[64];

In there, you have, for example, the mac address in 3 u16s at offsets
39-41:
  | offset | ... | 39     | 40     | 41     | ...
  | data   | ... | MAC 01 | MAC 23 | MAC 45 | ...

which together forms MAC 012345 (6 bytes)

Broadcom further assumes that things are in little endian, so it's
actually necessary to byteswap the MAC bytes 01, 23, 45 which I have
omitted from above pictures because it's an array of u16 so endianness
doesn't matter as long as you store it to the mac in big endian.


Now come along the current code which didn't understand this and
overlayed the eeprom_data_as_stored with a new array:
    u8 eeprom[128];

That's fine on little endian machines because each u16 will be
represented in exactly the same way, and it all works out.

However, because of Broadcom always thinking "little endian u16" *and*
the current code using "u8" there's a mismatch on big endian machines
which Michael fixed up by making the u8 "overlay" the driver is using
see "little endian u16". Insofar, it is the correct fix because the
current code wants to use a u8 overlay over an array that was intended
to be a "little endian u16" array.

Now, arguably the correct fix would be to make the b44_read_eeprom
routine read an array of u16 as stored, and then use byte shifting
everywhere to fix up for the fact that Broadcom stores things into the
high/low byte of a u16 (yes, they always use a u16 layout even if the
data they want to store is just a u8 or less, then they stuff it into a
u16 and store it, they don't store byte-wise).

Now, making that fix would result in quite some ugly code along the
lines of:
        bp->dev->dev_addr[0] = eeprom[39] >> 8;
        bp->dev->dev_addr[1] = eeprom[39] & 0xFF;
        bp->dev->dev_addr[2] = eeprom[40] >> 8;
        bp->dev->dev_addr[3] = eeprom[40] & 0xFF;
etc.

Similar for the other parameters (which you seem to be forgetting by
advocating the byte swap here, but they too are stored into u16s!)

The current code obviously didn't want to do that so they overlaid the
u16 array with a u8 array to read out the bytes directly. This results
in the manual-seeming byte-swapping for some parameters of course.

Now, Michaels fix works differently instead, it properly reads out the
sprom data so that the overlaid u8 array gets what it expects, a view
into a "little endian u16" array. You really have to think of it as a
view. This is obviously what the original authors intended to do but
they were unaware of the endianness complications with that approach.

johannes
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to