ralink: add TSO
[openwrt/staging/chunkeey.git] / target / linux / ramips / patches-3.10 / 0111-NET-MIPS-add-ralink-SoC-ethernet-driver.patch
index 96daed4ffbff1b89acc4410f92408addfc87bd63..b298c536cba0ea6a1e94a93d92a785b1b73d2c3e 100644 (file)
@@ -46,10 +46,10 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
  create mode 100644 drivers/net/ethernet/ralink/soc_rt305x.c
  create mode 100644 drivers/net/ethernet/ralink/soc_rt3883.c
 
-Index: linux-3.10.18/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h
+Index: linux-3.10.21/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h      2013-11-19 11:15:38.964470794 +0100
++++ linux-3.10.21/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h      2013-12-09 13:26:42.320125202 +0100
 @@ -0,0 +1,27 @@
 +/*
 + *  Ralink RT305x SoC platform device registration
@@ -78,10 +78,10 @@ Index: linux-3.10.18/arch/mips/include/asm/mach-ralink/rt305x_esw_platform.h
 +};
 +
 +#endif /* _RT305X_ESW_PLATFORM_H */
-Index: linux-3.10.18/arch/mips/ralink/rt305x.c
+Index: linux-3.10.21/arch/mips/ralink/rt305x.c
 ===================================================================
---- linux-3.10.18.orig/arch/mips/ralink/rt305x.c       2013-11-04 13:31:29.000000000 +0100
-+++ linux-3.10.18/arch/mips/ralink/rt305x.c    2013-11-21 12:04:47.524164571 +0100
+--- linux-3.10.21.orig/arch/mips/ralink/rt305x.c       2013-11-29 20:12:03.000000000 +0100
++++ linux-3.10.21/arch/mips/ralink/rt305x.c    2013-12-09 14:04:34.200179338 +0100
 @@ -221,6 +221,7 @@
        }
  
@@ -90,10 +90,10 @@ Index: linux-3.10.18/arch/mips/ralink/rt305x.c
        ralink_clk_add("10000b00.spi", sys_rate);
        ralink_clk_add("10000100.timer", wdt_rate);
        ralink_clk_add("10000120.watchdog", wdt_rate);
-Index: linux-3.10.18/drivers/net/ethernet/Kconfig
+Index: linux-3.10.21/drivers/net/ethernet/Kconfig
 ===================================================================
---- linux-3.10.18.orig/drivers/net/ethernet/Kconfig    2013-11-04 13:31:29.000000000 +0100
-+++ linux-3.10.18/drivers/net/ethernet/Kconfig 2013-11-19 11:15:38.964470794 +0100
+--- linux-3.10.21.orig/drivers/net/ethernet/Kconfig    2013-11-29 20:12:03.000000000 +0100
++++ linux-3.10.21/drivers/net/ethernet/Kconfig 2013-12-09 13:26:42.324125203 +0100
 @@ -135,6 +135,7 @@
  source "drivers/net/ethernet/packetengines/Kconfig"
  source "drivers/net/ethernet/pasemi/Kconfig"
@@ -102,10 +102,10 @@ Index: linux-3.10.18/drivers/net/ethernet/Kconfig
  source "drivers/net/ethernet/realtek/Kconfig"
  source "drivers/net/ethernet/renesas/Kconfig"
  source "drivers/net/ethernet/rdc/Kconfig"
-Index: linux-3.10.18/drivers/net/ethernet/Makefile
+Index: linux-3.10.21/drivers/net/ethernet/Makefile
 ===================================================================
---- linux-3.10.18.orig/drivers/net/ethernet/Makefile   2013-11-04 13:31:29.000000000 +0100
-+++ linux-3.10.18/drivers/net/ethernet/Makefile        2013-11-19 11:15:38.964470794 +0100
+--- linux-3.10.21.orig/drivers/net/ethernet/Makefile   2013-11-29 20:12:03.000000000 +0100
++++ linux-3.10.21/drivers/net/ethernet/Makefile        2013-12-09 13:26:42.324125203 +0100
 @@ -53,6 +53,7 @@
  obj-$(CONFIG_NET_PACKET_ENGINE) += packetengines/
  obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
@@ -114,11 +114,11 @@ Index: linux-3.10.18/drivers/net/ethernet/Makefile
  obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
  obj-$(CONFIG_SH_ETH) += renesas/
  obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
-Index: linux-3.10.18/drivers/net/ethernet/ralink/Kconfig
+Index: linux-3.10.21/drivers/net/ethernet/ralink/Kconfig
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/Kconfig  2013-11-19 11:15:38.964470794 +0100
-@@ -0,0 +1,31 @@
++++ linux-3.10.21/drivers/net/ethernet/ralink/Kconfig  2013-12-09 13:26:42.324125203 +0100
+@@ -0,0 +1,32 @@
 +config NET_RALINK
 +      tristate "Ralink RT288X/RT3X5X/RT3662/RT3883/MT7620 ethernet driver"
 +      depends on RALINK
@@ -146,14 +146,15 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/Kconfig
 +config NET_RALINK_GSW_MT7620
 +      def_bool NET_RALINK
 +      depends on SOC_MT7620
++      select INET_LRO
 +      select NET_RALINK_MDIO
 +      select PHYLIB
 +      select SWCONFIG
 +endif
-Index: linux-3.10.18/drivers/net/ethernet/ralink/Makefile
+Index: linux-3.10.21/drivers/net/ethernet/ralink/Makefile
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/Makefile 2013-11-19 11:15:38.964470794 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/Makefile 2013-12-09 13:26:42.324125203 +0100
 @@ -0,0 +1,18 @@
 +#
 +# Makefile for the Ralink SoCs built-in ethernet macs
@@ -173,10 +174,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/Makefile
 +ralink-eth-$(CONFIG_SOC_MT7620)                       += soc_mt7620.o
 +
 +obj-$(CONFIG_NET_RALINK)                      += ralink-eth.o
-Index: linux-3.10.18/drivers/net/ethernet/ralink/esw_rt3052.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/esw_rt3052.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/esw_rt3052.c     2013-11-19 11:15:38.968470792 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/esw_rt3052.c     2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,1463 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -1641,10 +1642,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/esw_rt3052.c
 +{
 +      platform_driver_unregister(&esw_driver);
 +}
-Index: linux-3.10.18/drivers/net/ethernet/ralink/esw_rt3052.h
+Index: linux-3.10.21/drivers/net/ethernet/ralink/esw_rt3052.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/esw_rt3052.h     2013-11-19 11:15:38.968470792 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/esw_rt3052.h     2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,32 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -1678,10 +1679,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/esw_rt3052.h
 +
 +#endif
 +#endif
-Index: linux-3.10.18/drivers/net/ethernet/ralink/gsw_mt7620a.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/gsw_mt7620a.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/gsw_mt7620a.c    2013-11-19 11:15:38.968470792 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/gsw_mt7620a.c    2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,566 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -2249,10 +2250,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/gsw_mt7620a.c
 +
 +      return 0;
 +}
-Index: linux-3.10.18/drivers/net/ethernet/ralink/gsw_mt7620a.h
+Index: linux-3.10.21/drivers/net/ethernet/ralink/gsw_mt7620a.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/gsw_mt7620a.h    2013-11-19 11:15:38.968470792 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/gsw_mt7620a.h    2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,30 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -2284,10 +2285,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/gsw_mt7620a.h
 +extern int mt7620a_has_carrier(struct fe_priv *priv);
 +
 +#endif
-Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/mdio.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/mdio.c   2013-11-19 11:15:38.968470792 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/mdio.c   2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,244 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -2533,10 +2534,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio.c
 +      of_node_put(priv->mii_bus->dev.of_node);
 +      kfree(priv->mii_bus);
 +}
-Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio.h
+Index: linux-3.10.21/drivers/net/ethernet/ralink/mdio.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/mdio.h   2013-11-19 11:15:38.968470792 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/mdio.h   2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,29 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -2567,10 +2568,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio.h
 +static inline void fe_mdio_cleanup(struct fe_priv *priv) {}
 +#endif
 +#endif
-Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio_rt2880.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/mdio_rt2880.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/mdio_rt2880.c    2013-11-19 11:15:38.972470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/mdio_rt2880.c    2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,232 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -2804,10 +2805,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio_rt2880.c
 +
 +      return;
 +}
-Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio_rt2880.h
+Index: linux-3.10.21/drivers/net/ethernet/ralink/mdio_rt2880.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/mdio_rt2880.h    2013-11-19 11:15:38.972470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/mdio_rt2880.h    2013-12-09 13:26:42.328125203 +0100
 @@ -0,0 +1,26 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -2835,11 +2836,11 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/mdio_rt2880.h
 +void rt2880_port_init(struct fe_priv *priv, struct device_node *np);
 +
 +#endif
-Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/ralink_soc_eth.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c 2013-11-21 11:29:22.000113924 +0100
-@@ -0,0 +1,744 @@
++++ linux-3.10.21/drivers/net/ethernet/ralink/ralink_soc_eth.c 2013-12-09 14:01:00.060174130 +0100
+@@ -0,0 +1,846 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
 + *   it under the terms of the GNU General Public License as published by
@@ -2879,8 +2880,9 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +#include "esw_rt3052.h"
 +#include "mdio.h"
 +
-+#define TX_TIMEOUT            (20 * HZ / 100)
++#define TX_TIMEOUT            (2 * HZ)
 +#define       MAX_RX_LENGTH           1536
++#define DMA_DUMMY_DESC                0xffffffff
 +
 +static const u32 fe_reg_table_default[FE_REG_COUNT] = {
 +      [FE_REG_PDMA_GLO_CFG] = FE_PDMA_GLO_CFG,
@@ -3081,12 +3083,41 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +      netdev_reset_queue(priv->netdev);
 +}
 +
++static void fe_start_tso(struct sk_buff *skb, struct net_device *dev, unsigned int nr_frags, int idx)
++{
++        struct fe_priv *priv = netdev_priv(dev);
++      struct skb_frag_struct *frag;
++      int i;
++
++      for (i = 0; i < nr_frags; i++) {
++              dma_addr_t mapped_addr;
++
++              frag = &skb_shinfo(skb)->frags[i];
++              mapped_addr = skb_frag_dma_map(&dev->dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE);
++              if (i % 2) {
++                      idx = (idx + 1) % NUM_DMA_DESC;
++                      priv->tx_dma[idx].txd1 = mapped_addr;
++                      if (i == nr_frags - 1)
++                              priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(frag->size);
++                      else
++                              priv->tx_dma[idx].txd2 = TX_DMA_PLEN0(frag->size);
++              } else {
++                      priv->tx_dma[idx].txd3 = mapped_addr;
++                      if (i == nr_frags - 1)
++                              priv->tx_dma[idx].txd2 |= TX_DMA_LS1 | TX_DMA_PLEN1(frag->size);
++                      else
++                              priv->tx_dma[idx].txd2 |= TX_DMA_PLEN1(frag->size);
++              }
++      }
++}
++
 +static int fe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 +{
++      unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
 +      struct fe_priv *priv = netdev_priv(dev);
 +      dma_addr_t mapped_addr;
-+      u32 tx_next;
-+      u32 tx;
++      u32 tx_next, tx, tx_num = 1;
++      int i;
 +
 +      if (priv->soc->min_pkt_len) {
 +              if (skb->len < priv->soc->min_pkt_len) {
@@ -3107,8 +3138,9 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +      spin_lock(&priv->page_lock);
 +
 +      tx = fe_reg_r32(FE_REG_TX_CTX_IDX0);
-+      tx_next = (tx + 1) % NUM_DMA_DESC;
-+
++      if (priv->soc->tso && nr_frags)
++              tx_num += nr_frags >> 1;
++      tx_next = (tx + tx_num) % NUM_DMA_DESC;
 +      if ((priv->tx_skb[tx]) || (priv->tx_skb[tx_next]) ||
 +                      !(priv->tx_dma[tx].txd2 & TX_DMA_DONE) ||
 +                      !(priv->tx_dma[tx_next].txd2 & TX_DMA_DONE))
@@ -3120,7 +3152,15 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +              return NETDEV_TX_OK;
 +      }
 +
-+      priv->tx_skb[tx] = skb;
++      if (priv->soc->tso) {
++              int t = tx_num;
++
++              priv->tx_skb[(tx + t - 1) % NUM_DMA_DESC] = skb;
++              while (--t)
++                      priv->tx_skb[(tx + t - 1) % NUM_DMA_DESC] = (struct sk_buff *) DMA_DUMMY_DESC;
++      } else {
++              priv->tx_skb[tx] = skb;
++      }
 +      priv->tx_dma[tx].txd1 = (unsigned int) mapped_addr;
 +      wmb();
 +
@@ -3135,9 +3175,36 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +      else
 +              priv->tx_dma[tx].txd4 &= ~TX_DMA_CHKSUM;
 +
++      if (priv->soc->tso)
++              fe_start_tso(skb, dev, nr_frags, tx);
++
++      if (skb_shinfo(skb)->gso_segs > 1) {
++              struct iphdr *iph = NULL;
++              struct tcphdr *th = NULL;
++              struct ipv6hdr *ip6h = NULL;
++
++              ip6h = (struct ipv6hdr *) skb_network_header(skb);
++              iph = (struct iphdr *) skb_network_header(skb);
++              if ((iph->version == 4) && (iph->protocol == IPPROTO_TCP)) {
++                      th = (struct tcphdr *)skb_transport_header(skb);
++                      priv->tx_dma[tx].txd4 |= BIT(28);
++                      th->check = htons(skb_shinfo(skb)->gso_size);
++                      dma_cache_sync(NULL, th, sizeof(struct tcphdr), DMA_TO_DEVICE);
++              } else if ((ip6h->version == 6) && (ip6h->nexthdr == NEXTHDR_TCP)) {
++                      th = (struct tcphdr *)skb_transport_header(skb);
++                      priv->tx_dma[tx].txd4 |= BIT(28);
++                      th->check = htons(skb_shinfo(skb)->gso_size);
++                      dma_cache_sync(NULL, th, sizeof(struct tcphdr), DMA_TO_DEVICE);
++              }
++      }
++
++      for (i = 0; i < tx_num; i++)
++              dma_cache_sync(NULL,  &priv->tx_dma[tx + i], sizeof(struct fe_tx_dma), DMA_TO_DEVICE);
++
 +      dev->stats.tx_packets++;
 +      dev->stats.tx_bytes += skb->len;
 +
++      wmb();
 +      fe_reg_w32(tx_next, FE_REG_TX_CTX_IDX0);
 +      netdev_sent_queue(dev, skb->len);
 +
@@ -3175,7 +3242,13 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +                                      priv->rx_skb[idx]->ip_summed = CHECKSUM_NONE;
 +                              priv->netdev->stats.rx_packets++;
 +                              priv->netdev->stats.rx_bytes += pktlen;
-+                              netif_receive_skb(priv->rx_skb[idx]);
++
++#ifdef CONFIG_INET_LRO
++                              if (priv->soc->get_skb_header && priv->rx_skb[idx]->ip_summed == CHECKSUM_UNNECESSARY)
++                                      lro_receive_skb(&priv->lro_mgr, priv->rx_skb[idx], NULL);
++                              else
++#endif
++                                      netif_receive_skb(priv->rx_skb[idx]);
 +
 +                              priv->rx_skb[idx] = new_skb;
 +
@@ -3201,6 +3274,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +              }
 +      }
 +
++#ifdef CONFIG_INET_LRO
++      if (priv->soc->get_skb_header)
++              lro_flush_all(&priv->lro_mgr);
++#endif
 +      if (complete) {
 +              napi_complete(&priv->rx_napi);
 +              fe_int_enable(priv->soc->rx_dly_int);
@@ -3225,10 +3302,11 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +              if (!(txd->txd2 & TX_DMA_DONE) || !(priv->tx_skb[priv->tx_free_idx]))
 +                      break;
 +
-+              bytes_compl += priv->tx_skb[priv->tx_free_idx]->len;
++              if (priv->tx_skb[priv->tx_free_idx] != (struct sk_buff *) DMA_DUMMY_DESC) {
++                      bytes_compl += priv->tx_skb[priv->tx_free_idx]->len;
++                      dev_kfree_skb_irq(priv->tx_skb[priv->tx_free_idx]);
++              }
 +              pkts_compl++;
-+
-+              dev_kfree_skb_irq(priv->tx_skb[priv->tx_free_idx]);
 +              priv->tx_skb[priv->tx_free_idx] = NULL;
 +              priv->tx_free_idx++;
 +              if (priv->tx_free_idx >= NUM_DMA_DESC)
@@ -3477,6 +3555,9 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +
 +      match = of_match_device(of_fe_match, &pdev->dev);
 +      soc = (struct fe_soc_data *) match->data;
++
++      if (soc->init_data)
++              soc->init_data(soc);
 +      if (soc->reg_table)
 +              fe_reg_table = soc->reg_table;
 +
@@ -3499,6 +3580,13 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +      if (fe_reg_table[FE_REG_FE_DMA_VID_BASE])
 +              netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
 +
++      if (soc->tso) {
++              dev_info(&pdev->dev, "Enabling TSO\n");
++              netdev->features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_IPV6_CSUM;
++      }
++
++      netdev->hw_features = netdev->vlan_features = netdev->features;
++
 +      netdev->irq = platform_get_irq(pdev, 0);
 +      if (netdev->irq < 0) {
 +              dev_err(&pdev->dev, "no IRQ resource found\n");
@@ -3526,6 +3614,21 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +      }
 +      netif_napi_add(netdev, &priv->rx_napi, fe_poll_rx, 32);
 +
++#ifdef CONFIG_INET_LRO
++      if (priv->soc->get_skb_header) {
++              priv->lro_mgr.dev = netdev;
++              memset(&priv->lro_mgr.stats, 0, sizeof(priv->lro_mgr.stats));
++              priv->lro_mgr.features = LRO_F_NAPI;
++              priv->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
++              priv->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
++              priv->lro_mgr.max_desc = ARRAY_SIZE(priv->lro_arr);
++              priv->lro_mgr.max_aggr = 64;
++              priv->lro_mgr.frag_align_pad = 0;
++              priv->lro_mgr.lro_arr = priv->lro_arr;
++              priv->lro_mgr.get_skb_header = priv->soc->get_skb_header;
++      }
++#endif
++
 +      platform_set_drvdata(pdev, netdev);
 +
 +      netdev_info(netdev, "done loading\n");
@@ -3584,11 +3687,11 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.c
 +MODULE_LICENSE("GPL");
 +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
 +MODULE_DESCRIPTION("Ethernet driver for Ralink SoC");
-Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
+Index: linux-3.10.21/drivers/net/ethernet/ralink/ralink_soc_eth.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h 2013-11-21 11:11:54.160088954 +0100
-@@ -0,0 +1,375 @@
++++ linux-3.10.21/drivers/net/ethernet/ralink/ralink_soc_eth.h 2013-12-09 13:26:42.332125203 +0100
+@@ -0,0 +1,384 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
 + *   it under the terms of the GNU General Public License as published by
@@ -3615,6 +3718,7 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
 +#include <linux/netdevice.h>
 +#include <linux/dma-mapping.h>
 +#include <linux/phy.h>
++#include <linux/inet_lro.h>
 +
 +
 +enum fe_reg {
@@ -3869,6 +3973,8 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
 +
 +#define TX_DMA_PLEN0_MASK     ((0x3fff) << 16)
 +#define TX_DMA_PLEN0(_x)      (((_x) & 0x3fff) << 16)
++#define TX_DMA_PLEN1(_x)      ((_x) & 0x3fff)
++#define TX_DMA_LS1            BIT(14)
 +#define TX_DMA_LSO            BIT(30)
 +#define TX_DMA_DONE           BIT(31)
 +#define TX_DMA_QN(_x)         ((_x) << 16)
@@ -3907,6 +4013,7 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
 +      unsigned char mac[6];
 +      const u32 *reg_table;
 +
++      void (*init_data)(struct fe_soc_data *data);
 +      void (*reset_fe)(void);
 +      void (*set_mac)(struct fe_priv *priv, unsigned char *mac);
 +      void (*fwd_config)(struct fe_priv *priv);
@@ -3921,12 +4028,14 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
 +      int (*mdio_write)(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val);
 +      int (*mdio_read)(struct mii_bus *bus, int phy_addr, int phy_reg);
 +      void (*mdio_adjust_link)(struct fe_priv *priv, int port);
++      int (*get_skb_header)(struct sk_buff *skb, void **iphdr, void **tcph, u64 *hdr_flags, void *priv);
 +
 +      void *swpriv;
 +      u32 pdma_glo_cfg;
 +      u32 rx_dly_int;
 +      u32 tx_dly_int;
 +      u32 checksum_bit;
++      u32 tso;
 +
 +      int min_pkt_len;
 +};
@@ -3956,6 +4065,9 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
 +      int                             mii_irq[PHY_MAX_ADDR];
 +
 +      int                             link[8];
++
++      struct net_lro_mgr              lro_mgr;
++      struct net_lro_desc             lro_arr[8];
 +};
 +
 +extern const struct of_device_id of_fe_match[];
@@ -3964,11 +4076,11 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/ralink_soc_eth.h
 +u32 fe_r32(unsigned reg);
 +
 +#endif /* FE_ETH_H */
-Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/soc_mt7620.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c     2013-11-21 11:42:23.264132543 +0100
-@@ -0,0 +1,124 @@
++++ linux-3.10.21/drivers/net/ethernet/ralink/soc_mt7620.c     2013-12-09 13:26:42.332125203 +0100
+@@ -0,0 +1,172 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
 + *   it under the terms of the GNU General Public License as published by
@@ -3992,6 +4104,7 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c
 +
 +#include <asm/mach-ralink/ralink_regs.h>
 +
++#include <mt7620.h>
 +#include "ralink_soc_eth.h"
 +#include "gsw_mt7620a.h"
 +
@@ -4049,10 +4162,20 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c
 +
 +static void mt7620_tx_dma(struct fe_priv *priv, int idx, struct sk_buff *skb)
 +{
-+      if (skb)
-+              priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(skb->len);
-+      else
++      unsigned int nr_frags = 0;
++      unsigned int len = 0;
++
++      if (skb) {
++              nr_frags = skb_shinfo(skb)->nr_frags;
++              len = skb->len - skb->data_len;
++      }
++
++      if (!skb)
 +              priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_DONE;
++      else if (!nr_frags)
++              priv->tx_dma[idx].txd2 = TX_DMA_LSO | TX_DMA_PLEN0(len);
++      else
++              priv->tx_dma[idx].txd2 = TX_DMA_PLEN0(len);
 +
 +      if(skb && vlan_tx_tag_present(skb))
 +              priv->tx_dma[idx].txd4 = 0x80 | (vlan_tx_tag_get(skb) >> 13) << 4 | (vlan_tx_tag_get(skb) & 0xF);
@@ -4065,8 +4188,42 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c
 +      priv->rx_dma[idx].rxd2 = RX_DMA_PLEN0(len);
 +}
 +
++#ifdef CONFIG_INET_LRO
++static int
++mt7620_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph,
++                      u64 *hdr_flags, void *_priv)
++{
++      struct iphdr *iph = NULL;
++      int vhdr_len = 0;
++
++      /*
++       * Make sure that this packet is Ethernet II, is not VLAN
++       * tagged, is IPv4, has a valid IP header, and is TCP.
++       */
++      if (skb->protocol == 0x0081)
++              vhdr_len = VLAN_HLEN;
++
++      iph = (struct iphdr *)(skb->data + vhdr_len);
++      if(iph->protocol != IPPROTO_TCP)
++              return -1;
++
++      *iphdr = iph;
++      *tcph = skb->data + (iph->ihl << 2) + vhdr_len;
++      *hdr_flags = LRO_IPV4 | LRO_TCP;
++
++      return 0;
++}
++#endif
++
++static void mt7620_init_data(struct fe_soc_data *data)
++{
++      if (mt7620_get_eco() >= 5)
++              data->tso = 1;
++}
++
 +static struct fe_soc_data mt7620_data = {
 +      .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 },
++      .init_data = mt7620_init_data,
 +      .reset_fe = mt7620_fe_reset,
 +      .set_mac = mt7620_set_mac,
 +      .fwd_config = mt7620_fwd_config,
@@ -4085,6 +4242,9 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c
 +      .mdio_read = mt7620_mdio_read,
 +      .mdio_write = mt7620_mdio_write,
 +      .mdio_adjust_link = mt7620_mdio_link_adjust,
++#ifdef CONFIG_INET_LRO
++      .get_skb_header = mt7620_get_skb_header,
++#endif
 +};
 +
 +const struct of_device_id of_fe_match[] = {
@@ -4093,10 +4253,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_mt7620.c
 +};
 +
 +MODULE_DEVICE_TABLE(of, of_fe_match);
-Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_rt2880.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/soc_rt2880.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/soc_rt2880.c     2013-11-19 11:15:38.972470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/soc_rt2880.c     2013-12-09 13:26:42.332125203 +0100
 @@ -0,0 +1,51 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -4149,10 +4309,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_rt2880.c
 +};
 +
 +MODULE_DEVICE_TABLE(of, of_fe_match);
-Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_rt305x.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/soc_rt305x.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/soc_rt305x.c     2013-11-19 11:15:38.972470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/soc_rt305x.c     2013-12-09 13:26:42.332125203 +0100
 @@ -0,0 +1,113 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -4267,10 +4427,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_rt305x.c
 +};
 +
 +MODULE_DEVICE_TABLE(of, of_fe_match);
-Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_rt3883.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/soc_rt3883.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/soc_rt3883.c     2013-11-19 11:15:38.972470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/soc_rt3883.c     2013-12-09 13:26:42.332125203 +0100
 @@ -0,0 +1,60 @@
 +/*
 + *   This program is free software; you can redistribute it and/or modify
@@ -4332,10 +4492,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/soc_rt3883.c
 +
 +MODULE_DEVICE_TABLE(of, of_fe_match);
 +
-Index: linux-3.10.18/drivers/net/ethernet/ralink/mt7530.c
+Index: linux-3.10.21/drivers/net/ethernet/ralink/mt7530.c
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/mt7530.c 2013-11-19 11:15:38.976470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/mt7530.c 2013-12-09 13:26:42.336125203 +0100
 @@ -0,0 +1,467 @@
 +/*
 + * This program is free software; you can redistribute it and/or
@@ -4412,11 +4572,11 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/mt7530.c
 +      {
 +              .name = "llllw",
 +              .pvids = { 1, 1, 1, 1, 2, 1 },
-+              .vlans = { 0, 0x4f, 0x50 },
++              .vlans = { 0, 0x6f, 0x50 },
 +      }, {
 +              .name = "wllll",
 +              .pvids = { 2, 1, 1, 1, 1, 1 },
-+              .vlans = { 0, 0x5e, 0x41 },
++              .vlans = { 0, 0x7e, 0x41 },
 +      },
 +};
 +
@@ -4804,10 +4964,10 @@ Index: linux-3.10.18/drivers/net/ethernet/ralink/mt7530.c
 +
 +      return 0;
 +}
-Index: linux-3.10.18/drivers/net/ethernet/ralink/mt7530.h
+Index: linux-3.10.21/drivers/net/ethernet/ralink/mt7530.h
 ===================================================================
 --- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-3.10.18/drivers/net/ethernet/ralink/mt7530.h 2013-11-19 11:15:38.976470791 +0100
++++ linux-3.10.21/drivers/net/ethernet/ralink/mt7530.h 2013-12-09 13:26:42.336125203 +0100
 @@ -0,0 +1,20 @@
 +/*
 + * This program is free software; you can redistribute it and/or