]> err.no Git - linux-2.6/blobdiff - drivers/net/forcedeth.c
Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / drivers / net / forcedeth.c
index c93f3d08dc4274164a9294bc4c811e75df0a6710..64f0f697c958ad399317fe7cc628bf93d9f73018 100644 (file)
  *                        cause DMA to kfree'd memory.
  *     0.31: 14 Nov 2004: ethtool support for getting/setting link
  *                        capabilities.
+ *     0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ *     0.33: 16 May 2005: Support for MCP51 added.
+ *     0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ *     0.35: 26 Jun 2005: Support for MCP55 added.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
@@ -92,7 +96,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.31"
+#define FORCEDETH_VERSION              "0.35"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
 #include <linux/mii.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/if_vlan.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -1013,6 +1018,59 @@ static void nv_tx_timeout(struct net_device *dev)
        spin_unlock_irq(&np->lock);
 }
 
+/*
+ * Called when the nic notices a mismatch between the actual data len on the
+ * wire and the len indicated in the 802 header
+ */
+static int nv_getlen(struct net_device *dev, void *packet, int datalen)
+{
+       int hdrlen;     /* length of the 802 header */
+       int protolen;   /* length as stored in the proto field */
+
+       /* 1) calculate len according to header */
+       if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+               protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
+               hdrlen = VLAN_HLEN;
+       } else {
+               protolen = ntohs( ((struct ethhdr *)packet)->h_proto);
+               hdrlen = ETH_HLEN;
+       }
+       dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n",
+                               dev->name, datalen, protolen, hdrlen);
+       if (protolen > ETH_DATA_LEN)
+               return datalen; /* Value in proto field not a len, no checks possible */
+
+       protolen += hdrlen;
+       /* consistency checks: */
+       if (datalen > ETH_ZLEN) {
+               if (datalen >= protolen) {
+                       /* more data on wire than in 802 header, trim of
+                        * additional data.
+                        */
+                       dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+                                       dev->name, protolen);
+                       return protolen;
+               } else {
+                       /* less data on wire than mentioned in header.
+                        * Discard the packet.
+                        */
+                       dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n",
+                                       dev->name);
+                       return -1;
+               }
+       } else {
+               /* short packet. Accept only if 802 values are also short */
+               if (protolen > ETH_ZLEN) {
+                       dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n",
+                                       dev->name);
+                       return -1;
+               }
+               dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+                               dev->name, datalen);
+               return datalen;
+       }
+}
+
 static void nv_rx_process(struct net_device *dev)
 {
        struct fe_priv *np = get_nvpriv(dev);
@@ -1064,7 +1122,7 @@ static void nv_rx_process(struct net_device *dev)
                                np->stats.rx_errors++;
                                goto next_pkt;
                        }
-                       if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
+                       if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
                                np->stats.rx_errors++;
                                goto next_pkt;
                        }
@@ -1078,22 +1136,24 @@ static void nv_rx_process(struct net_device *dev)
                                np->stats.rx_errors++;
                                goto next_pkt;
                        }
-                       if (Flags & NV_RX_ERROR) {
-                               /* framing errors are soft errors, the rest is fatal. */
-                               if (Flags & NV_RX_FRAMINGERR) {
-                                       if (Flags & NV_RX_SUBSTRACT1) {
-                                               len--;
-                                       }
-                               } else {
+                       if (Flags & NV_RX_ERROR4) {
+                               len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+                               if (len < 0) {
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
                        }
+                       /* framing errors are soft errors. */
+                       if (Flags & NV_RX_FRAMINGERR) {
+                               if (Flags & NV_RX_SUBSTRACT1) {
+                                       len--;
+                               }
+                       }
                } else {
                        if (!(Flags & NV_RX2_DESCRIPTORVALID))
                                goto next_pkt;
 
-                       if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {
+                       if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
                                np->stats.rx_errors++;
                                goto next_pkt;
                        }
@@ -1107,17 +1167,19 @@ static void nv_rx_process(struct net_device *dev)
                                np->stats.rx_errors++;
                                goto next_pkt;
                        }
-                       if (Flags & NV_RX2_ERROR) {
-                               /* framing errors are soft errors, the rest is fatal. */
-                               if (Flags & NV_RX2_FRAMINGERR) {
-                                       if (Flags & NV_RX2_SUBSTRACT1) {
-                                               len--;
-                                       }
-                               } else {
+                       if (Flags & NV_RX2_ERROR4) {
+                               len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+                               if (len < 0) {
                                        np->stats.rx_errors++;
                                        goto next_pkt;
                                }
                        }
+                       /* framing errors are soft errors */
+                       if (Flags & NV_RX2_FRAMINGERR) {
+                               if (Flags & NV_RX2_SUBSTRACT1) {
+                                       len--;
+                               }
+                       }
                        Flags &= NV_RX2_CHECKSUMMASK;
                        if (Flags == NV_RX2_CHECKSUMOK1 ||
                                        Flags == NV_RX2_CHECKSUMOK2 ||
@@ -1946,7 +2008,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        /* handle different descriptor versions */
        if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
                pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
-               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||    
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+               pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
                np->desc_ver = DESC_VER_1;
        else
                np->desc_ver = DESC_VER_2;
@@ -2156,56 +2220,84 @@ static struct pci_device_id pci_tbl[] = {
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_5,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_6,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_7,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* CK804 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* CK804 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* MCP04 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* MCP04 Ethernet Controller */
                .vendor = PCI_VENDOR_ID_NVIDIA,
                .device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_ANY_ID,
-               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP51 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP51 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP55 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+       },
+       {       /* MCP55 Ethernet Controller */
+               .vendor = PCI_VENDOR_ID_NVIDIA,
+               .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
+               .subvendor = PCI_ANY_ID,
+               .subdevice = PCI_ANY_ID,
+               .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {0,},
 };