8139too: Support RX-ALL logic.
authorBen Greear <greearb@candelatech.com>
Fri, 10 Feb 2012 15:04:31 +0000 (15:04 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 24 Feb 2012 09:56:08 +0000 (01:56 -0800)
This allows the NIC to receive Runts and frames with bad
Ethernet Frame Checksums (FCS).

Useful to sniffing & diagnosing bad networks.

Signed-off-by: Ben Greear <greearb@candelatech.com>
drivers/net/ethernet/realtek/8139too.c

index 1c3feb0116b5da0bc497e30c1f415bb904076288..1b9a090d4865419ee9936c99bde0351d27fbb44a 100644 (file)
@@ -907,6 +907,33 @@ err_out:
        return ERR_PTR(rc);
 }
 
+static int rtl8139_set_features(struct net_device *dev, netdev_features_t features)
+{
+       struct rtl8139_private *tp = netdev_priv(dev);
+       unsigned long flags;
+       netdev_features_t changed = features ^ dev->features;
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       if (!(changed & (NETIF_F_RXALL)))
+               return 0;
+
+       spin_lock_irqsave(&tp->lock, flags);
+
+       if (changed & NETIF_F_RXALL) {
+               int rx_mode = tp->rx_config;
+               if (features & NETIF_F_RXALL)
+                       rx_mode |= (AcceptErr | AcceptRunt);
+               else
+                       rx_mode &= ~(AcceptErr | AcceptRunt);
+               tp->rx_config = rtl8139_rx_config | rx_mode;
+               RTL_W32_F(RxConfig, tp->rx_config);
+       }
+
+       spin_unlock_irqrestore(&tp->lock, flags);
+
+       return 0;
+}
+
 static const struct net_device_ops rtl8139_netdev_ops = {
        .ndo_open               = rtl8139_open,
        .ndo_stop               = rtl8139_close,
@@ -921,6 +948,7 @@ static const struct net_device_ops rtl8139_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = rtl8139_poll_controller,
 #endif
+       .ndo_set_features       = rtl8139_set_features,
 };
 
 static int __devinit rtl8139_init_one (struct pci_dev *pdev,
@@ -994,6 +1022,8 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
        dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
        dev->vlan_features = dev->features;
 
+       dev->hw_features |= NETIF_F_RXALL;
+
        dev->irq = pdev->irq;
 
        /* tp zeroed and aligned in alloc_etherdev */
@@ -1978,11 +2008,30 @@ no_early_rx:
                if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
                             (rx_size < 8) ||
                             (!(rx_status & RxStatusOK)))) {
+                       if ((dev->features & NETIF_F_RXALL) &&
+                           (rx_size <= (MAX_ETH_FRAME_SIZE + 4)) &&
+                           (rx_size >= 8) &&
+                           (!(rx_status & RxStatusOK))) {
+                               /* Length is at least mostly OK, but pkt has
+                                * error.  I'm hoping we can handle some of these
+                                * errors without resetting the chip. --Ben
+                                */
+                               dev->stats.rx_errors++;
+                               if (rx_status & RxCRCErr) {
+                                       dev->stats.rx_crc_errors++;
+                                       goto keep_pkt;
+                               }
+                               if (rx_status & RxRunt) {
+                                       dev->stats.rx_length_errors++;
+                                       goto keep_pkt;
+                               }
+                       }
                        rtl8139_rx_err (rx_status, dev, tp, ioaddr);
                        received = -1;
                        goto out;
                }
 
+keep_pkt:
                /* Malloc up new buffer, compatible with net-2e. */
                /* Omit the four octet CRC from the length. */
 
@@ -2515,6 +2564,9 @@ static void __set_rx_mode (struct net_device *dev)
                }
        }
 
+       if (dev->features & NETIF_F_RXALL)
+               rx_mode |= (AcceptErr | AcceptRunt);
+
        /* We can safely update without stopping the chip. */
        tmp = rtl8139_rx_config | rx_mode;
        if (tp->rx_config != tmp) {