Hi list,

I have been running recent linux kernel on nexcom NSA 1086's equipped
with sysconnect NICs.

Like some people previously have on this list I am running into
problems with these NICs and seeing frequent errors in my dmesg:

sky2 eth4: rx error, status 0x402300 length 60
printk: 17 messages suppressed.
sky2 eth4: rx error, status 0x402300 length 60
printk: 32 messages suppressed.
sky2 eth4: rx error, status 0x602300 length 92
printk: 25 messages suppressed.
sky2 eth4: rx error, status 0x6e2300 length 106
printk: 16 messages suppressed.
sky2 eth4: rx error, status 0x402300 length 60
printk: 10 messages suppressed.
sky2 eth4: rx error, status 0x402300 length 60
printk: 17 messages suppressed.
sky2 eth4: rx error, status 0x402300 length 60


I have investigated a bit and status doesn't match any of the errors in
GMR_FS_ANY_ERR.
The block generating the error is now len_mismatch, due to the fact
that on packets having the GMR_FS_VLAN bit set, the length argument to
sky2_receive is 4 bytes shorter that the 16 bit value in status (status
``right shift'' 16).

Since both these values are read from the card I don't know how to
solve this other than by incrementing the length arg by 4 when
GMR_FS_VLAN is set in status. So here's a diff that does this, although
I'm not sure its an elegant solution:

--- sky2.c.orig 2007-09-10 15:34:15.000000000 +0200
+++ sky2.c      2007-09-10 16:20:28.000000000 +0200
@@ -2059,13 +2059,16 @@ static struct sk_buff *sky2_receive(stru
        sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
        prefetch(sky2->rx_ring + sky2->rx_next);
 
+       if (status & GMR_FS_VLAN)
+               length += 4;
+
        if (status & GMR_FS_ANY_ERR)
                goto error;
 
        if (!(status & GMR_FS_RX_OK))
                goto resubmit;
 
-       if (status >> 16 != length)
+       if ((status >> 16) != length)
                goto len_mismatch;
 
        if (length < copybreak)
@@ -2081,6 +2084,8 @@ len_mismatch:
        /* Truncation of overlength packets
           causes PHY length to not match MAC length */
        ++sky2->net_stats.rx_length_errors;
+       printk(KERN_INFO PFX "%s: rx length mismatch: length %d != %d\n",
+              dev->name, length, status >> 16);
 
 error:
        ++sky2->net_stats.rx_errors;

Any thoughts on how to solve this ?
Further testing shows that sometimes there are packets without the
GMR_FS_VLAN bit set which have a 4 bytes length difference, has shown
by this log excerpt:

sky2 eth4: rx length mismatch: length 243 != 247
sky2 eth4: rx error, status 0xf70300 length 243

For debugging purposes, I here is the little program with
excerpts from sky2.c I use to see what bits are set in the status field:

#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

enum {
        GMR_FS_LEN      = 0xffff<<16, /* Bit 31..16:    Rx Frame Length */
        GMR_FS_VLAN     = 1<<13, /* VLAN Packet */
        GMR_FS_JABBER   = 1<<12, /* Jabber Packet */
        GMR_FS_UN_SIZE  = 1<<11, /* Undersize Packet */
        GMR_FS_MC       = 1<<10, /* Multicast Packet */
        GMR_FS_BC       = 1<<9,  /* Broadcast Packet */
        GMR_FS_RX_OK    = 1<<8,  /* Receive OK (Good Packet) */
        GMR_FS_GOOD_FC  = 1<<7,  /* Good Flow-Control Packet */
        GMR_FS_BAD_FC   = 1<<6,  /* Bad  Flow-Control Packet */
        GMR_FS_MII_ERR  = 1<<5,  /* MII Error */
        GMR_FS_LONG_ERR = 1<<4,  /* Too Long Packet */
        GMR_FS_FRAGMENT = 1<<3,  /* Fragment */

        GMR_FS_CRC_ERR  = 1<<1,  /* CRC Error */
        GMR_FS_RX_FF_OV = 1<<0,  /* Rx FIFO Overflow */

        GMR_FS_ANY_ERR  = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
                          GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
                          GMR_FS_MII_ERR | GMR_FS_BAD_FC |
                          GMR_FS_UN_SIZE | GMR_FS_JABBER,
};

struct bitdesc {
        const char      *name;
        u_int32_t        field;
};

struct bitdesc bits[] = {
        { "GMR_FS_VLAN", 1 << 13 },
        { "GMR_FS_JABBER", 1 << 12 },
        { "GMR_FS_UN_SIZE", 1 << 11 },
        { "GMR_FS_MC", 1 << 10 },
        { "GMR_FS_BC", 1 << 9 },
        { "GMR_FS_RX_OK", 1 << 8 },
        { "GMR_FS_GOOD_FC", 1 << 7 },
        { "GMR_FS_BAD_FC", 1 << 6 },
        { "GMR_FS_MII_ERR", 1 << 5 },
        { "GMR_FS_LONG_ERR", 1 << 4 },
        { "GMR_FS_FRAGMENT", 1 << 3 },
        { "GMR_FS_CRC_ERR", 1 << 1 },
        { "GMR_FS_RX_FF_OV", 1 << 0 }
};

int
main(int argc, const char *argv[])
{
        int     status;
        int     i;

        if (argc < 2)
                return (1);

        status = strtol(argv[1], NULL, 16);
        printf("status: 0x%08x\n", status);
        if (status & GMR_FS_ANY_ERR)
                printf("packet has an error\n");
        printf("length: %u\n", status >> 16);

        for (i = 0; i < (sizeof(bits) / sizeof(bits[0])); i++) {
                if (status & bits[i].field) {
                        printf("has bit %s\n", bits[i].name);
                }
        }
        return (0);
}
-
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