[CASSINI]: Fix endianness bug.
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 4 Jan 2008 02:49:00 +0000 (18:49 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 4 Jan 2008 08:47:04 +0000 (00:47 -0800)
Here's proposed fix for RX checksum handling in cassini; it affects
little-endian working with half-duplex gigabit, but obviously needs
testing on big-endian too.

The problem is, we need to convert checksum to fixed-endian *before*
correcting for (unstripped) FCS.  On big-endian it won't matter
(conversion is no-op), on little-endian it will, but only if FCS is
not stripped by hardware; i.e. in half-duplex gigabit mode when
->crc_size is set.

cassini.c part is that fix, cassini.h one consists of trivial
endianness annotations.  With that applied the sucker is endian-clean,
according to sparse.

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

index 7df31b5561cc02000cbc44d1ea2048bd016f4e58..9030ca54a5bdf407d24aaa40929ea2e8403a3479 100644 (file)
@@ -1979,6 +1979,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
        struct cas_page *page;
        struct sk_buff *skb;
        void *addr, *crcaddr;
+       __sum16 csum;
        char *p;
 
        hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
@@ -2158,14 +2159,15 @@ end_copy_pkt:
                skb_put(skb, alloclen);
        }
 
-       i = CAS_VAL(RX_COMP4_TCP_CSUM, words[3]);
+       csum = (__force __sum16)htons(CAS_VAL(RX_COMP4_TCP_CSUM, words[3]));
        if (cp->crc_size) {
                /* checksum includes FCS. strip it out. */
-               i = csum_fold(csum_partial(crcaddr, cp->crc_size, i));
+               csum = csum_fold(csum_partial(crcaddr, cp->crc_size,
+                                             csum_unfold(csum)));
                if (addr)
                        cas_page_unmap(addr);
        }
-       skb->csum = ntohs(i ^ 0xffff);
+       skb->csum = csum_unfold(~csum);
        skb->ip_summed = CHECKSUM_COMPLETE;
        skb->protocol = eth_type_trans(skb, cp->dev);
        return len;
index 2f93f83342d2575e146f8999ff37bafb55170dd6..552af89ca1cf04f49165248293570132bdaa189a 100644 (file)
@@ -4122,8 +4122,8 @@ cas_saturn_patch_t cas_saturn_patch[] = {
                                                             inserted into
                                                             outgoing frame. */
 struct cas_tx_desc {
-       u64     control;
-       u64     buffer;
+       __le64     control;
+       __le64     buffer;
 };
 
 /* descriptor ring for free buffers contains page-sized buffers. the index
@@ -4131,8 +4131,8 @@ struct cas_tx_desc {
  * the completion ring.
  */
 struct cas_rx_desc {
-       u64     index;
-       u64     buffer;
+       __le64     index;
+       __le64     buffer;
 };
 
 /* received packets are put on the completion ring. */
@@ -4210,10 +4210,10 @@ struct cas_rx_desc {
 #define RX_INDEX_RELEASE                  0x0000000000002000ULL
 
 struct cas_rx_comp {
-       u64     word1;
-       u64     word2;
-       u64     word3;
-       u64     word4;
+       __le64     word1;
+       __le64     word2;
+       __le64     word3;
+       __le64     word4;
 };
 
 enum link_state {
@@ -4252,7 +4252,7 @@ struct cas_init_block {
        struct cas_rx_comp rxcs[N_RX_COMP_RINGS][INIT_BLOCK_RX_COMP];
        struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
        struct cas_tx_desc txds[N_TX_RINGS][INIT_BLOCK_TX];
-       u64 tx_compwb;
+       __le64 tx_compwb;
 };
 
 /* tiny buffers to deal with target abort issue. we allocate a bit