Probable endianess problem in TLAN driver
Hello.
I'm trying to use a Compaq Dual Netteligent card in a Apple Macintosh Performa 6360. Basically, my purpose is to use this system as a more powerful firewall than that the one I have today.
To make things shorter, the TLAN driver on its atual incarnation does not work in PowerPC machines. It isn't detected on 2.2 kernel unless I activate it with setpci; OTOH, it is detected on 2.4, but does not work. I get messages like "TLAN: Adaptor Error: 0x180005" every time I try to ping other hosts; when this message appears, the link is reset and goes online again. Also I get occasional panics when I try to ping the machine from other machines in my Ethernet network. I've noticed also that the board statistics don't change: all values are zero, always.
Physical media disruption was ruled out, since mii-diag reported that the link was up and I could verify this on the leds of the board and of the hub I use; both reported link up for the connection. mii-diag also detects correctly when the link is up or down.
As I'm really no kernel hacker, I started looking for help. I've found Hollis of openprojects.org (CC:ed in this message), and we begun to think what could be the problem. I've generated backtraces of the panics I've got, but there wasn't nothing really conclusive. So Hollis inspected the code and found lines like these:
host_int = inw( dev->base_addr + TLAN_HOST_INT );
outw( host_int, dev->base_addr + TLAN_HOST_INT );or
outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD );
He said me that these funtions don't address the endianess question, and sent me a patch. He said that this probably wouldn't work, but I've decided to give a try anyway. Here is the patch:
tlan.c Thu Jun 7 21:37:42 2001 renamed from tlan.c.old Thu Jun 7 21:24:25 2001 +6 -0
@@ -172,6 +172,12 @@ #include <linux/delay.h> #include <linux/spinlock.h> +#if defined(__powerpc__) +#define inw(addr) le32_to_cpu(inw(addr)) +#define inl(addr) le32_to_cpu(inl(addr)) +#define outw(val, addr) outw(cpu_to_le32(val), addr) +#define outl(val, addr) outl(cpu_to_le32(val), addr) +#endif
It's very clear (even to me) what it does: it takes into account the big-endianess of PowerPC for out[l,w] and in[l,w]. I've applied this patch, and for my surprise it brought some good effects. The error messages stopped, and the machine does not crash anymore. Also, I'm now able to see changes on the statistics of the board, even if they are completely bogus nowadays. It's a real change for good but for one
thing: I still can't communicate with the other computers on my network.
I've tried to contact Torben, but oddly seems that he is not around. The driver page in tlan.kernel.dk has not been updated since October 2000, and there is no recent activity either on the TLAN driver mailing list or in the new project page on Compaq
(http://linuxalpha.compaq.com/sourceforge/project/?group_id=12). Again, as I'm no kernel hacker, I'd like to ask the linux-kernel list for help (even if to point me to sources about correcting this problem).
Please answer directly to me, as I'm not subscribed to linux-kernel.
TIA,
Paulo Fessel
Quoted 9 lines · Paulo Afonso Graner Fessel
[...]
He said me that these funtions don't address the endianess question, and sent me a patch. He said that this probably wouldn't work, but I've decided to give a try anyway. Here is the patch:
tlan.c Thu Jun 7 21:37:42 2001 line 180
Quoted 9 lines
tlan.c Thu Jun 7 21:37:42 2001 renamed from tlan.c.old Thu Jun 7 21:24:25 2001 +6
-0@@ -172,6 +172,12 @@ #include <linux/delay.h> #include <linux/spinlock.h> +#if defined(__powerpc__) +#define inw(addr) le32_to_cpu(inw(addr)) +#define inl(addr) le32_to_cpu(inl(addr)) +#define outw(val, addr) outw(cpu_to_le32(val), addr) +#define outl(val, addr) outl(cpu_to_le32(val), addr) +#endif
On ppc the inw, inl, outw, and outl functions already byteswap, so by adding the extra byteswap you're now passing unswapped data to the chip. Take a look at include/asm-ppc/io.h and you'll see it uses byte reversed load and store instructions. Which means that either the chip is running in a big-endian mode, or that the problem is actually with data structures placed in host memory.
Often when porting a driver from i386 to ppc all that is required is to add the cpu_to_le32() macros around data in host memory that the device accesses, and to remove any #ifdef __powerpc__ code written by people who don't realise that ppc uses the standard linux pci code.
Signature · 1 line
Adrian Cox http://www.humboldt.co.uk/
Quoted 9 lines · Adrian Cox
tlan.c Thu Jun 7 21:37:42 2001 line 180
Quoted 6 lines
tlan.c Thu Jun 7 21:37:42 2001 renamed from tlan.c.old Thu Jun 7 21:24:25 2001 +6
-0+#if defined(__powerpc__) +#define inw(addr) le32_to_cpu(inw(addr)) +#define inl(addr) le32_to_cpu(inl(addr)) +#define outw(val, addr) outw(cpu_to_le32(val), addr) +#define outl(val, addr) outl(cpu_to_le32(val), addr) +#endifOn ppc the inw, inl, outw, and outl functions already byteswap, so by adding the extra byteswap you're now passing unswapped data to the chip.
Yes, and this is true for every architecture.
All of {in,out}{b,w,l}() and {read/write}{b,w,l}() swap to/from bus endianness for you.
Later,
David S. Miller
[email protected]
Hi David.
Quoted 13 lines · David S. Miller
Quoted 10 lines · Adrian Cox
tlan.c Thu Jun 7 21:37:42 2001 line 180
Quoted 6 lines
tlan.c Thu Jun 7 21:37:42 2001 renamed from tlan.c.old Thu Jun 7 21:24:25 2001 +6
-0+#if defined(__powerpc__) +#define inw(addr) le32_to_cpu(inw(addr)) +#define inl(addr) le32_to_cpu(inl(addr)) +#define outw(val, addr) outw(cpu_to_le32(val), addr) +#define outl(val, addr) outl(cpu_to_le32(val), addr) +#endifOn ppc the inw, inl, outw, and outl functions already byteswap, so by adding the extra byteswap you're now passing unswapped data to the chip.
Quoted 4 lines
Yes, and this is true for every architecture.
All of {in,out}{b,w,l}() and {read/write}{b,w,l}() swap to/from bus endianness for you.
Even if that wasn't true, aren't the above all self-recursive definitions that would prevent anything calling them from compiling?
Best wishes from Riley.
Quoted 2 lines · Riley Williams
Even if that wasn't true, aren't the above all self-recursive definitions that would prevent anything calling them from compiling?
Yes, it looks that way.
Later,
David S. Miller
[email protected]
Quoted 5 lines · [email protected] said:
Quoted 2 lines · Riley Williams
Even if that wasn't true, aren't the above all self-recursive definitions that would prevent anything calling them from compiling?
Yes, it looks that way.
cpp doesn't recurse.
--
dwmw2
Quoted 8 lines · David Woodhouse
Quoted 5 lines · [email protected] said:
Quoted 2 lines · Riley Williams
Even if that wasn't true, aren't the above all self-recursive definitions that would prevent anything calling them from compiling?
Yes, it looks that way.
cpp doesn't recurse.
My bad. What I actually mean is that it simply wouldn't work. They'd have to do something like drivers/net/eepro100.c does (grep for "#ifndef USE_IO").
Later,
David S. Miller
[email protected]