]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - drivers/net/r8169.c
[PATCH] r8169: incoming frame length check
[linux-3.10.git] / drivers / net / r8169.c
index c59507f8a76befe001f1313f55b6780423d1e778..b3768d84474700296bf04aab92513b15f216eddb 100644 (file)
@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
        RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
        RTL_W8(EarlyTxThres, EarlyTxThld);
 
-       /* For gigabit rtl8169, MTU + header + CRC + VLAN */
-       RTL_W16(RxMaxSize, tp->rx_buf_sz);
+       /* Low hurts. Let's disable the filtering. */
+       RTL_W16(RxMaxSize, 16383);
 
        /* Set Rx Config register */
        i = rtl8169_rx_config |
@@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
        }
 }
 
+static inline int rtl8169_fragmented_frame(u32 status)
+{
+       return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
+}
+
 static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
 {
        u32 opts1 = le32_to_cpu(desc->opts1);
@@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 
        while (rx_left > 0) {
                unsigned int entry = cur_rx % NUM_RX_DESC;
+               struct RxDesc *desc = tp->RxDescArray + entry;
                u32 status;
 
                rmb();
-               status = le32_to_cpu(tp->RxDescArray[entry].opts1);
+               status = le32_to_cpu(desc->opts1);
 
                if (status & DescOwn)
                        break;
                if (status & RxRES) {
-                       printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
+                       printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
+                              dev->name, status);
                        tp->stats.rx_errors++;
                        if (status & (RxRWT | RxRUNT))
                                tp->stats.rx_length_errors++;
                        if (status & RxCRC)
                                tp->stats.rx_crc_errors++;
+                       rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
                } else {
-                       struct RxDesc *desc = tp->RxDescArray + entry;
                        struct sk_buff *skb = tp->Rx_skbuff[entry];
                        int pkt_size = (status & 0x00001FFF) - 4;
                        void (*pci_action)(struct pci_dev *, dma_addr_t,
                                size_t, int) = pci_dma_sync_single_for_device;
 
+                       /*
+                        * The driver does not support incoming fragmented
+                        * frames. They are seen as a symptom of over-mtu
+                        * sized frames.
+                        */
+                       if (unlikely(rtl8169_fragmented_frame(status))) {
+                               tp->stats.rx_dropped++;
+                               tp->stats.rx_length_errors++;
+                               rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+                               goto move_on;
+                       }
+
                        rtl8169_rx_csum(skb, desc);
                        
                        pci_dma_sync_single_for_cpu(tp->pci_dev,
@@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
                        tp->stats.rx_bytes += pkt_size;
                        tp->stats.rx_packets++;
                }
-               
+move_on:               
                cur_rx++; 
                rx_left--;
        }