Skip to contentSkip to conversation

rt2x00: byte ordering correctness

PATCH In review Ivo van Doorn 3 participants 10 messages Apr 27, 2006 – Apr 28, 2006

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 20/32 rt2x00: byte ordering correctness

From: Ivo van Doorn <[email protected]>

Fix various little/big endian conversions. rt2500pci should use cpu_to_le32 and rt2500usb should not.

drivers/net/wireless/d80211/rt2x00/rt2500pci.c +1 -1
diff -uprN wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2500pci.c wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2500pci.c
@@ -441,7 +441,7 @@ rt2500pci_config_channel(struct rt2x00_p
 	txpower = (txpower > 31) ? 31 : txpower;
 
 	if (rt2x00_rf(&rt2x00pci->chip, RF2525E) && channel == 14)
-		rf4 |= 0x00000010;
+		rf4 |= cpu_to_le32(0x00000010);
 
 	if (rt2x00_rf(&rt2x00pci->chip, RF5222)) {
 		if (channel < 14) {
drivers/net/wireless/d80211/rt2x00/rt2500usb.c +17 -18
diff -uprN wireless-dev-rt2x00/drivers/net/wireless/d80211/rt2x00/rt2500usb.c wireless-dev-rt2x00-patch/drivers/net/wireless/d80211/rt2x00/rt2500usb.c
@@ -324,20 +324,20 @@ rt2500usb_config_channel(struct rt2x00_u
 
 	if (rt2x00_rf(&rt2x00usb->chip, RF5222)) {
 		if (channel < 14) {
-			rf1 = cpu_to_le32(0x00022020);
-			rf4 = cpu_to_le32(0x00000a0b);
+			rf1 = 0x00022020;
+			rf4 = 0x00000a0b;
 		} else if (channel == 14) {
-			rf1 = cpu_to_le32(0x00022010);
-			rf4 = cpu_to_le32(0x00000a1b);
+			rf1 = 0x00022010;
+			rf4 = 0x00000a1b;
 		} else if (channel < 64) {
-			rf1 = cpu_to_le32(0x00022010);
-			rf4 = cpu_to_le32(0x00000a1f);
+			rf1 = 0x00022010;
+			rf4 = 0x00000a1f;
 		} else if (channel < 140) {
-			rf1 = cpu_to_le32(0x00022010);
-			rf4 = cpu_to_le32(0x00000a0f);
+			rf1 = 0x00022010;
+			rf4 = 0x00000a0f;
 		} else if (channel < 161) {
-			rf1 = cpu_to_le32(0x00022020);
-			rf4 = cpu_to_le32(0x00000a07);
+			rf1 = 0x00022020;
+			rf4 = 0x00000a07;
 		}
 	}
 
@@ -1829,7 +1829,7 @@ rt2500usb_init_hw_channels(struct rt2x00
 		};
 
 		for (counter = 0; counter < ARRAY_SIZE(vals); counter++)
-			channels[counter].val = cpu_to_le32(vals[counter]);
+			channels[counter].val = vals[counter];
 	} else if (rt2x00_rf(&rt2x00usb->chip, RF2523)
 	|| rt2x00_rf(&rt2x00usb->chip, RF2524)
 	|| rt2x00_rf(&rt2x00usb->chip, RF2525)) {
@@ -1841,8 +1841,7 @@ rt2500usb_init_hw_channels(struct rt2x00
 		};
 
 		for (counter = 0; counter < ARRAY_SIZE(vals); counter++)
-				channels[counter].val =
-				cpu_to_le32(vals[counter] | rf2_base);
+			channels[counter].val = vals[counter] | rf2_base;
 	} else if (rt2x00_rf(&rt2x00usb->chip, RF2525E)) {
 		u32 vals[] = {
 			0x0000089a, 0x0000089e, 0x0000089e, 0x000008a2,
@@ -1852,7 +1851,7 @@ rt2500usb_init_hw_channels(struct rt2x00
 		};
 
 		for (counter = 0; counter < ARRAY_SIZE(vals); counter++)
-			channels[counter].val = cpu_to_le32(vals[counter]);
+			channels[counter].val = vals[counter];
 	} else if (rt2x00_rf(&rt2x00usb->chip, RF5222)) {
 		static u32 vals[] = {
 			0x00001136, 0x0000113a, 0x0000113e, 0x00001182,
@@ -1868,7 +1867,7 @@ rt2500usb_init_hw_channels(struct rt2x00
 		};
 
 		for (counter = 0; counter < ARRAY_SIZE(vals); counter++)
-			channels[counter].val = cpu_to_le32(vals[counter]);
+			channels[counter].val = vals[counter];
 		}
 
 		/*
@@ -1895,9 +1894,9 @@ rt2500usb_init_hw_channels(struct rt2x00
 	 */
 	for (counter = 0; counter < ARRAY_SIZE(rf); counter++) {
 		if (rt2x00_rf(&rt2x00usb->chip, rf[counter].chip)) {
-			rt2x00usb->rf1 = cpu_to_le32(rf[counter].val[0]);
-			rt2x00usb->rf3 = cpu_to_le32(rf[counter].val[1]);
-			rt2x00usb->rf4 = cpu_to_le32(rf[counter].val[2]);
+			rt2x00usb->rf1 = rf[counter].val[0];
+			rt2x00usb->rf3 = rf[counter].val[1];
+			rt2x00usb->rf4 = rf[counter].val[2];
 		}
 	}
 }
#1 lore raw
Quoted 4 lines · Ivo van Doorn

From: Ivo van Doorn <[email protected]>

Fix various little/big endian conversions. rt2500pci should use cpu_to_le32 and rt2500usb should not.

While you're at it can you add __be* annotations to the hardware datastructures so the endianess handling can be verified using sparse?

#2 lore raw
Quoted 8 lines · Christoph Hellwig
Quoted 4 lines · Ivo van Doorn

From: Ivo van Doorn <[email protected]>

Fix various little/big endian conversions. rt2500pci should use cpu_to_le32 and rt2500usb should not.

While you're at it can you add __be* annotations to the hardware datastructures so the endianess handling can be verified using sparse?

I am not sure if that would be a wise idea,
there is no byte ordering done in rt2500usb except for the EEPROM contents which is little endian.
So when the module is used on a normal x86 platform, there won't be any big endian structures or fields.

#3 lore raw
Quoted 5 lines · Ivo van Doorn

I am not sure if that would be a wise idea,
there is no byte ordering done in rt2500usb except for the EEPROM contents which is little endian.
So when the module is used on a normal x86 platform, there won't be any big endian structures or fields.

Well, then you'll need __le* annotation and the le*_to_cpu/cpu_to_le* instead. Any new driver should be endian clean.

#4 lore raw
Quoted 9 lines · Christoph Hellwig
Quoted 5 lines · Ivo van Doorn

I am not sure if that would be a wise idea,
there is no byte ordering done in rt2500usb except for the EEPROM contents which is little endian.
So when the module is used on a normal x86 platform, there won't be any big endian structures or fields.

Well, then you'll need __le* annotation and the le*_to_cpu/cpu_to_le* instead. Any new driver should be endian clean.

Not exactly true for rt2570, to correctly operate with the device, no endian conversions should be made at all. Not to big endian and not
to little endian. The register should be send as a regular value with the byteordering equal to the byteordering of the currently used CPU.
It has been tested to send only little endian or big endian values to
the device on all CPU's, and in all cases it meant that the device would not function on CPU's with the other byte ordering.

#5 lore raw
Quoted 11 lines · you
Quoted 9 lines · Christoph Hellwig
Quoted 5 lines · Ivo van Doorn

I am not sure if that would be a wise idea,
there is no byte ordering done in rt2500usb except for the EEPROM contents which is little endian.
So when the module is used on a normal x86 platform, there won't be any big endian structures or fields.

Well, then you'll need __le* annotation and the le*_to_cpu/cpu_to_le* instead. Any new driver should be endian clean.

Quoted 7 lines

Not exactly true for rt2570, to correctly operate with the device, no endian conversions should be made at all. Not to big endian and not
to little endian. The register should be send as a regular value with the byteordering equal to the byteordering of the currently used CPU.
It has been tested to send only little endian or big endian values to
the device on all CPU's, and in all cases it meant that the device would not function on CPU's with the other byte ordering.

I guess you are confusing something here:
MMIO access versus values in structs (for example) that are accessed through DMA (for example).

Signature · 1 line
Greetings Michael.
#6 lore raw
Quoted 20 lines · Michael Buesch
Quoted 11 lines · you
Quoted 9 lines · Christoph Hellwig
Quoted 5 lines · Ivo van Doorn

I am not sure if that would be a wise idea,
there is no byte ordering done in rt2500usb except for the EEPROM contents which is little endian.
So when the module is used on a normal x86 platform, there won't be any big endian structures or fields.

Well, then you'll need __le* annotation and the le*_to_cpu/cpu_to_le* instead. Any new driver should be endian clean.

Quoted 7 lines

Not exactly true for rt2570, to correctly operate with the device, no endian conversions should be made at all. Not to big endian and not
to little endian. The register should be send as a regular value with the byteordering equal to the byteordering of the currently used CPU.
It has been tested to send only little endian or big endian values to
the device on all CPU's, and in all cases it meant that the device would not function on CPU's with the other byte ordering.

Quoted 3 lines

I guess you are confusing something here:
MMIO access versus values in structs (for example) that are accessed through DMA (for example).

Ah ok. I was indeed missing that point.
In that case you are right, there could be some places where the __le* annotation could be used.
I'll create a quick patch to do that.

#7 lore raw
In reply to Michael Buesch
Quoted 3 lines · Michael Buesch

I guess you are confusing something here:
MMIO access versus values in structs (for example) that are accessed through DMA (for example).

so there's two general problems:

mmio/pio - linux expects the device to be le there by defalt and
{read,write}{b,s,l} do the switch automatically
dmaed data - you always need to switch data yourself, data is commonly
either be or le

now there's devices that are always be for mmio or can be switched to it during initialization. For Linux you'd traditionally have to switch before calling {read,write}{b,s,l} or use the __raw_ version that have other issues. The ioread*/iowrite* APIs now have a BE version, too.

I've not heard about devices having this switch for dma payload, and it would be rather usual as large parts of it are determined by some on the wire protocol anyway.

Quoted 3 lines
Signature · 2 lines
-- 
Greetings Michael.

---end quoted text---

#8 lore raw
Quoted 12 lines · you
Quoted 3 lines · Michael Buesch

I guess you are confusing something here:
MMIO access versus values in structs (for example) that are accessed through DMA (for example).

so there's two general problems:

mmio/pio - linux expects the device to be le there by defalt and
{read,write}{b,s,l} do the switch automatically
dmaed data - you always need to switch data yourself, data is commonly
either be or le

Quoted 8 lines

now there's devices that are always be for mmio or can be switched to it during initialization. For Linux you'd traditionally have to switch before calling {read,write}{b,s,l} or use the __raw_ version that have other issues. The ioread*/iowrite* APIs now have a BE version, too.

I've not heard about devices having this switch for dma payload, and it would be rather usual as large parts of it are determined by some on the wire protocol anyway.

bcm43xx has a switch for this in PIO mode.
But we are currently not using it, because it is a little bit tricky to get right and I did not want to do such experiments before 2.6.17.

Signature · 1 line
Greetings Michael.
#9 lore raw
In reply to Christoph Hellwig
Quoted 12 lines · Christoph Hellwig
Quoted 3 lines · Michael Buesch

I guess you are confusing something here:
MMIO access versus values in structs (for example) that are accessed through DMA (for example).

so there's two general problems:

mmio/pio - linux expects the device to be le there by defalt and
{read,write}{b,s,l} do the switch automatically
dmaed data - you always need to switch data yourself, data is commonly
either be or le

Quoted 4 lines

now there's devices that are always be for mmio or can be switched to it during initialization. For Linux you'd traditionally have to switch before calling {read,write}{b,s,l} or use the __raw_ version that have other issues. The ioread*/iowrite* APIs now have a BE version, too.

Unless I am mistaken, or the ralink design sheets are outdated on that issue, I do recall that there was a big endian switch in one of the registers. I think I need to definately investigate that to see if it would be usefull. :)

Thanks,

Ivo