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